diff --git a/.gitea/ISSUE_TEMPLATE/BUG_REPORT.md b/.gitea/ISSUE_TEMPLATE/BUG_REPORT.md index a8a1efe..10f8648 100644 --- a/.gitea/ISSUE_TEMPLATE/BUG_REPORT.md +++ b/.gitea/ISSUE_TEMPLATE/BUG_REPORT.md @@ -1,6 +1,6 @@ --- name: Bug report -about: Create a report for something does not work as it should +about: Erstelle eine Meldung für etwas, das nicht Funktioniert, wie es soll. title: '' labels: 'Task/Bug' assignees: '' @@ -9,28 +9,27 @@ assignees: '' # Bug Report -## Description -[A clear and concise description of the bug] +## Beschreibung +[Eine klare und prägnante Beschreibung des Bugs] -## Steps to Reproduce -1. Step 1 -2. Step 2 +## Schritte zur Reproduktion +1. Schritt 1 +2. Schritt 2 3. ... -## Expected Behavior -[What should have happened] +## Erwartetes Verhalten +[Was hätte passieren sollen] -## Actual Behavior -[What actually happened] +## Tatsächliches Verhalten +[Was tatsächlich passiert ist] -## Screenshots/Logs -[If applicable, add screenshots, error logs, or stack traces] +## Screenshots/Protokolle +[Falls zutreffend, füge Screenshots, Error Logs oder Stack Traces hinzu] -## Environment -- OS: [e.g., iOS 18.5, Android 14] +## Umgebung +- Plattform: Android, iOS, Web +- OS: [z. B. iOS 18.5, Android 14] +- Flutter Version: [z.B. 3.35.6] -## Possible Fix (Optional) -[Any suggestions on how to resolve the issue] - -## Related Issues (Optional) -[Reference similar issues or PRs] +## Verwandte Issues +[Verweisen Sie auf ähnliche Issues oder PRs] \ No newline at end of file diff --git a/.gitea/ISSUE_TEMPLATE/ENHANCEMENT.md b/.gitea/ISSUE_TEMPLATE/ENHANCEMENT.md index 5e40dd9..49442d1 100644 --- a/.gitea/ISSUE_TEMPLATE/ENHANCEMENT.md +++ b/.gitea/ISSUE_TEMPLATE/ENHANCEMENT.md @@ -9,14 +9,14 @@ assignees: '' # Enhancement -## Current Behavior -[Describe the existing functionality] +## Aktuelles Verhalten +[Beschreibe die bestehende Funktionalität] -## Limitations/Problems -[What are the current shortcomings?] +## Einschränkungen/Probleme +[Was sind die aktuellen Mängel?] -## Suggested Improvement -[How can this be enhanced? Be specific.] +## Vorgeschlagene Verbesserung +[Wie kann das Problem bzw. die Einschränkung verbessert werden?] -## Benefits -[How will this improve the product?] \ No newline at end of file +## Zugehörige Issues +[Links zu verwandten oder blockierenden Issues] \ No newline at end of file diff --git a/.gitea/ISSUE_TEMPLATE/FEATURE.md b/.gitea/ISSUE_TEMPLATE/FEATURE.md index 809509b..01e7a5f 100644 --- a/.gitea/ISSUE_TEMPLATE/FEATURE.md +++ b/.gitea/ISSUE_TEMPLATE/FEATURE.md @@ -1,22 +1,19 @@ --- name: Feature -about: New feature for the app +about: Neues Feature für die App title: '' labels: 'Task\Feature' assignees: '' --- -# 🚀 Feature +# Feature -## Description -[Detailed explanation of the proposed feature] +## Beschreibung +[Ausführliche Erläuterung der vorgeschlagenen Funktion] -## Why is this feature needed? -[Explain the problem or use case this feature would solve] +## Vorgeschlagene Lösung +[Beschreibe, wie die Feature funktionieren soll] -## Proposed Solution -[Describe how the feature should work] - -## Related Issues (Optional) -[Links to related discussions or requests] \ No newline at end of file +## Zugehörige Issues +[Links zu verwandten oder blockierenden Issues] \ No newline at end of file diff --git a/.gitea/PULL_REQUEST_TEMPLATE.md b/.gitea/PULL_REQUEST_TEMPLATE.md index d174324..7ae0f8a 100644 --- a/.gitea/PULL_REQUEST_TEMPLATE.md +++ b/.gitea/PULL_REQUEST_TEMPLATE.md @@ -1,16 +1,16 @@ -# [PR Title] +# [PR Titel] -**Related Issue(s):** +**Zugehörige Issue(s):** Closes `` -## Description -*A clear and concise overview of the changes made. Explain the "why" behind the PR, not just the "what".* +## Beschreibung +*Eine klare und prägnante Übersicht über die vorgenommenen Änderungen. Erläutere nicht nur das was gemacht wurde, sondern auch warum.* -## Changes Made -- [ ] Added new feature X -- [ ] Fixed bug in component Y -- [ ] Refactored module Z for better performance -- [ ] Updated dependencies +## Änderungen +- [ ] Neue Funktion X hinzugefügt +- [ ] Bug in Komponente Y behoben +- [ ] Modul Z für bessere Leistung refactored +- [ ] Dependencies aktualisiert -## Additional Notes -*Any extra context, limitations, or decisions that reviewers should know about?* +## Zusätzliche Anmerkungen +*Gibt es zusätzlichen Kontext, Einschränkungen oder Informationen, die Reviewer wissen sollten?* diff --git a/.gitea/workflows/pull_request.yaml b/.gitea/workflows/pull_request.yaml new file mode 100644 index 0000000..43d36d2 --- /dev/null +++ b/.gitea/workflows/pull_request.yaml @@ -0,0 +1,57 @@ +name: Pull Request Pipeline + +on: + pull_request: + +jobs: + lint: + runs-on: ubuntu-latest + steps: + - name: Checkout code + uses: actions/checkout@v4 + + - name: Install jq + run: | + apt-get update + apt-get install -y jq + + - name: Install Flutter (wget) + run: | + wget https://storage.googleapis.com/flutter_infra_release/releases/stable/linux/flutter_linux_3.38.2-stable.tar.xz + tar xf flutter_linux_3.38.2-stable.tar.xz + # Set Git safe directory for Flutter path + git config --global --add safe.directory "$(pwd)/flutter" + # Set Flutter path + echo "$(pwd)/flutter/bin" >> $GITHUB_PATH + + - name: Get dependencies + run: flutter pub get + + - name: Analyze Formatting + run: flutter analyze lib test + + test: + runs-on: ubuntu-latest + steps: + - name: Checkout code + uses: actions/checkout@v4 + + - name: Install dependencies + run: | + apt-get update + apt-get install -y jq + + - name: Install Flutter (wget) + run: | + wget https://storage.googleapis.com/flutter_infra_release/releases/stable/linux/flutter_linux_3.38.2-stable.tar.xz + tar xf flutter_linux_3.38.2-stable.tar.xz + # Set Git safe directory for Flutter path + git config --global --add safe.directory "$(pwd)/flutter" + # Set Flutter path + echo "$(pwd)/flutter/bin" >> $GITHUB_PATH + + - name: Get dependencies + run: flutter pub get + + - name: Run tests + run: flutter test \ No newline at end of file diff --git a/.gitea/workflows/push.yaml b/.gitea/workflows/push.yaml new file mode 100644 index 0000000..700e96b --- /dev/null +++ b/.gitea/workflows/push.yaml @@ -0,0 +1,50 @@ +name: Push Pipeline + +on: + push: + branches: + - "development" + - "main" + +jobs: + format: + runs-on: ubuntu-latest + if: false # Needs bot user + steps: + - name: Checkout code + uses: actions/checkout@v4 + + - name: Install dependencies + run: | + apt-get update + apt-get install -y jq + + - name: Install Flutter (wget) + run: | + wget https://storage.googleapis.com/flutter_infra_release/releases/stable/linux/flutter_linux_3.38.2-stable.tar.xz + tar xf flutter_linux_3.38.2-stable.tar.xz + # Set Git safe directory for Flutter path + git config --global --add safe.directory "$(pwd)/flutter" + # Set Flutter path + echo "$(pwd)/flutter/bin" >> $GITHUB_PATH + + - name: Get & upgrade dependencies + run: | + flutter pub get + flutter pub upgrade --major-versions + + - name: Auto-format + run: | + dart format lib + dart fix --apply lib + + # Needs credentials, push access and the right files need to be staged + - name: Commit Changes + run: | + git config --global user.name "Gitea Actions" + git config --global user.email "actions@gitea.com" + git status + git add lib/ + git status + git commit -m "Actions: Auto-formatting [skip ci]" + git push diff --git a/lib/core/custom_theme.dart b/lib/core/custom_theme.dart index 438aab5..16e9585 100644 --- a/lib/core/custom_theme.dart +++ b/lib/core/custom_theme.dart @@ -5,6 +5,7 @@ class CustomTheme { static Color secondaryColor = const Color(0xFFAFA2FF); static Color backgroundColor = const Color(0xFF0B0B0B); static Color boxColor = const Color(0xFF101010); + static Color onBoxColor = const Color(0xFF181818); static Color boxBorder = const Color(0xFF272727); static AppBarTheme appBarTheme = AppBarTheme( diff --git a/lib/core/enums.dart b/lib/core/enums.dart new file mode 100644 index 0000000..320eaf7 --- /dev/null +++ b/lib/core/enums.dart @@ -0,0 +1,2 @@ +/// Button types used for styling the [CustomWidthButton] +enum ButtonType { primary, secondary, tertiary } diff --git a/lib/data/dao/game_dao.dart b/lib/data/dao/game_dao.dart index 3b6529a..94d010c 100644 --- a/lib/data/dao/game_dao.dart +++ b/lib/data/dao/game_dao.dart @@ -2,6 +2,8 @@ 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/data/dto/group.dart'; +import 'package:game_tracker/data/dto/player.dart'; part 'game_dao.g.dart'; @@ -13,14 +15,67 @@ class GameDao extends DatabaseAccessor with _$GameDaoMixin { Future> getAllGames() async { final query = select(gameTable); final result = await query.get(); - return result.map((row) => Game(id: row.id, name: row.name)).toList(); + return result + .map( + (row) => Game(id: row.id, name: row.name, createdAt: row.createdAt), + ) + .toList(); } - /// Retrieves a [Game] by its [id]. - Future getGameById(String id) async { - final query = select(gameTable)..where((g) => g.id.equals(id)); + /// Retrieves a [Game] by its [gameId]. + Future getGameById({required String gameId}) async { + final query = select(gameTable)..where((g) => g.id.equals(gameId)); final result = await query.getSingle(); - return Game(id: result.id, name: result.name); + + List? players; + if (await db.playerGameDao.gameHasPlayers(gameId: gameId)) { + players = await db.playerGameDao.getPlayersByGameId(gameId: gameId); + } + Group? group; + if (await db.groupGameDao.hasGameGroup(gameId: gameId)) { + group = await db.groupGameDao.getGroupByGameId(gameId: gameId); + } + + return Game( + id: result.id, + name: result.name, + players: players, + group: group, + winner: result.winnerId, + createdAt: result.createdAt, + ); + } + + /// Adds a new [Game] to the database. + /// Also adds associated players and group if they exist. + Future addGame({required Game game}) async { + await db.transaction(() async { + for (final p in game.players ?? []) { + await db.playerDao.addPlayer(player: p); + await db.playerGameDao.addPlayerToGame(gameId: game.id, playerId: p.id); + } + if (game.group != null) { + await db.groupDao.addGroup(group: game.group!); + await db.groupGameDao.addGroupToGame(game.id, game.group!.id); + } + await into(gameTable).insert( + GameTableCompanion.insert( + id: game.id, + name: game.name, + winnerId: game.winner, + createdAt: game.createdAt, + ), + mode: InsertMode.insertOrReplace, + ); + }); + } + + /// Deletes the game with the given [gameId] from the database. + /// Returns `true` if more than 0 rows were affected, otherwise `false`. + Future deleteGame({required String gameId}) async { + final query = delete(gameTable)..where((g) => g.id.equals(gameId)); + final rowsAffected = await query.go(); + return rowsAffected > 0; } /// Retrieves the number of games in the database. @@ -31,4 +86,12 @@ class GameDao extends DatabaseAccessor with _$GameDaoMixin { .getSingle(); return count ?? 0; } + + /// Checks if a game with the given [gameId] exists in the database. + /// Returns `true` if the game exists, otherwise `false`. + Future gameExists({required String gameId}) async { + final query = select(gameTable)..where((g) => g.id.equals(gameId)); + final result = await query.getSingleOrNull(); + return result != null; + } } diff --git a/lib/data/dao/game_dao.g.dart b/lib/data/dao/game_dao.g.dart index b5a29fe..ebf5524 100644 --- a/lib/data/dao/game_dao.g.dart +++ b/lib/data/dao/game_dao.g.dart @@ -4,5 +4,6 @@ part of 'game_dao.dart'; // ignore_for_file: type=lint mixin _$GameDaoMixin on DatabaseAccessor { + $PlayerTableTable get playerTable => attachedDatabase.playerTable; $GameTableTable get gameTable => attachedDatabase.gameTable; } diff --git a/lib/data/dao/group_dao.dart b/lib/data/dao/group_dao.dart index 7dc144d..3378948 100644 --- a/lib/data/dao/group_dao.dart +++ b/lib/data/dao/group_dao.dart @@ -14,44 +14,88 @@ class GroupDao extends DatabaseAccessor with _$GroupDaoMixin { Future> getAllGroups() async { final query = select(groupTable); final result = await query.get(); - return result - .map((row) => Group(id: row.id, name: row.name, members: [])) - .toList(); + return Future.wait( + result.map((groupData) async { + final members = await db.playerGroupDao.getPlayersOfGroupById( + groupId: groupData.id, + ); + return Group( + id: groupData.id, + name: groupData.name, + members: members, + createdAt: groupData.createdAt, + ); + }), + ); } - /// Retrieves a [Group] by its [id], including its members. - Future getGroupById(String id) async { - final query = select(groupTable)..where((g) => g.id.equals(id)); + /// Retrieves a [Group] by its [groupId], including its members. + Future getGroupById({required String groupId}) async { + final query = select(groupTable)..where((g) => g.id.equals(groupId)); final result = await query.getSingle(); - List members = []; + List members = await db.playerGroupDao.getPlayersOfGroupById( + groupId: groupId, + ); - members = await db.playerGroupDao.getPlayersOfGroupById(id); - - return Group(id: result.id, name: result.name, members: members); + return Group( + id: result.id, + name: result.name, + members: members, + createdAt: result.createdAt, + ); } /// Adds a new group with the given [id] and [name] to the database. - /// Returns `true` if more than 0 rows were affected, otherwise `false`. - Future addGroup(String id, String name) async { - await into( - groupTable, - ).insert(GroupTableCompanion.insert(id: id, name: name)); + /// This method also adds the group's members to the [PlayerGroupTable]. + Future addGroup({required Group group}) async { + if (!await groupExists(groupId: group.id)) { + await db.transaction(() async { + await into(groupTable).insert( + GroupTableCompanion.insert( + id: group.id, + name: group.name, + createdAt: group.createdAt, + ), + ); + await db.batch( + (b) => b.insertAll( + db.playerGroupTable, + group.members + .map( + (member) => PlayerGroupTableCompanion.insert( + playerId: member.id, + groupId: group.id, + ), + ) + .toList(), + ), + ); + await Future.wait( + group.members.map((player) => db.playerDao.addPlayer(player: player)), + ); + }); + return true; + } + return false; } /// Deletes the group with the given [id] from the database. /// Returns `true` if more than 0 rows were affected, otherwise `false`. - Future deleteGroup(String id) async { - final query = (delete(groupTable)..where((g) => g.id.equals(id))); + Future deleteGroup({required String groupId}) async { + final query = (delete(groupTable)..where((g) => g.id.equals(groupId))); final rowsAffected = await query.go(); return rowsAffected > 0; } /// Updates the name of the group with the given [id] to [newName]. /// Returns `true` if more than 0 rows were affected, otherwise `false`. - Future updateGroupname(String id, String newName) async { + Future updateGroupname({ + required String groupId, + required String newName, + }) async { final rowsAffected = - await (update(groupTable)..where((g) => g.id.equals(id))).write( + await (update(groupTable)..where((g) => g.id.equals(groupId))).write( GroupTableCompanion(name: Value(newName)), ); return rowsAffected > 0; @@ -65,4 +109,12 @@ class GroupDao extends DatabaseAccessor with _$GroupDaoMixin { .getSingle(); return count ?? 0; } + + /// Checks if a group with the given [groupId] exists in the database. + /// Returns `true` if the group exists, `false` otherwise. + Future groupExists({required String groupId}) async { + final query = select(groupTable)..where((g) => g.id.equals(groupId)); + final result = await query.getSingleOrNull(); + return result != null; + } } diff --git a/lib/data/dao/group_game_dao.dart b/lib/data/dao/group_game_dao.dart new file mode 100644 index 0000000..d3b30ca --- /dev/null +++ b/lib/data/dao/group_game_dao.dart @@ -0,0 +1,42 @@ +import 'package:drift/drift.dart'; +import 'package:game_tracker/data/db/database.dart'; +import 'package:game_tracker/data/db/tables/group_game_table.dart'; +import 'package:game_tracker/data/dto/group.dart'; + +part 'group_game_dao.g.dart'; + +@DriftAccessor(tables: [GroupGameTable]) +class GroupGameDao extends DatabaseAccessor + with _$GroupGameDaoMixin { + GroupGameDao(super.db); + + /// Checks if there is a group associated with the given [gameId]. + /// Returns `true` if there is a group, otherwise `false`. + Future hasGameGroup({required String gameId}) async { + final count = + await (selectOnly(groupGameTable) + ..where(groupGameTable.gameId.equals(gameId)) + ..addColumns([groupGameTable.groupId.count()])) + .map((row) => row.read(groupGameTable.groupId.count())) + .getSingle(); + return (count ?? 0) > 0; + } + + /// Retrieves the [Group] associated with the given [gameId]. + Future getGroupByGameId({required String gameId}) async { + final result = await (select( + groupGameTable, + )..where((g) => g.gameId.equals(gameId))).getSingle(); + + final group = await db.groupDao.getGroupById(groupId: result.groupId); + return group; + } + + /// Associates a group with a game by inserting a record into the + /// [GroupGameTable]. + Future addGroupToGame(String gameId, String groupId) async { + await into( + groupGameTable, + ).insert(GroupGameTableCompanion.insert(groupId: groupId, gameId: gameId)); + } +} diff --git a/lib/data/dao/group_game_dao.g.dart b/lib/data/dao/group_game_dao.g.dart new file mode 100644 index 0000000..426f192 --- /dev/null +++ b/lib/data/dao/group_game_dao.g.dart @@ -0,0 +1,11 @@ +// GENERATED CODE - DO NOT MODIFY BY HAND + +part of 'group_game_dao.dart'; + +// ignore_for_file: type=lint +mixin _$GroupGameDaoMixin on DatabaseAccessor { + $GroupTableTable get groupTable => attachedDatabase.groupTable; + $PlayerTableTable get playerTable => attachedDatabase.playerTable; + $GameTableTable get gameTable => attachedDatabase.gameTable; + $GroupGameTableTable get groupGameTable => attachedDatabase.groupGameTable; +} diff --git a/lib/data/dao/player_dao.dart b/lib/data/dao/player_dao.dart index 2d3c0ab..36f9305 100644 --- a/lib/data/dao/player_dao.dart +++ b/lib/data/dao/player_dao.dart @@ -13,43 +13,73 @@ class PlayerDao extends DatabaseAccessor with _$PlayerDaoMixin { Future> getAllPlayers() async { final query = select(playerTable); final result = await query.get(); - return result.map((row) => Player(id: row.id, name: row.name)).toList(); + return result + .map( + (row) => Player(id: row.id, name: row.name, createdAt: row.createdAt), + ) + .toList(); } /// Retrieves a [Player] by their [id]. - Future getPlayerById(String id) async { - final query = select(playerTable)..where((p) => p.id.equals(id)); + Future getPlayerById({required String playerId}) async { + final query = select(playerTable)..where((p) => p.id.equals(playerId)); final result = await query.getSingle(); - return Player(id: result.id, name: result.name); + return Player( + id: result.id, + name: result.name, + createdAt: result.createdAt, + ); } /// Adds a new [player] to the database. - Future addPlayer(Player player) async { - await into( - playerTable, - ).insert(PlayerTableCompanion.insert(id: player.id, name: player.name)); + /// If a player with the same ID already exists, updates their name to + /// the new one. + Future addPlayer({required Player player}) async { + if (!await playerExists(playerId: player.id)) { + await into(playerTable).insert( + PlayerTableCompanion.insert( + id: player.id, + name: player.name, + createdAt: player.createdAt, + ), + ); + return true; + } + return false; } /// Deletes the player with the given [id] from the database. /// Returns `true` if the player was deleted, `false` if the player did not exist. - Future deletePlayer(String id) async { - final query = delete(playerTable)..where((p) => p.id.equals(id)); + Future deletePlayer({required String playerId}) async { + final query = delete(playerTable)..where((p) => p.id.equals(playerId)); final rowsAffected = await query.go(); return rowsAffected > 0; } /// Checks if a player with the given [id] exists in the database. /// Returns `true` if the player exists, `false` otherwise. - Future playerExists(String id) async { - final query = select(playerTable)..where((p) => p.id.equals(id)); + Future playerExists({required String playerId}) async { + final query = select(playerTable)..where((p) => p.id.equals(playerId)); final result = await query.getSingleOrNull(); return result != null; } - /// Updates the name of the player with the given [id] to [newName]. - Future updatePlayername(String id, String newName) async { - await (update(playerTable)..where((p) => p.id.equals(id))).write( + /// Updates the name of the player with the given [playerId] to [newName]. + Future updatePlayername({ + required String playerId, + required String newName, + }) async { + await (update(playerTable)..where((p) => p.id.equals(playerId))).write( PlayerTableCompanion(name: Value(newName)), ); } + + /// Retrieves the total count of players in the database. + Future getPlayerCount() async { + final count = + await (selectOnly(playerTable)..addColumns([playerTable.id.count()])) + .map((row) => row.read(playerTable.id.count())) + .getSingle(); + return count ?? 0; + } } diff --git a/lib/data/dao/player_game_dao.dart b/lib/data/dao/player_game_dao.dart new file mode 100644 index 0000000..8f367f8 --- /dev/null +++ b/lib/data/dao/player_game_dao.dart @@ -0,0 +1,51 @@ +import 'package:drift/drift.dart'; +import 'package:game_tracker/data/db/database.dart'; +import 'package:game_tracker/data/db/tables/player_game_table.dart'; +import 'package:game_tracker/data/dto/player.dart'; + +part 'player_game_dao.g.dart'; + +@DriftAccessor(tables: [PlayerGameTable]) +class PlayerGameDao extends DatabaseAccessor + with _$PlayerGameDaoMixin { + PlayerGameDao(super.db); + + /// Checks if there are any players associated with the given [gameId]. + /// Returns `true` if there are players, otherwise `false`. + Future gameHasPlayers({required String gameId}) async { + final count = + await (selectOnly(playerGameTable) + ..where(playerGameTable.gameId.equals(gameId)) + ..addColumns([playerGameTable.playerId.count()])) + .map((row) => row.read(playerGameTable.playerId.count())) + .getSingle(); + return (count ?? 0) > 0; + } + + /// Retrieves a list of [Player]s associated with the given [gameId]. + /// Returns an empty list if no players are found. + Future> getPlayersByGameId({required String gameId}) async { + final result = await (select( + playerGameTable, + )..where((p) => p.gameId.equals(gameId))).get(); + + if (result.isEmpty) return []; + + final futures = result.map( + (row) => db.playerDao.getPlayerById(playerId: row.playerId), + ); + final players = await Future.wait(futures); + return players.whereType().toList(); + } + + /// Associates a player with a game by inserting a record into the + /// [PlayerGameTable]. + Future addPlayerToGame({ + required String gameId, + required String playerId, + }) async { + await into(playerGameTable).insert( + PlayerGameTableCompanion.insert(playerId: playerId, gameId: gameId), + ); + } +} diff --git a/lib/data/dao/player_game_dao.g.dart b/lib/data/dao/player_game_dao.g.dart new file mode 100644 index 0000000..4d0a192 --- /dev/null +++ b/lib/data/dao/player_game_dao.g.dart @@ -0,0 +1,10 @@ +// GENERATED CODE - DO NOT MODIFY BY HAND + +part of 'player_game_dao.dart'; + +// ignore_for_file: type=lint +mixin _$PlayerGameDaoMixin on DatabaseAccessor { + $PlayerTableTable get playerTable => attachedDatabase.playerTable; + $GameTableTable get gameTable => attachedDatabase.gameTable; + $PlayerGameTableTable get playerGameTable => attachedDatabase.playerGameTable; +} diff --git a/lib/data/dao/player_group_dao.dart b/lib/data/dao/player_group_dao.dart index b68ed09..fe067ae 100644 --- a/lib/data/dao/player_group_dao.dart +++ b/lib/data/dao/player_group_dao.dart @@ -11,34 +11,65 @@ class PlayerGroupDao extends DatabaseAccessor PlayerGroupDao(super.db); /// Retrieves all players belonging to a specific group by [groupId]. - Future> getPlayersOfGroupById(String groupId) async { + Future> getPlayersOfGroupById({required String groupId}) async { final query = select(playerGroupTable) ..where((pG) => pG.groupId.equals(groupId)); final result = await query.get(); - List groupMembers = []; + List groupMembers = List.empty(growable: true); for (var entry in result) { - final player = await db.playerDao.getPlayerById(entry.userId); + final player = await db.playerDao.getPlayerById(playerId: entry.playerId); groupMembers.add(player); } return groupMembers; } - /// Removes a player from a group based on [userId] and [groupId]. + /// Removes a player from a group based on [playerId] and [groupId]. /// Returns `true` if more than 0 rows were affected, otherwise `false`. - Future removePlayerFromGroup(String userId, String groupId) async { + Future removePlayerFromGroup({ + required String playerId, + required String groupId, + }) async { final query = delete(playerGroupTable) - ..where((p) => p.userId.equals(userId) & p.groupId.equals(groupId)); + ..where((p) => p.playerId.equals(playerId) & p.groupId.equals(groupId)); final rowsAffected = await query.go(); return rowsAffected > 0; } - /// Adds a player to a group with the given [userId] and [groupId]. - Future addPlayerToGroup(String userId, String groupId) async { + /// Adds a [player] to a group with the given [groupId]. + /// If the player is already in the group, no action is taken. + /// If the player does not exist in the player table, they are added. + /// Returns `true` if the player was added, otherwise `false`. + Future addPlayerToGroup({ + required Player player, + required String groupId, + }) async { + if (await isPlayerInGroup(playerId: player.id, groupId: groupId)) { + return false; + } + + if (await db.playerDao.playerExists(playerId: player.id) == false) { + db.playerDao.addPlayer(player: player); + } + await into(playerGroupTable).insert( - PlayerGroupTableCompanion.insert(userId: userId, groupId: groupId), + PlayerGroupTableCompanion.insert(playerId: player.id, groupId: groupId), ); + + return true; + } + + /// Checks if a player with [playerId] is in the group with [groupId]. + /// Returns `true` if the player is in the group, otherwise `false`. + Future isPlayerInGroup({ + required String playerId, + required String groupId, + }) async { + final query = select(playerGroupTable) + ..where((p) => p.playerId.equals(playerId) & p.groupId.equals(groupId)); + final result = await query.getSingleOrNull(); + return result != null; } } diff --git a/lib/data/db/database.dart b/lib/data/db/database.dart index e35513e..73ad73e 100644 --- a/lib/data/db/database.dart +++ b/lib/data/db/database.dart @@ -2,10 +2,14 @@ import 'package:drift/drift.dart'; import 'package:drift_flutter/drift_flutter.dart'; import 'package:game_tracker/data/dao/game_dao.dart'; import 'package:game_tracker/data/dao/group_dao.dart'; +import 'package:game_tracker/data/dao/group_game_dao.dart'; import 'package:game_tracker/data/dao/player_dao.dart'; +import 'package:game_tracker/data/dao/player_game_dao.dart'; import 'package:game_tracker/data/dao/player_group_dao.dart'; import 'package:game_tracker/data/db/tables/game_table.dart'; +import 'package:game_tracker/data/db/tables/group_game_table.dart'; import 'package:game_tracker/data/db/tables/group_table.dart'; +import 'package:game_tracker/data/db/tables/player_game_table.dart'; import 'package:game_tracker/data/db/tables/player_group_table.dart'; import 'package:game_tracker/data/db/tables/player_table.dart'; import 'package:path_provider/path_provider.dart'; @@ -13,8 +17,22 @@ import 'package:path_provider/path_provider.dart'; part 'database.g.dart'; @DriftDatabase( - tables: [PlayerTable, GroupTable, PlayerGroupTable, GameTable], - daos: [GroupDao, PlayerDao, PlayerGroupDao, GameDao], + tables: [ + PlayerTable, + GroupTable, + GameTable, + PlayerGroupTable, + PlayerGameTable, + GroupGameTable, + ], + daos: [ + PlayerDao, + GroupDao, + GameDao, + PlayerGroupDao, + PlayerGameDao, + GroupGameDao, + ], ) class AppDatabase extends _$AppDatabase { AppDatabase([QueryExecutor? executor]) : super(executor ?? _openConnection()); diff --git a/lib/data/db/database.g.dart b/lib/data/db/database.g.dart index 4075912..3f10169 100644 --- a/lib/data/db/database.g.dart +++ b/lib/data/db/database.g.dart @@ -27,8 +27,19 @@ class $PlayerTableTable extends PlayerTable type: DriftSqlType.string, requiredDuringInsert: true, ); + static const VerificationMeta _createdAtMeta = const VerificationMeta( + 'createdAt', + ); @override - List get $columns => [id, name]; + late final GeneratedColumn createdAt = GeneratedColumn( + 'created_at', + aliasedName, + false, + type: DriftSqlType.dateTime, + requiredDuringInsert: true, + ); + @override + List get $columns => [id, name, createdAt]; @override String get aliasedName => _alias ?? actualTableName; @override @@ -54,6 +65,14 @@ class $PlayerTableTable extends PlayerTable } else if (isInserting) { context.missing(_nameMeta); } + if (data.containsKey('created_at')) { + context.handle( + _createdAtMeta, + createdAt.isAcceptableOrUnknown(data['created_at']!, _createdAtMeta), + ); + } else if (isInserting) { + context.missing(_createdAtMeta); + } return context; } @@ -71,6 +90,10 @@ class $PlayerTableTable extends PlayerTable DriftSqlType.string, data['${effectivePrefix}name'], )!, + createdAt: attachedDatabase.typeMapping.read( + DriftSqlType.dateTime, + data['${effectivePrefix}created_at'], + )!, ); } @@ -83,17 +106,27 @@ class $PlayerTableTable extends PlayerTable class PlayerTableData extends DataClass implements Insertable { final String id; final String name; - const PlayerTableData({required this.id, required this.name}); + final DateTime createdAt; + const PlayerTableData({ + required this.id, + required this.name, + required this.createdAt, + }); @override Map toColumns(bool nullToAbsent) { final map = {}; map['id'] = Variable(id); map['name'] = Variable(name); + map['created_at'] = Variable(createdAt); return map; } PlayerTableCompanion toCompanion(bool nullToAbsent) { - return PlayerTableCompanion(id: Value(id), name: Value(name)); + return PlayerTableCompanion( + id: Value(id), + name: Value(name), + createdAt: Value(createdAt), + ); } factory PlayerTableData.fromJson( @@ -104,6 +137,7 @@ class PlayerTableData extends DataClass implements Insertable { return PlayerTableData( id: serializer.fromJson(json['id']), name: serializer.fromJson(json['name']), + createdAt: serializer.fromJson(json['createdAt']), ); } @override @@ -112,15 +146,21 @@ class PlayerTableData extends DataClass implements Insertable { return { 'id': serializer.toJson(id), 'name': serializer.toJson(name), + 'createdAt': serializer.toJson(createdAt), }; } - PlayerTableData copyWith({String? id, String? name}) => - PlayerTableData(id: id ?? this.id, name: name ?? this.name); + PlayerTableData copyWith({String? id, String? name, DateTime? createdAt}) => + PlayerTableData( + id: id ?? this.id, + name: name ?? this.name, + createdAt: createdAt ?? this.createdAt, + ); PlayerTableData copyWithCompanion(PlayerTableCompanion data) { return PlayerTableData( id: data.id.present ? data.id.value : this.id, name: data.name.present ? data.name.value : this.name, + createdAt: data.createdAt.present ? data.createdAt.value : this.createdAt, ); } @@ -128,44 +168,52 @@ class PlayerTableData extends DataClass implements Insertable { String toString() { return (StringBuffer('PlayerTableData(') ..write('id: $id, ') - ..write('name: $name') + ..write('name: $name, ') + ..write('createdAt: $createdAt') ..write(')')) .toString(); } @override - int get hashCode => Object.hash(id, name); + int get hashCode => Object.hash(id, name, createdAt); @override bool operator ==(Object other) => identical(this, other) || (other is PlayerTableData && other.id == this.id && - other.name == this.name); + other.name == this.name && + other.createdAt == this.createdAt); } class PlayerTableCompanion extends UpdateCompanion { final Value id; final Value name; + final Value createdAt; final Value rowid; const PlayerTableCompanion({ this.id = const Value.absent(), this.name = const Value.absent(), + this.createdAt = const Value.absent(), this.rowid = const Value.absent(), }); PlayerTableCompanion.insert({ required String id, required String name, + required DateTime createdAt, this.rowid = const Value.absent(), }) : id = Value(id), - name = Value(name); + name = Value(name), + createdAt = Value(createdAt); static Insertable custom({ Expression? id, Expression? name, + Expression? createdAt, Expression? rowid, }) { return RawValuesInsertable({ if (id != null) 'id': id, if (name != null) 'name': name, + if (createdAt != null) 'created_at': createdAt, if (rowid != null) 'rowid': rowid, }); } @@ -173,11 +221,13 @@ class PlayerTableCompanion extends UpdateCompanion { PlayerTableCompanion copyWith({ Value? id, Value? name, + Value? createdAt, Value? rowid, }) { return PlayerTableCompanion( id: id ?? this.id, name: name ?? this.name, + createdAt: createdAt ?? this.createdAt, rowid: rowid ?? this.rowid, ); } @@ -191,6 +241,9 @@ class PlayerTableCompanion extends UpdateCompanion { if (name.present) { map['name'] = Variable(name.value); } + if (createdAt.present) { + map['created_at'] = Variable(createdAt.value); + } if (rowid.present) { map['rowid'] = Variable(rowid.value); } @@ -202,6 +255,7 @@ class PlayerTableCompanion extends UpdateCompanion { return (StringBuffer('PlayerTableCompanion(') ..write('id: $id, ') ..write('name: $name, ') + ..write('createdAt: $createdAt, ') ..write('rowid: $rowid') ..write(')')) .toString(); @@ -232,8 +286,19 @@ class $GroupTableTable extends GroupTable type: DriftSqlType.string, requiredDuringInsert: true, ); + static const VerificationMeta _createdAtMeta = const VerificationMeta( + 'createdAt', + ); @override - List get $columns => [id, name]; + late final GeneratedColumn createdAt = GeneratedColumn( + 'created_at', + aliasedName, + false, + type: DriftSqlType.dateTime, + requiredDuringInsert: true, + ); + @override + List get $columns => [id, name, createdAt]; @override String get aliasedName => _alias ?? actualTableName; @override @@ -259,6 +324,14 @@ class $GroupTableTable extends GroupTable } else if (isInserting) { context.missing(_nameMeta); } + if (data.containsKey('created_at')) { + context.handle( + _createdAtMeta, + createdAt.isAcceptableOrUnknown(data['created_at']!, _createdAtMeta), + ); + } else if (isInserting) { + context.missing(_createdAtMeta); + } return context; } @@ -276,6 +349,10 @@ class $GroupTableTable extends GroupTable DriftSqlType.string, data['${effectivePrefix}name'], )!, + createdAt: attachedDatabase.typeMapping.read( + DriftSqlType.dateTime, + data['${effectivePrefix}created_at'], + )!, ); } @@ -288,17 +365,27 @@ class $GroupTableTable extends GroupTable class GroupTableData extends DataClass implements Insertable { final String id; final String name; - const GroupTableData({required this.id, required this.name}); + final DateTime createdAt; + const GroupTableData({ + required this.id, + required this.name, + required this.createdAt, + }); @override Map toColumns(bool nullToAbsent) { final map = {}; map['id'] = Variable(id); map['name'] = Variable(name); + map['created_at'] = Variable(createdAt); return map; } GroupTableCompanion toCompanion(bool nullToAbsent) { - return GroupTableCompanion(id: Value(id), name: Value(name)); + return GroupTableCompanion( + id: Value(id), + name: Value(name), + createdAt: Value(createdAt), + ); } factory GroupTableData.fromJson( @@ -309,6 +396,7 @@ class GroupTableData extends DataClass implements Insertable { return GroupTableData( id: serializer.fromJson(json['id']), name: serializer.fromJson(json['name']), + createdAt: serializer.fromJson(json['createdAt']), ); } @override @@ -317,15 +405,21 @@ class GroupTableData extends DataClass implements Insertable { return { 'id': serializer.toJson(id), 'name': serializer.toJson(name), + 'createdAt': serializer.toJson(createdAt), }; } - GroupTableData copyWith({String? id, String? name}) => - GroupTableData(id: id ?? this.id, name: name ?? this.name); + GroupTableData copyWith({String? id, String? name, DateTime? createdAt}) => + GroupTableData( + id: id ?? this.id, + name: name ?? this.name, + createdAt: createdAt ?? this.createdAt, + ); GroupTableData copyWithCompanion(GroupTableCompanion data) { return GroupTableData( id: data.id.present ? data.id.value : this.id, name: data.name.present ? data.name.value : this.name, + createdAt: data.createdAt.present ? data.createdAt.value : this.createdAt, ); } @@ -333,44 +427,52 @@ class GroupTableData extends DataClass implements Insertable { String toString() { return (StringBuffer('GroupTableData(') ..write('id: $id, ') - ..write('name: $name') + ..write('name: $name, ') + ..write('createdAt: $createdAt') ..write(')')) .toString(); } @override - int get hashCode => Object.hash(id, name); + int get hashCode => Object.hash(id, name, createdAt); @override bool operator ==(Object other) => identical(this, other) || (other is GroupTableData && other.id == this.id && - other.name == this.name); + other.name == this.name && + other.createdAt == this.createdAt); } class GroupTableCompanion extends UpdateCompanion { final Value id; final Value name; + final Value createdAt; final Value rowid; const GroupTableCompanion({ this.id = const Value.absent(), this.name = const Value.absent(), + this.createdAt = const Value.absent(), this.rowid = const Value.absent(), }); GroupTableCompanion.insert({ required String id, required String name, + required DateTime createdAt, this.rowid = const Value.absent(), }) : id = Value(id), - name = Value(name); + name = Value(name), + createdAt = Value(createdAt); static Insertable custom({ Expression? id, Expression? name, + Expression? createdAt, Expression? rowid, }) { return RawValuesInsertable({ if (id != null) 'id': id, if (name != null) 'name': name, + if (createdAt != null) 'created_at': createdAt, if (rowid != null) 'rowid': rowid, }); } @@ -378,11 +480,13 @@ class GroupTableCompanion extends UpdateCompanion { GroupTableCompanion copyWith({ Value? id, Value? name, + Value? createdAt, Value? rowid, }) { return GroupTableCompanion( id: id ?? this.id, name: name ?? this.name, + createdAt: createdAt ?? this.createdAt, rowid: rowid ?? this.rowid, ); } @@ -396,6 +500,9 @@ class GroupTableCompanion extends UpdateCompanion { if (name.present) { map['name'] = Variable(name.value); } + if (createdAt.present) { + map['created_at'] = Variable(createdAt.value); + } if (rowid.present) { map['rowid'] = Variable(rowid.value); } @@ -407,229 +514,7 @@ class GroupTableCompanion extends UpdateCompanion { return (StringBuffer('GroupTableCompanion(') ..write('id: $id, ') ..write('name: $name, ') - ..write('rowid: $rowid') - ..write(')')) - .toString(); - } -} - -class $PlayerGroupTableTable extends PlayerGroupTable - with TableInfo<$PlayerGroupTableTable, PlayerGroupTableData> { - @override - final GeneratedDatabase attachedDatabase; - final String? _alias; - $PlayerGroupTableTable(this.attachedDatabase, [this._alias]); - static const VerificationMeta _userIdMeta = const VerificationMeta('userId'); - @override - late final GeneratedColumn userId = GeneratedColumn( - 'user_id', - aliasedName, - false, - type: DriftSqlType.string, - requiredDuringInsert: true, - defaultConstraints: GeneratedColumn.constraintIsAlways( - 'REFERENCES player_table (id)', - ), - ); - static const VerificationMeta _groupIdMeta = const VerificationMeta( - 'groupId', - ); - @override - late final GeneratedColumn groupId = GeneratedColumn( - 'group_id', - aliasedName, - false, - type: DriftSqlType.string, - requiredDuringInsert: true, - defaultConstraints: GeneratedColumn.constraintIsAlways( - 'REFERENCES group_table (id)', - ), - ); - @override - List get $columns => [userId, groupId]; - @override - String get aliasedName => _alias ?? actualTableName; - @override - String get actualTableName => $name; - static const String $name = 'player_group_table'; - @override - VerificationContext validateIntegrity( - Insertable instance, { - bool isInserting = false, - }) { - final context = VerificationContext(); - final data = instance.toColumns(true); - if (data.containsKey('user_id')) { - context.handle( - _userIdMeta, - userId.isAcceptableOrUnknown(data['user_id']!, _userIdMeta), - ); - } else if (isInserting) { - context.missing(_userIdMeta); - } - if (data.containsKey('group_id')) { - context.handle( - _groupIdMeta, - groupId.isAcceptableOrUnknown(data['group_id']!, _groupIdMeta), - ); - } else if (isInserting) { - context.missing(_groupIdMeta); - } - return context; - } - - @override - Set get $primaryKey => {userId, groupId}; - @override - PlayerGroupTableData map(Map data, {String? tablePrefix}) { - final effectivePrefix = tablePrefix != null ? '$tablePrefix.' : ''; - return PlayerGroupTableData( - userId: attachedDatabase.typeMapping.read( - DriftSqlType.string, - data['${effectivePrefix}user_id'], - )!, - groupId: attachedDatabase.typeMapping.read( - DriftSqlType.string, - data['${effectivePrefix}group_id'], - )!, - ); - } - - @override - $PlayerGroupTableTable createAlias(String alias) { - return $PlayerGroupTableTable(attachedDatabase, alias); - } -} - -class PlayerGroupTableData extends DataClass - implements Insertable { - final String userId; - final String groupId; - const PlayerGroupTableData({required this.userId, required this.groupId}); - @override - Map toColumns(bool nullToAbsent) { - final map = {}; - map['user_id'] = Variable(userId); - map['group_id'] = Variable(groupId); - return map; - } - - PlayerGroupTableCompanion toCompanion(bool nullToAbsent) { - return PlayerGroupTableCompanion( - userId: Value(userId), - groupId: Value(groupId), - ); - } - - factory PlayerGroupTableData.fromJson( - Map json, { - ValueSerializer? serializer, - }) { - serializer ??= driftRuntimeOptions.defaultSerializer; - return PlayerGroupTableData( - userId: serializer.fromJson(json['userId']), - groupId: serializer.fromJson(json['groupId']), - ); - } - @override - Map toJson({ValueSerializer? serializer}) { - serializer ??= driftRuntimeOptions.defaultSerializer; - return { - 'userId': serializer.toJson(userId), - 'groupId': serializer.toJson(groupId), - }; - } - - PlayerGroupTableData copyWith({String? userId, String? groupId}) => - PlayerGroupTableData( - userId: userId ?? this.userId, - groupId: groupId ?? this.groupId, - ); - PlayerGroupTableData copyWithCompanion(PlayerGroupTableCompanion data) { - return PlayerGroupTableData( - userId: data.userId.present ? data.userId.value : this.userId, - groupId: data.groupId.present ? data.groupId.value : this.groupId, - ); - } - - @override - String toString() { - return (StringBuffer('PlayerGroupTableData(') - ..write('userId: $userId, ') - ..write('groupId: $groupId') - ..write(')')) - .toString(); - } - - @override - int get hashCode => Object.hash(userId, groupId); - @override - bool operator ==(Object other) => - identical(this, other) || - (other is PlayerGroupTableData && - other.userId == this.userId && - other.groupId == this.groupId); -} - -class PlayerGroupTableCompanion extends UpdateCompanion { - final Value userId; - final Value groupId; - final Value rowid; - const PlayerGroupTableCompanion({ - this.userId = const Value.absent(), - this.groupId = const Value.absent(), - this.rowid = const Value.absent(), - }); - PlayerGroupTableCompanion.insert({ - required String userId, - required String groupId, - this.rowid = const Value.absent(), - }) : userId = Value(userId), - groupId = Value(groupId); - static Insertable custom({ - Expression? userId, - Expression? groupId, - Expression? rowid, - }) { - return RawValuesInsertable({ - if (userId != null) 'user_id': userId, - if (groupId != null) 'group_id': groupId, - if (rowid != null) 'rowid': rowid, - }); - } - - PlayerGroupTableCompanion copyWith({ - Value? userId, - Value? groupId, - Value? rowid, - }) { - return PlayerGroupTableCompanion( - userId: userId ?? this.userId, - groupId: groupId ?? this.groupId, - rowid: rowid ?? this.rowid, - ); - } - - @override - Map toColumns(bool nullToAbsent) { - final map = {}; - if (userId.present) { - map['user_id'] = Variable(userId.value); - } - if (groupId.present) { - map['group_id'] = Variable(groupId.value); - } - if (rowid.present) { - map['rowid'] = Variable(rowid.value); - } - return map; - } - - @override - String toString() { - return (StringBuffer('PlayerGroupTableCompanion(') - ..write('userId: $userId, ') - ..write('groupId: $groupId, ') + ..write('createdAt: $createdAt, ') ..write('rowid: $rowid') ..write(')')) .toString(); @@ -660,8 +545,33 @@ class $GameTableTable extends GameTable type: DriftSqlType.string, requiredDuringInsert: true, ); + static const VerificationMeta _winnerIdMeta = const VerificationMeta( + 'winnerId', + ); @override - List get $columns => [id, name]; + late final GeneratedColumn winnerId = GeneratedColumn( + 'winner_id', + aliasedName, + false, + type: DriftSqlType.string, + requiredDuringInsert: true, + defaultConstraints: GeneratedColumn.constraintIsAlways( + 'REFERENCES player_table (id) ON DELETE CASCADE', + ), + ); + static const VerificationMeta _createdAtMeta = const VerificationMeta( + 'createdAt', + ); + @override + late final GeneratedColumn createdAt = GeneratedColumn( + 'created_at', + aliasedName, + false, + type: DriftSqlType.dateTime, + requiredDuringInsert: true, + ); + @override + List get $columns => [id, name, winnerId, createdAt]; @override String get aliasedName => _alias ?? actualTableName; @override @@ -687,6 +597,22 @@ class $GameTableTable extends GameTable } else if (isInserting) { context.missing(_nameMeta); } + if (data.containsKey('winner_id')) { + context.handle( + _winnerIdMeta, + winnerId.isAcceptableOrUnknown(data['winner_id']!, _winnerIdMeta), + ); + } else if (isInserting) { + context.missing(_winnerIdMeta); + } + if (data.containsKey('created_at')) { + context.handle( + _createdAtMeta, + createdAt.isAcceptableOrUnknown(data['created_at']!, _createdAtMeta), + ); + } else if (isInserting) { + context.missing(_createdAtMeta); + } return context; } @@ -704,6 +630,14 @@ class $GameTableTable extends GameTable DriftSqlType.string, data['${effectivePrefix}name'], )!, + winnerId: attachedDatabase.typeMapping.read( + DriftSqlType.string, + data['${effectivePrefix}winner_id'], + )!, + createdAt: attachedDatabase.typeMapping.read( + DriftSqlType.dateTime, + data['${effectivePrefix}created_at'], + )!, ); } @@ -716,17 +650,31 @@ class $GameTableTable extends GameTable class GameTableData extends DataClass implements Insertable { final String id; final String name; - const GameTableData({required this.id, required this.name}); + final String winnerId; + final DateTime createdAt; + const GameTableData({ + required this.id, + required this.name, + required this.winnerId, + required this.createdAt, + }); @override Map toColumns(bool nullToAbsent) { final map = {}; map['id'] = Variable(id); map['name'] = Variable(name); + map['winner_id'] = Variable(winnerId); + map['created_at'] = Variable(createdAt); return map; } GameTableCompanion toCompanion(bool nullToAbsent) { - return GameTableCompanion(id: Value(id), name: Value(name)); + return GameTableCompanion( + id: Value(id), + name: Value(name), + winnerId: Value(winnerId), + createdAt: Value(createdAt), + ); } factory GameTableData.fromJson( @@ -737,6 +685,8 @@ class GameTableData extends DataClass implements Insertable { return GameTableData( id: serializer.fromJson(json['id']), name: serializer.fromJson(json['name']), + winnerId: serializer.fromJson(json['winnerId']), + createdAt: serializer.fromJson(json['createdAt']), ); } @override @@ -745,15 +695,28 @@ class GameTableData extends DataClass implements Insertable { return { 'id': serializer.toJson(id), 'name': serializer.toJson(name), + 'winnerId': serializer.toJson(winnerId), + 'createdAt': serializer.toJson(createdAt), }; } - GameTableData copyWith({String? id, String? name}) => - GameTableData(id: id ?? this.id, name: name ?? this.name); + GameTableData copyWith({ + String? id, + String? name, + String? winnerId, + DateTime? createdAt, + }) => GameTableData( + id: id ?? this.id, + name: name ?? this.name, + winnerId: winnerId ?? this.winnerId, + createdAt: createdAt ?? this.createdAt, + ); GameTableData copyWithCompanion(GameTableCompanion data) { return GameTableData( id: data.id.present ? data.id.value : this.id, name: data.name.present ? data.name.value : this.name, + winnerId: data.winnerId.present ? data.winnerId.value : this.winnerId, + createdAt: data.createdAt.present ? data.createdAt.value : this.createdAt, ); } @@ -761,44 +724,60 @@ class GameTableData extends DataClass implements Insertable { String toString() { return (StringBuffer('GameTableData(') ..write('id: $id, ') - ..write('name: $name') + ..write('name: $name, ') + ..write('winnerId: $winnerId, ') + ..write('createdAt: $createdAt') ..write(')')) .toString(); } @override - int get hashCode => Object.hash(id, name); + int get hashCode => Object.hash(id, name, winnerId, createdAt); @override bool operator ==(Object other) => identical(this, other) || (other is GameTableData && other.id == this.id && - other.name == this.name); + other.name == this.name && + other.winnerId == this.winnerId && + other.createdAt == this.createdAt); } class GameTableCompanion extends UpdateCompanion { final Value id; final Value name; + final Value winnerId; + final Value createdAt; final Value rowid; const GameTableCompanion({ this.id = const Value.absent(), this.name = const Value.absent(), + this.winnerId = const Value.absent(), + this.createdAt = const Value.absent(), this.rowid = const Value.absent(), }); GameTableCompanion.insert({ required String id, required String name, + required String winnerId, + required DateTime createdAt, this.rowid = const Value.absent(), }) : id = Value(id), - name = Value(name); + name = Value(name), + winnerId = Value(winnerId), + createdAt = Value(createdAt); static Insertable custom({ Expression? id, Expression? name, + Expression? winnerId, + Expression? createdAt, Expression? rowid, }) { return RawValuesInsertable({ if (id != null) 'id': id, if (name != null) 'name': name, + if (winnerId != null) 'winner_id': winnerId, + if (createdAt != null) 'created_at': createdAt, if (rowid != null) 'rowid': rowid, }); } @@ -806,11 +785,15 @@ class GameTableCompanion extends UpdateCompanion { GameTableCompanion copyWith({ Value? id, Value? name, + Value? winnerId, + Value? createdAt, Value? rowid, }) { return GameTableCompanion( id: id ?? this.id, name: name ?? this.name, + winnerId: winnerId ?? this.winnerId, + createdAt: createdAt ?? this.createdAt, rowid: rowid ?? this.rowid, ); } @@ -824,6 +807,12 @@ class GameTableCompanion extends UpdateCompanion { if (name.present) { map['name'] = Variable(name.value); } + if (winnerId.present) { + map['winner_id'] = Variable(winnerId.value); + } + if (createdAt.present) { + map['created_at'] = Variable(createdAt.value); + } if (rowid.present) { map['rowid'] = Variable(rowid.value); } @@ -835,6 +824,679 @@ class GameTableCompanion extends UpdateCompanion { return (StringBuffer('GameTableCompanion(') ..write('id: $id, ') ..write('name: $name, ') + ..write('winnerId: $winnerId, ') + ..write('createdAt: $createdAt, ') + ..write('rowid: $rowid') + ..write(')')) + .toString(); + } +} + +class $PlayerGroupTableTable extends PlayerGroupTable + with TableInfo<$PlayerGroupTableTable, PlayerGroupTableData> { + @override + final GeneratedDatabase attachedDatabase; + final String? _alias; + $PlayerGroupTableTable(this.attachedDatabase, [this._alias]); + static const VerificationMeta _playerIdMeta = const VerificationMeta( + 'playerId', + ); + @override + late final GeneratedColumn playerId = GeneratedColumn( + 'player_id', + aliasedName, + false, + type: DriftSqlType.string, + requiredDuringInsert: true, + defaultConstraints: GeneratedColumn.constraintIsAlways( + 'REFERENCES player_table (id) ON DELETE CASCADE', + ), + ); + static const VerificationMeta _groupIdMeta = const VerificationMeta( + 'groupId', + ); + @override + late final GeneratedColumn groupId = GeneratedColumn( + 'group_id', + aliasedName, + false, + type: DriftSqlType.string, + requiredDuringInsert: true, + defaultConstraints: GeneratedColumn.constraintIsAlways( + 'REFERENCES group_table (id) ON DELETE CASCADE', + ), + ); + @override + List get $columns => [playerId, groupId]; + @override + String get aliasedName => _alias ?? actualTableName; + @override + String get actualTableName => $name; + static const String $name = 'player_group_table'; + @override + VerificationContext validateIntegrity( + Insertable instance, { + bool isInserting = false, + }) { + final context = VerificationContext(); + final data = instance.toColumns(true); + if (data.containsKey('player_id')) { + context.handle( + _playerIdMeta, + playerId.isAcceptableOrUnknown(data['player_id']!, _playerIdMeta), + ); + } else if (isInserting) { + context.missing(_playerIdMeta); + } + if (data.containsKey('group_id')) { + context.handle( + _groupIdMeta, + groupId.isAcceptableOrUnknown(data['group_id']!, _groupIdMeta), + ); + } else if (isInserting) { + context.missing(_groupIdMeta); + } + return context; + } + + @override + Set get $primaryKey => {playerId, groupId}; + @override + PlayerGroupTableData map(Map data, {String? tablePrefix}) { + final effectivePrefix = tablePrefix != null ? '$tablePrefix.' : ''; + return PlayerGroupTableData( + playerId: attachedDatabase.typeMapping.read( + DriftSqlType.string, + data['${effectivePrefix}player_id'], + )!, + groupId: attachedDatabase.typeMapping.read( + DriftSqlType.string, + data['${effectivePrefix}group_id'], + )!, + ); + } + + @override + $PlayerGroupTableTable createAlias(String alias) { + return $PlayerGroupTableTable(attachedDatabase, alias); + } +} + +class PlayerGroupTableData extends DataClass + implements Insertable { + final String playerId; + final String groupId; + const PlayerGroupTableData({required this.playerId, required this.groupId}); + @override + Map toColumns(bool nullToAbsent) { + final map = {}; + map['player_id'] = Variable(playerId); + map['group_id'] = Variable(groupId); + return map; + } + + PlayerGroupTableCompanion toCompanion(bool nullToAbsent) { + return PlayerGroupTableCompanion( + playerId: Value(playerId), + groupId: Value(groupId), + ); + } + + factory PlayerGroupTableData.fromJson( + Map json, { + ValueSerializer? serializer, + }) { + serializer ??= driftRuntimeOptions.defaultSerializer; + return PlayerGroupTableData( + playerId: serializer.fromJson(json['playerId']), + groupId: serializer.fromJson(json['groupId']), + ); + } + @override + Map toJson({ValueSerializer? serializer}) { + serializer ??= driftRuntimeOptions.defaultSerializer; + return { + 'playerId': serializer.toJson(playerId), + 'groupId': serializer.toJson(groupId), + }; + } + + PlayerGroupTableData copyWith({String? playerId, String? groupId}) => + PlayerGroupTableData( + playerId: playerId ?? this.playerId, + groupId: groupId ?? this.groupId, + ); + PlayerGroupTableData copyWithCompanion(PlayerGroupTableCompanion data) { + return PlayerGroupTableData( + playerId: data.playerId.present ? data.playerId.value : this.playerId, + groupId: data.groupId.present ? data.groupId.value : this.groupId, + ); + } + + @override + String toString() { + return (StringBuffer('PlayerGroupTableData(') + ..write('playerId: $playerId, ') + ..write('groupId: $groupId') + ..write(')')) + .toString(); + } + + @override + int get hashCode => Object.hash(playerId, groupId); + @override + bool operator ==(Object other) => + identical(this, other) || + (other is PlayerGroupTableData && + other.playerId == this.playerId && + other.groupId == this.groupId); +} + +class PlayerGroupTableCompanion extends UpdateCompanion { + final Value playerId; + final Value groupId; + final Value rowid; + const PlayerGroupTableCompanion({ + this.playerId = const Value.absent(), + this.groupId = const Value.absent(), + this.rowid = const Value.absent(), + }); + PlayerGroupTableCompanion.insert({ + required String playerId, + required String groupId, + this.rowid = const Value.absent(), + }) : playerId = Value(playerId), + groupId = Value(groupId); + static Insertable custom({ + Expression? playerId, + Expression? groupId, + Expression? rowid, + }) { + return RawValuesInsertable({ + if (playerId != null) 'player_id': playerId, + if (groupId != null) 'group_id': groupId, + if (rowid != null) 'rowid': rowid, + }); + } + + PlayerGroupTableCompanion copyWith({ + Value? playerId, + Value? groupId, + Value? rowid, + }) { + return PlayerGroupTableCompanion( + playerId: playerId ?? this.playerId, + groupId: groupId ?? this.groupId, + rowid: rowid ?? this.rowid, + ); + } + + @override + Map toColumns(bool nullToAbsent) { + final map = {}; + if (playerId.present) { + map['player_id'] = Variable(playerId.value); + } + if (groupId.present) { + map['group_id'] = Variable(groupId.value); + } + if (rowid.present) { + map['rowid'] = Variable(rowid.value); + } + return map; + } + + @override + String toString() { + return (StringBuffer('PlayerGroupTableCompanion(') + ..write('playerId: $playerId, ') + ..write('groupId: $groupId, ') + ..write('rowid: $rowid') + ..write(')')) + .toString(); + } +} + +class $PlayerGameTableTable extends PlayerGameTable + with TableInfo<$PlayerGameTableTable, PlayerGameTableData> { + @override + final GeneratedDatabase attachedDatabase; + final String? _alias; + $PlayerGameTableTable(this.attachedDatabase, [this._alias]); + static const VerificationMeta _playerIdMeta = const VerificationMeta( + 'playerId', + ); + @override + late final GeneratedColumn playerId = GeneratedColumn( + 'player_id', + aliasedName, + false, + type: DriftSqlType.string, + requiredDuringInsert: true, + defaultConstraints: GeneratedColumn.constraintIsAlways( + 'REFERENCES player_table (id) ON DELETE CASCADE', + ), + ); + static const VerificationMeta _gameIdMeta = const VerificationMeta('gameId'); + @override + late final GeneratedColumn gameId = GeneratedColumn( + 'game_id', + aliasedName, + false, + type: DriftSqlType.string, + requiredDuringInsert: true, + defaultConstraints: GeneratedColumn.constraintIsAlways( + 'REFERENCES game_table (id) ON DELETE CASCADE', + ), + ); + @override + List get $columns => [playerId, gameId]; + @override + String get aliasedName => _alias ?? actualTableName; + @override + String get actualTableName => $name; + static const String $name = 'player_game_table'; + @override + VerificationContext validateIntegrity( + Insertable instance, { + bool isInserting = false, + }) { + final context = VerificationContext(); + final data = instance.toColumns(true); + if (data.containsKey('player_id')) { + context.handle( + _playerIdMeta, + playerId.isAcceptableOrUnknown(data['player_id']!, _playerIdMeta), + ); + } else if (isInserting) { + context.missing(_playerIdMeta); + } + if (data.containsKey('game_id')) { + context.handle( + _gameIdMeta, + gameId.isAcceptableOrUnknown(data['game_id']!, _gameIdMeta), + ); + } else if (isInserting) { + context.missing(_gameIdMeta); + } + return context; + } + + @override + Set get $primaryKey => {playerId, gameId}; + @override + PlayerGameTableData map(Map data, {String? tablePrefix}) { + final effectivePrefix = tablePrefix != null ? '$tablePrefix.' : ''; + return PlayerGameTableData( + playerId: attachedDatabase.typeMapping.read( + DriftSqlType.string, + data['${effectivePrefix}player_id'], + )!, + gameId: attachedDatabase.typeMapping.read( + DriftSqlType.string, + data['${effectivePrefix}game_id'], + )!, + ); + } + + @override + $PlayerGameTableTable createAlias(String alias) { + return $PlayerGameTableTable(attachedDatabase, alias); + } +} + +class PlayerGameTableData extends DataClass + implements Insertable { + final String playerId; + final String gameId; + const PlayerGameTableData({required this.playerId, required this.gameId}); + @override + Map toColumns(bool nullToAbsent) { + final map = {}; + map['player_id'] = Variable(playerId); + map['game_id'] = Variable(gameId); + return map; + } + + PlayerGameTableCompanion toCompanion(bool nullToAbsent) { + return PlayerGameTableCompanion( + playerId: Value(playerId), + gameId: Value(gameId), + ); + } + + factory PlayerGameTableData.fromJson( + Map json, { + ValueSerializer? serializer, + }) { + serializer ??= driftRuntimeOptions.defaultSerializer; + return PlayerGameTableData( + playerId: serializer.fromJson(json['playerId']), + gameId: serializer.fromJson(json['gameId']), + ); + } + @override + Map toJson({ValueSerializer? serializer}) { + serializer ??= driftRuntimeOptions.defaultSerializer; + return { + 'playerId': serializer.toJson(playerId), + 'gameId': serializer.toJson(gameId), + }; + } + + PlayerGameTableData copyWith({String? playerId, String? gameId}) => + PlayerGameTableData( + playerId: playerId ?? this.playerId, + gameId: gameId ?? this.gameId, + ); + PlayerGameTableData copyWithCompanion(PlayerGameTableCompanion data) { + return PlayerGameTableData( + playerId: data.playerId.present ? data.playerId.value : this.playerId, + gameId: data.gameId.present ? data.gameId.value : this.gameId, + ); + } + + @override + String toString() { + return (StringBuffer('PlayerGameTableData(') + ..write('playerId: $playerId, ') + ..write('gameId: $gameId') + ..write(')')) + .toString(); + } + + @override + int get hashCode => Object.hash(playerId, gameId); + @override + bool operator ==(Object other) => + identical(this, other) || + (other is PlayerGameTableData && + other.playerId == this.playerId && + other.gameId == this.gameId); +} + +class PlayerGameTableCompanion extends UpdateCompanion { + final Value playerId; + final Value gameId; + final Value rowid; + const PlayerGameTableCompanion({ + this.playerId = const Value.absent(), + this.gameId = const Value.absent(), + this.rowid = const Value.absent(), + }); + PlayerGameTableCompanion.insert({ + required String playerId, + required String gameId, + this.rowid = const Value.absent(), + }) : playerId = Value(playerId), + gameId = Value(gameId); + static Insertable custom({ + Expression? playerId, + Expression? gameId, + Expression? rowid, + }) { + return RawValuesInsertable({ + if (playerId != null) 'player_id': playerId, + if (gameId != null) 'game_id': gameId, + if (rowid != null) 'rowid': rowid, + }); + } + + PlayerGameTableCompanion copyWith({ + Value? playerId, + Value? gameId, + Value? rowid, + }) { + return PlayerGameTableCompanion( + playerId: playerId ?? this.playerId, + gameId: gameId ?? this.gameId, + rowid: rowid ?? this.rowid, + ); + } + + @override + Map toColumns(bool nullToAbsent) { + final map = {}; + if (playerId.present) { + map['player_id'] = Variable(playerId.value); + } + if (gameId.present) { + map['game_id'] = Variable(gameId.value); + } + if (rowid.present) { + map['rowid'] = Variable(rowid.value); + } + return map; + } + + @override + String toString() { + return (StringBuffer('PlayerGameTableCompanion(') + ..write('playerId: $playerId, ') + ..write('gameId: $gameId, ') + ..write('rowid: $rowid') + ..write(')')) + .toString(); + } +} + +class $GroupGameTableTable extends GroupGameTable + with TableInfo<$GroupGameTableTable, GroupGameTableData> { + @override + final GeneratedDatabase attachedDatabase; + final String? _alias; + $GroupGameTableTable(this.attachedDatabase, [this._alias]); + static const VerificationMeta _groupIdMeta = const VerificationMeta( + 'groupId', + ); + @override + late final GeneratedColumn groupId = GeneratedColumn( + 'group_id', + aliasedName, + false, + type: DriftSqlType.string, + requiredDuringInsert: true, + defaultConstraints: GeneratedColumn.constraintIsAlways( + 'REFERENCES group_table (id) ON DELETE CASCADE', + ), + ); + static const VerificationMeta _gameIdMeta = const VerificationMeta('gameId'); + @override + late final GeneratedColumn gameId = GeneratedColumn( + 'game_id', + aliasedName, + false, + type: DriftSqlType.string, + requiredDuringInsert: true, + defaultConstraints: GeneratedColumn.constraintIsAlways( + 'REFERENCES game_table (id) ON DELETE CASCADE', + ), + ); + @override + List get $columns => [groupId, gameId]; + @override + String get aliasedName => _alias ?? actualTableName; + @override + String get actualTableName => $name; + static const String $name = 'group_game_table'; + @override + VerificationContext validateIntegrity( + Insertable instance, { + bool isInserting = false, + }) { + final context = VerificationContext(); + final data = instance.toColumns(true); + if (data.containsKey('group_id')) { + context.handle( + _groupIdMeta, + groupId.isAcceptableOrUnknown(data['group_id']!, _groupIdMeta), + ); + } else if (isInserting) { + context.missing(_groupIdMeta); + } + if (data.containsKey('game_id')) { + context.handle( + _gameIdMeta, + gameId.isAcceptableOrUnknown(data['game_id']!, _gameIdMeta), + ); + } else if (isInserting) { + context.missing(_gameIdMeta); + } + return context; + } + + @override + Set get $primaryKey => {groupId, gameId}; + @override + GroupGameTableData map(Map data, {String? tablePrefix}) { + final effectivePrefix = tablePrefix != null ? '$tablePrefix.' : ''; + return GroupGameTableData( + groupId: attachedDatabase.typeMapping.read( + DriftSqlType.string, + data['${effectivePrefix}group_id'], + )!, + gameId: attachedDatabase.typeMapping.read( + DriftSqlType.string, + data['${effectivePrefix}game_id'], + )!, + ); + } + + @override + $GroupGameTableTable createAlias(String alias) { + return $GroupGameTableTable(attachedDatabase, alias); + } +} + +class GroupGameTableData extends DataClass + implements Insertable { + final String groupId; + final String gameId; + const GroupGameTableData({required this.groupId, required this.gameId}); + @override + Map toColumns(bool nullToAbsent) { + final map = {}; + map['group_id'] = Variable(groupId); + map['game_id'] = Variable(gameId); + return map; + } + + GroupGameTableCompanion toCompanion(bool nullToAbsent) { + return GroupGameTableCompanion( + groupId: Value(groupId), + gameId: Value(gameId), + ); + } + + factory GroupGameTableData.fromJson( + Map json, { + ValueSerializer? serializer, + }) { + serializer ??= driftRuntimeOptions.defaultSerializer; + return GroupGameTableData( + groupId: serializer.fromJson(json['groupId']), + gameId: serializer.fromJson(json['gameId']), + ); + } + @override + Map toJson({ValueSerializer? serializer}) { + serializer ??= driftRuntimeOptions.defaultSerializer; + return { + 'groupId': serializer.toJson(groupId), + 'gameId': serializer.toJson(gameId), + }; + } + + GroupGameTableData copyWith({String? groupId, String? gameId}) => + GroupGameTableData( + groupId: groupId ?? this.groupId, + gameId: gameId ?? this.gameId, + ); + GroupGameTableData copyWithCompanion(GroupGameTableCompanion data) { + return GroupGameTableData( + groupId: data.groupId.present ? data.groupId.value : this.groupId, + gameId: data.gameId.present ? data.gameId.value : this.gameId, + ); + } + + @override + String toString() { + return (StringBuffer('GroupGameTableData(') + ..write('groupId: $groupId, ') + ..write('gameId: $gameId') + ..write(')')) + .toString(); + } + + @override + int get hashCode => Object.hash(groupId, gameId); + @override + bool operator ==(Object other) => + identical(this, other) || + (other is GroupGameTableData && + other.groupId == this.groupId && + other.gameId == this.gameId); +} + +class GroupGameTableCompanion extends UpdateCompanion { + final Value groupId; + final Value gameId; + final Value rowid; + const GroupGameTableCompanion({ + this.groupId = const Value.absent(), + this.gameId = const Value.absent(), + this.rowid = const Value.absent(), + }); + GroupGameTableCompanion.insert({ + required String groupId, + required String gameId, + this.rowid = const Value.absent(), + }) : groupId = Value(groupId), + gameId = Value(gameId); + static Insertable custom({ + Expression? groupId, + Expression? gameId, + Expression? rowid, + }) { + return RawValuesInsertable({ + if (groupId != null) 'group_id': groupId, + if (gameId != null) 'game_id': gameId, + if (rowid != null) 'rowid': rowid, + }); + } + + GroupGameTableCompanion copyWith({ + Value? groupId, + Value? gameId, + Value? rowid, + }) { + return GroupGameTableCompanion( + groupId: groupId ?? this.groupId, + gameId: gameId ?? this.gameId, + rowid: rowid ?? this.rowid, + ); + } + + @override + Map toColumns(bool nullToAbsent) { + final map = {}; + if (groupId.present) { + map['group_id'] = Variable(groupId.value); + } + if (gameId.present) { + map['game_id'] = Variable(gameId.value); + } + if (rowid.present) { + map['rowid'] = Variable(rowid.value); + } + return map; + } + + @override + String toString() { + return (StringBuffer('GroupGameTableCompanion(') + ..write('groupId: $groupId, ') + ..write('gameId: $gameId, ') ..write('rowid: $rowid') ..write(')')) .toString(); @@ -846,16 +1508,22 @@ abstract class _$AppDatabase extends GeneratedDatabase { $AppDatabaseManager get managers => $AppDatabaseManager(this); late final $PlayerTableTable playerTable = $PlayerTableTable(this); late final $GroupTableTable groupTable = $GroupTableTable(this); + late final $GameTableTable gameTable = $GameTableTable(this); late final $PlayerGroupTableTable playerGroupTable = $PlayerGroupTableTable( this, ); - late final $GameTableTable gameTable = $GameTableTable(this); - late final GroupDao groupDao = GroupDao(this as AppDatabase); + late final $PlayerGameTableTable playerGameTable = $PlayerGameTableTable( + this, + ); + late final $GroupGameTableTable groupGameTable = $GroupGameTableTable(this); late final PlayerDao playerDao = PlayerDao(this as AppDatabase); + late final GroupDao groupDao = GroupDao(this as AppDatabase); + late final GameDao gameDao = GameDao(this as AppDatabase); late final PlayerGroupDao playerGroupDao = PlayerGroupDao( this as AppDatabase, ); - late final GameDao gameDao = GameDao(this as AppDatabase); + late final PlayerGameDao playerGameDao = PlayerGameDao(this as AppDatabase); + late final GroupGameDao groupGameDao = GroupGameDao(this as AppDatabase); @override Iterable> get allTables => allSchemaEntities.whereType>(); @@ -863,21 +1531,77 @@ abstract class _$AppDatabase extends GeneratedDatabase { List get allSchemaEntities => [ playerTable, groupTable, - playerGroupTable, gameTable, + playerGroupTable, + playerGameTable, + groupGameTable, ]; + @override + StreamQueryUpdateRules get streamUpdateRules => const StreamQueryUpdateRules([ + WritePropagation( + on: TableUpdateQuery.onTableName( + 'player_table', + limitUpdateKind: UpdateKind.delete, + ), + result: [TableUpdate('game_table', kind: UpdateKind.delete)], + ), + WritePropagation( + on: TableUpdateQuery.onTableName( + 'player_table', + limitUpdateKind: UpdateKind.delete, + ), + result: [TableUpdate('player_group_table', kind: UpdateKind.delete)], + ), + WritePropagation( + on: TableUpdateQuery.onTableName( + 'group_table', + limitUpdateKind: UpdateKind.delete, + ), + result: [TableUpdate('player_group_table', kind: UpdateKind.delete)], + ), + WritePropagation( + on: TableUpdateQuery.onTableName( + 'player_table', + limitUpdateKind: UpdateKind.delete, + ), + result: [TableUpdate('player_game_table', kind: UpdateKind.delete)], + ), + WritePropagation( + on: TableUpdateQuery.onTableName( + 'game_table', + limitUpdateKind: UpdateKind.delete, + ), + result: [TableUpdate('player_game_table', kind: UpdateKind.delete)], + ), + WritePropagation( + on: TableUpdateQuery.onTableName( + 'group_table', + limitUpdateKind: UpdateKind.delete, + ), + result: [TableUpdate('group_game_table', kind: UpdateKind.delete)], + ), + WritePropagation( + on: TableUpdateQuery.onTableName( + 'game_table', + limitUpdateKind: UpdateKind.delete, + ), + result: [TableUpdate('group_game_table', kind: UpdateKind.delete)], + ), + ]); } typedef $$PlayerTableTableCreateCompanionBuilder = PlayerTableCompanion Function({ required String id, required String name, + required DateTime createdAt, Value rowid, }); typedef $$PlayerTableTableUpdateCompanionBuilder = PlayerTableCompanion Function({ Value id, Value name, + Value createdAt, Value rowid, }); @@ -885,12 +1609,30 @@ final class $$PlayerTableTableReferences extends BaseReferences<_$AppDatabase, $PlayerTableTable, PlayerTableData> { $$PlayerTableTableReferences(super.$_db, super.$_table, super.$_typedResult); + static MultiTypedResultKey<$GameTableTable, List> + _gameTableRefsTable(_$AppDatabase db) => MultiTypedResultKey.fromTable( + db.gameTable, + aliasName: $_aliasNameGenerator(db.playerTable.id, db.gameTable.winnerId), + ); + + $$GameTableTableProcessedTableManager get gameTableRefs { + final manager = $$GameTableTableTableManager( + $_db, + $_db.gameTable, + ).filter((f) => f.winnerId.id.sqlEquals($_itemColumn('id')!)); + + final cache = $_typedResult.readTableOrNull(_gameTableRefsTable($_db)); + return ProcessedTableManager( + manager.$state.copyWith(prefetchedData: cache), + ); + } + static MultiTypedResultKey<$PlayerGroupTableTable, List> _playerGroupTableRefsTable(_$AppDatabase db) => MultiTypedResultKey.fromTable( db.playerGroupTable, aliasName: $_aliasNameGenerator( db.playerTable.id, - db.playerGroupTable.userId, + db.playerGroupTable.playerId, ), ); @@ -898,7 +1640,7 @@ final class $$PlayerTableTableReferences final manager = $$PlayerGroupTableTableTableManager( $_db, $_db.playerGroupTable, - ).filter((f) => f.userId.id.sqlEquals($_itemColumn('id')!)); + ).filter((f) => f.playerId.id.sqlEquals($_itemColumn('id')!)); final cache = $_typedResult.readTableOrNull( _playerGroupTableRefsTable($_db), @@ -907,6 +1649,29 @@ final class $$PlayerTableTableReferences manager.$state.copyWith(prefetchedData: cache), ); } + + static MultiTypedResultKey<$PlayerGameTableTable, List> + _playerGameTableRefsTable(_$AppDatabase db) => MultiTypedResultKey.fromTable( + db.playerGameTable, + aliasName: $_aliasNameGenerator( + db.playerTable.id, + db.playerGameTable.playerId, + ), + ); + + $$PlayerGameTableTableProcessedTableManager get playerGameTableRefs { + final manager = $$PlayerGameTableTableTableManager( + $_db, + $_db.playerGameTable, + ).filter((f) => f.playerId.id.sqlEquals($_itemColumn('id')!)); + + final cache = $_typedResult.readTableOrNull( + _playerGameTableRefsTable($_db), + ); + return ProcessedTableManager( + manager.$state.copyWith(prefetchedData: cache), + ); + } } class $$PlayerTableTableFilterComposer @@ -928,6 +1693,36 @@ class $$PlayerTableTableFilterComposer builder: (column) => ColumnFilters(column), ); + ColumnFilters get createdAt => $composableBuilder( + column: $table.createdAt, + builder: (column) => ColumnFilters(column), + ); + + Expression gameTableRefs( + Expression Function($$GameTableTableFilterComposer f) f, + ) { + final $$GameTableTableFilterComposer composer = $composerBuilder( + composer: this, + getCurrentColumn: (t) => t.id, + referencedTable: $db.gameTable, + getReferencedColumn: (t) => t.winnerId, + builder: + ( + joinBuilder, { + $addJoinBuilderToRootComposer, + $removeJoinBuilderFromRootComposer, + }) => $$GameTableTableFilterComposer( + $db: $db, + $table: $db.gameTable, + $addJoinBuilderToRootComposer: $addJoinBuilderToRootComposer, + joinBuilder: joinBuilder, + $removeJoinBuilderFromRootComposer: + $removeJoinBuilderFromRootComposer, + ), + ); + return f(composer); + } + Expression playerGroupTableRefs( Expression Function($$PlayerGroupTableTableFilterComposer f) f, ) { @@ -935,7 +1730,7 @@ class $$PlayerTableTableFilterComposer composer: this, getCurrentColumn: (t) => t.id, referencedTable: $db.playerGroupTable, - getReferencedColumn: (t) => t.userId, + getReferencedColumn: (t) => t.playerId, builder: ( joinBuilder, { @@ -952,6 +1747,31 @@ class $$PlayerTableTableFilterComposer ); return f(composer); } + + Expression playerGameTableRefs( + Expression Function($$PlayerGameTableTableFilterComposer f) f, + ) { + final $$PlayerGameTableTableFilterComposer composer = $composerBuilder( + composer: this, + getCurrentColumn: (t) => t.id, + referencedTable: $db.playerGameTable, + getReferencedColumn: (t) => t.playerId, + builder: + ( + joinBuilder, { + $addJoinBuilderToRootComposer, + $removeJoinBuilderFromRootComposer, + }) => $$PlayerGameTableTableFilterComposer( + $db: $db, + $table: $db.playerGameTable, + $addJoinBuilderToRootComposer: $addJoinBuilderToRootComposer, + joinBuilder: joinBuilder, + $removeJoinBuilderFromRootComposer: + $removeJoinBuilderFromRootComposer, + ), + ); + return f(composer); + } } class $$PlayerTableTableOrderingComposer @@ -972,6 +1792,11 @@ class $$PlayerTableTableOrderingComposer column: $table.name, builder: (column) => ColumnOrderings(column), ); + + ColumnOrderings get createdAt => $composableBuilder( + column: $table.createdAt, + builder: (column) => ColumnOrderings(column), + ); } class $$PlayerTableTableAnnotationComposer @@ -989,6 +1814,34 @@ class $$PlayerTableTableAnnotationComposer GeneratedColumn get name => $composableBuilder(column: $table.name, builder: (column) => column); + GeneratedColumn get createdAt => + $composableBuilder(column: $table.createdAt, builder: (column) => column); + + Expression gameTableRefs( + Expression Function($$GameTableTableAnnotationComposer a) f, + ) { + final $$GameTableTableAnnotationComposer composer = $composerBuilder( + composer: this, + getCurrentColumn: (t) => t.id, + referencedTable: $db.gameTable, + getReferencedColumn: (t) => t.winnerId, + builder: + ( + joinBuilder, { + $addJoinBuilderToRootComposer, + $removeJoinBuilderFromRootComposer, + }) => $$GameTableTableAnnotationComposer( + $db: $db, + $table: $db.gameTable, + $addJoinBuilderToRootComposer: $addJoinBuilderToRootComposer, + joinBuilder: joinBuilder, + $removeJoinBuilderFromRootComposer: + $removeJoinBuilderFromRootComposer, + ), + ); + return f(composer); + } + Expression playerGroupTableRefs( Expression Function($$PlayerGroupTableTableAnnotationComposer a) f, ) { @@ -996,7 +1849,7 @@ class $$PlayerTableTableAnnotationComposer composer: this, getCurrentColumn: (t) => t.id, referencedTable: $db.playerGroupTable, - getReferencedColumn: (t) => t.userId, + getReferencedColumn: (t) => t.playerId, builder: ( joinBuilder, { @@ -1013,6 +1866,31 @@ class $$PlayerTableTableAnnotationComposer ); return f(composer); } + + Expression playerGameTableRefs( + Expression Function($$PlayerGameTableTableAnnotationComposer a) f, + ) { + final $$PlayerGameTableTableAnnotationComposer composer = $composerBuilder( + composer: this, + getCurrentColumn: (t) => t.id, + referencedTable: $db.playerGameTable, + getReferencedColumn: (t) => t.playerId, + builder: + ( + joinBuilder, { + $addJoinBuilderToRootComposer, + $removeJoinBuilderFromRootComposer, + }) => $$PlayerGameTableTableAnnotationComposer( + $db: $db, + $table: $db.playerGameTable, + $addJoinBuilderToRootComposer: $addJoinBuilderToRootComposer, + joinBuilder: joinBuilder, + $removeJoinBuilderFromRootComposer: + $removeJoinBuilderFromRootComposer, + ), + ); + return f(composer); + } } class $$PlayerTableTableTableManager @@ -1028,7 +1906,11 @@ class $$PlayerTableTableTableManager $$PlayerTableTableUpdateCompanionBuilder, (PlayerTableData, $$PlayerTableTableReferences), PlayerTableData, - PrefetchHooks Function({bool playerGroupTableRefs}) + PrefetchHooks Function({ + bool gameTableRefs, + bool playerGroupTableRefs, + bool playerGameTableRefs, + }) > { $$PlayerTableTableTableManager(_$AppDatabase db, $PlayerTableTable table) : super( @@ -1045,15 +1927,26 @@ class $$PlayerTableTableTableManager ({ Value id = const Value.absent(), Value name = const Value.absent(), + Value createdAt = const Value.absent(), Value rowid = const Value.absent(), - }) => PlayerTableCompanion(id: id, name: name, rowid: rowid), + }) => PlayerTableCompanion( + id: id, + name: name, + createdAt: createdAt, + rowid: rowid, + ), createCompanionCallback: ({ required String id, required String name, + required DateTime createdAt, Value rowid = const Value.absent(), - }) => - PlayerTableCompanion.insert(id: id, name: name, rowid: rowid), + }) => PlayerTableCompanion.insert( + id: id, + name: name, + createdAt: createdAt, + rowid: rowid, + ), withReferenceMapper: (p0) => p0 .map( (e) => ( @@ -1062,38 +1955,89 @@ class $$PlayerTableTableTableManager ), ) .toList(), - prefetchHooksCallback: ({playerGroupTableRefs = false}) { - return PrefetchHooks( - db: db, - explicitlyWatchedTables: [ - if (playerGroupTableRefs) db.playerGroupTable, - ], - addJoins: null, - getPrefetchedDataCallback: (items) async { - return [ - if (playerGroupTableRefs) - await $_getPrefetchedData< - PlayerTableData, - $PlayerTableTable, - PlayerGroupTableData - >( - currentTable: table, - referencedTable: $$PlayerTableTableReferences - ._playerGroupTableRefsTable(db), - managerFromTypedResult: (p0) => - $$PlayerTableTableReferences( - db, - table, - p0, - ).playerGroupTableRefs, - referencedItemsForCurrentItem: (item, referencedItems) => - referencedItems.where((e) => e.userId == item.id), - typedResults: items, - ), - ]; + prefetchHooksCallback: + ({ + gameTableRefs = false, + playerGroupTableRefs = false, + playerGameTableRefs = false, + }) { + return PrefetchHooks( + db: db, + explicitlyWatchedTables: [ + if (gameTableRefs) db.gameTable, + if (playerGroupTableRefs) db.playerGroupTable, + if (playerGameTableRefs) db.playerGameTable, + ], + addJoins: null, + getPrefetchedDataCallback: (items) async { + return [ + if (gameTableRefs) + await $_getPrefetchedData< + PlayerTableData, + $PlayerTableTable, + GameTableData + >( + currentTable: table, + referencedTable: $$PlayerTableTableReferences + ._gameTableRefsTable(db), + managerFromTypedResult: (p0) => + $$PlayerTableTableReferences( + db, + table, + p0, + ).gameTableRefs, + referencedItemsForCurrentItem: + (item, referencedItems) => referencedItems.where( + (e) => e.winnerId == item.id, + ), + typedResults: items, + ), + if (playerGroupTableRefs) + await $_getPrefetchedData< + PlayerTableData, + $PlayerTableTable, + PlayerGroupTableData + >( + currentTable: table, + referencedTable: $$PlayerTableTableReferences + ._playerGroupTableRefsTable(db), + managerFromTypedResult: (p0) => + $$PlayerTableTableReferences( + db, + table, + p0, + ).playerGroupTableRefs, + referencedItemsForCurrentItem: + (item, referencedItems) => referencedItems.where( + (e) => e.playerId == item.id, + ), + typedResults: items, + ), + if (playerGameTableRefs) + await $_getPrefetchedData< + PlayerTableData, + $PlayerTableTable, + PlayerGameTableData + >( + currentTable: table, + referencedTable: $$PlayerTableTableReferences + ._playerGameTableRefsTable(db), + managerFromTypedResult: (p0) => + $$PlayerTableTableReferences( + db, + table, + p0, + ).playerGameTableRefs, + referencedItemsForCurrentItem: + (item, referencedItems) => referencedItems.where( + (e) => e.playerId == item.id, + ), + typedResults: items, + ), + ]; + }, + ); }, - ); - }, ), ); } @@ -1110,18 +2054,24 @@ typedef $$PlayerTableTableProcessedTableManager = $$PlayerTableTableUpdateCompanionBuilder, (PlayerTableData, $$PlayerTableTableReferences), PlayerTableData, - PrefetchHooks Function({bool playerGroupTableRefs}) + PrefetchHooks Function({ + bool gameTableRefs, + bool playerGroupTableRefs, + bool playerGameTableRefs, + }) >; typedef $$GroupTableTableCreateCompanionBuilder = GroupTableCompanion Function({ required String id, required String name, + required DateTime createdAt, Value rowid, }); typedef $$GroupTableTableUpdateCompanionBuilder = GroupTableCompanion Function({ Value id, Value name, + Value createdAt, Value rowid, }); @@ -1151,6 +2101,27 @@ final class $$GroupTableTableReferences manager.$state.copyWith(prefetchedData: cache), ); } + + static MultiTypedResultKey<$GroupGameTableTable, List> + _groupGameTableRefsTable(_$AppDatabase db) => MultiTypedResultKey.fromTable( + db.groupGameTable, + aliasName: $_aliasNameGenerator( + db.groupTable.id, + db.groupGameTable.groupId, + ), + ); + + $$GroupGameTableTableProcessedTableManager get groupGameTableRefs { + final manager = $$GroupGameTableTableTableManager( + $_db, + $_db.groupGameTable, + ).filter((f) => f.groupId.id.sqlEquals($_itemColumn('id')!)); + + final cache = $_typedResult.readTableOrNull(_groupGameTableRefsTable($_db)); + return ProcessedTableManager( + manager.$state.copyWith(prefetchedData: cache), + ); + } } class $$GroupTableTableFilterComposer @@ -1172,6 +2143,11 @@ class $$GroupTableTableFilterComposer builder: (column) => ColumnFilters(column), ); + ColumnFilters get createdAt => $composableBuilder( + column: $table.createdAt, + builder: (column) => ColumnFilters(column), + ); + Expression playerGroupTableRefs( Expression Function($$PlayerGroupTableTableFilterComposer f) f, ) { @@ -1196,6 +2172,31 @@ class $$GroupTableTableFilterComposer ); return f(composer); } + + Expression groupGameTableRefs( + Expression Function($$GroupGameTableTableFilterComposer f) f, + ) { + final $$GroupGameTableTableFilterComposer composer = $composerBuilder( + composer: this, + getCurrentColumn: (t) => t.id, + referencedTable: $db.groupGameTable, + getReferencedColumn: (t) => t.groupId, + builder: + ( + joinBuilder, { + $addJoinBuilderToRootComposer, + $removeJoinBuilderFromRootComposer, + }) => $$GroupGameTableTableFilterComposer( + $db: $db, + $table: $db.groupGameTable, + $addJoinBuilderToRootComposer: $addJoinBuilderToRootComposer, + joinBuilder: joinBuilder, + $removeJoinBuilderFromRootComposer: + $removeJoinBuilderFromRootComposer, + ), + ); + return f(composer); + } } class $$GroupTableTableOrderingComposer @@ -1216,6 +2217,11 @@ class $$GroupTableTableOrderingComposer column: $table.name, builder: (column) => ColumnOrderings(column), ); + + ColumnOrderings get createdAt => $composableBuilder( + column: $table.createdAt, + builder: (column) => ColumnOrderings(column), + ); } class $$GroupTableTableAnnotationComposer @@ -1233,6 +2239,9 @@ class $$GroupTableTableAnnotationComposer GeneratedColumn get name => $composableBuilder(column: $table.name, builder: (column) => column); + GeneratedColumn get createdAt => + $composableBuilder(column: $table.createdAt, builder: (column) => column); + Expression playerGroupTableRefs( Expression Function($$PlayerGroupTableTableAnnotationComposer a) f, ) { @@ -1257,6 +2266,31 @@ class $$GroupTableTableAnnotationComposer ); return f(composer); } + + Expression groupGameTableRefs( + Expression Function($$GroupGameTableTableAnnotationComposer a) f, + ) { + final $$GroupGameTableTableAnnotationComposer composer = $composerBuilder( + composer: this, + getCurrentColumn: (t) => t.id, + referencedTable: $db.groupGameTable, + getReferencedColumn: (t) => t.groupId, + builder: + ( + joinBuilder, { + $addJoinBuilderToRootComposer, + $removeJoinBuilderFromRootComposer, + }) => $$GroupGameTableTableAnnotationComposer( + $db: $db, + $table: $db.groupGameTable, + $addJoinBuilderToRootComposer: $addJoinBuilderToRootComposer, + joinBuilder: joinBuilder, + $removeJoinBuilderFromRootComposer: + $removeJoinBuilderFromRootComposer, + ), + ); + return f(composer); + } } class $$GroupTableTableTableManager @@ -1272,7 +2306,10 @@ class $$GroupTableTableTableManager $$GroupTableTableUpdateCompanionBuilder, (GroupTableData, $$GroupTableTableReferences), GroupTableData, - PrefetchHooks Function({bool playerGroupTableRefs}) + PrefetchHooks Function({ + bool playerGroupTableRefs, + bool groupGameTableRefs, + }) > { $$GroupTableTableTableManager(_$AppDatabase db, $GroupTableTable table) : super( @@ -1289,15 +2326,26 @@ class $$GroupTableTableTableManager ({ Value id = const Value.absent(), Value name = const Value.absent(), + Value createdAt = const Value.absent(), Value rowid = const Value.absent(), - }) => GroupTableCompanion(id: id, name: name, rowid: rowid), + }) => GroupTableCompanion( + id: id, + name: name, + createdAt: createdAt, + rowid: rowid, + ), createCompanionCallback: ({ required String id, required String name, + required DateTime createdAt, Value rowid = const Value.absent(), - }) => - GroupTableCompanion.insert(id: id, name: name, rowid: rowid), + }) => GroupTableCompanion.insert( + id: id, + name: name, + createdAt: createdAt, + rowid: rowid, + ), withReferenceMapper: (p0) => p0 .map( (e) => ( @@ -1306,38 +2354,63 @@ class $$GroupTableTableTableManager ), ) .toList(), - prefetchHooksCallback: ({playerGroupTableRefs = false}) { - return PrefetchHooks( - db: db, - explicitlyWatchedTables: [ - if (playerGroupTableRefs) db.playerGroupTable, - ], - addJoins: null, - getPrefetchedDataCallback: (items) async { - return [ - if (playerGroupTableRefs) - await $_getPrefetchedData< - GroupTableData, - $GroupTableTable, - PlayerGroupTableData - >( - currentTable: table, - referencedTable: $$GroupTableTableReferences - ._playerGroupTableRefsTable(db), - managerFromTypedResult: (p0) => - $$GroupTableTableReferences( - db, - table, - p0, - ).playerGroupTableRefs, - referencedItemsForCurrentItem: (item, referencedItems) => - referencedItems.where((e) => e.groupId == item.id), - typedResults: items, - ), - ]; + prefetchHooksCallback: + ({playerGroupTableRefs = false, groupGameTableRefs = false}) { + return PrefetchHooks( + db: db, + explicitlyWatchedTables: [ + if (playerGroupTableRefs) db.playerGroupTable, + if (groupGameTableRefs) db.groupGameTable, + ], + addJoins: null, + getPrefetchedDataCallback: (items) async { + return [ + if (playerGroupTableRefs) + await $_getPrefetchedData< + GroupTableData, + $GroupTableTable, + PlayerGroupTableData + >( + currentTable: table, + referencedTable: $$GroupTableTableReferences + ._playerGroupTableRefsTable(db), + managerFromTypedResult: (p0) => + $$GroupTableTableReferences( + db, + table, + p0, + ).playerGroupTableRefs, + referencedItemsForCurrentItem: + (item, referencedItems) => referencedItems.where( + (e) => e.groupId == item.id, + ), + typedResults: items, + ), + if (groupGameTableRefs) + await $_getPrefetchedData< + GroupTableData, + $GroupTableTable, + GroupGameTableData + >( + currentTable: table, + referencedTable: $$GroupTableTableReferences + ._groupGameTableRefsTable(db), + managerFromTypedResult: (p0) => + $$GroupTableTableReferences( + db, + table, + p0, + ).groupGameTableRefs, + referencedItemsForCurrentItem: + (item, referencedItems) => referencedItems.where( + (e) => e.groupId == item.id, + ), + typedResults: items, + ), + ]; + }, + ); }, - ); - }, ), ); } @@ -1354,17 +2427,517 @@ typedef $$GroupTableTableProcessedTableManager = $$GroupTableTableUpdateCompanionBuilder, (GroupTableData, $$GroupTableTableReferences), GroupTableData, - PrefetchHooks Function({bool playerGroupTableRefs}) + PrefetchHooks Function({ + bool playerGroupTableRefs, + bool groupGameTableRefs, + }) + >; +typedef $$GameTableTableCreateCompanionBuilder = + GameTableCompanion Function({ + required String id, + required String name, + required String winnerId, + required DateTime createdAt, + Value rowid, + }); +typedef $$GameTableTableUpdateCompanionBuilder = + GameTableCompanion Function({ + Value id, + Value name, + Value winnerId, + Value createdAt, + Value rowid, + }); + +final class $$GameTableTableReferences + extends BaseReferences<_$AppDatabase, $GameTableTable, GameTableData> { + $$GameTableTableReferences(super.$_db, super.$_table, super.$_typedResult); + + static $PlayerTableTable _winnerIdTable(_$AppDatabase db) => + db.playerTable.createAlias( + $_aliasNameGenerator(db.gameTable.winnerId, db.playerTable.id), + ); + + $$PlayerTableTableProcessedTableManager get winnerId { + final $_column = $_itemColumn('winner_id')!; + + final manager = $$PlayerTableTableTableManager( + $_db, + $_db.playerTable, + ).filter((f) => f.id.sqlEquals($_column)); + final item = $_typedResult.readTableOrNull(_winnerIdTable($_db)); + if (item == null) return manager; + return ProcessedTableManager( + manager.$state.copyWith(prefetchedData: [item]), + ); + } + + static MultiTypedResultKey<$PlayerGameTableTable, List> + _playerGameTableRefsTable(_$AppDatabase db) => MultiTypedResultKey.fromTable( + db.playerGameTable, + aliasName: $_aliasNameGenerator(db.gameTable.id, db.playerGameTable.gameId), + ); + + $$PlayerGameTableTableProcessedTableManager get playerGameTableRefs { + final manager = $$PlayerGameTableTableTableManager( + $_db, + $_db.playerGameTable, + ).filter((f) => f.gameId.id.sqlEquals($_itemColumn('id')!)); + + final cache = $_typedResult.readTableOrNull( + _playerGameTableRefsTable($_db), + ); + return ProcessedTableManager( + manager.$state.copyWith(prefetchedData: cache), + ); + } + + static MultiTypedResultKey<$GroupGameTableTable, List> + _groupGameTableRefsTable(_$AppDatabase db) => MultiTypedResultKey.fromTable( + db.groupGameTable, + aliasName: $_aliasNameGenerator(db.gameTable.id, db.groupGameTable.gameId), + ); + + $$GroupGameTableTableProcessedTableManager get groupGameTableRefs { + final manager = $$GroupGameTableTableTableManager( + $_db, + $_db.groupGameTable, + ).filter((f) => f.gameId.id.sqlEquals($_itemColumn('id')!)); + + final cache = $_typedResult.readTableOrNull(_groupGameTableRefsTable($_db)); + return ProcessedTableManager( + manager.$state.copyWith(prefetchedData: cache), + ); + } +} + +class $$GameTableTableFilterComposer + extends Composer<_$AppDatabase, $GameTableTable> { + $$GameTableTableFilterComposer({ + required super.$db, + required super.$table, + super.joinBuilder, + super.$addJoinBuilderToRootComposer, + super.$removeJoinBuilderFromRootComposer, + }); + ColumnFilters get id => $composableBuilder( + column: $table.id, + builder: (column) => ColumnFilters(column), + ); + + ColumnFilters get name => $composableBuilder( + column: $table.name, + builder: (column) => ColumnFilters(column), + ); + + ColumnFilters get createdAt => $composableBuilder( + column: $table.createdAt, + builder: (column) => ColumnFilters(column), + ); + + $$PlayerTableTableFilterComposer get winnerId { + final $$PlayerTableTableFilterComposer composer = $composerBuilder( + composer: this, + getCurrentColumn: (t) => t.winnerId, + referencedTable: $db.playerTable, + getReferencedColumn: (t) => t.id, + builder: + ( + joinBuilder, { + $addJoinBuilderToRootComposer, + $removeJoinBuilderFromRootComposer, + }) => $$PlayerTableTableFilterComposer( + $db: $db, + $table: $db.playerTable, + $addJoinBuilderToRootComposer: $addJoinBuilderToRootComposer, + joinBuilder: joinBuilder, + $removeJoinBuilderFromRootComposer: + $removeJoinBuilderFromRootComposer, + ), + ); + return composer; + } + + Expression playerGameTableRefs( + Expression Function($$PlayerGameTableTableFilterComposer f) f, + ) { + final $$PlayerGameTableTableFilterComposer composer = $composerBuilder( + composer: this, + getCurrentColumn: (t) => t.id, + referencedTable: $db.playerGameTable, + getReferencedColumn: (t) => t.gameId, + builder: + ( + joinBuilder, { + $addJoinBuilderToRootComposer, + $removeJoinBuilderFromRootComposer, + }) => $$PlayerGameTableTableFilterComposer( + $db: $db, + $table: $db.playerGameTable, + $addJoinBuilderToRootComposer: $addJoinBuilderToRootComposer, + joinBuilder: joinBuilder, + $removeJoinBuilderFromRootComposer: + $removeJoinBuilderFromRootComposer, + ), + ); + return f(composer); + } + + Expression groupGameTableRefs( + Expression Function($$GroupGameTableTableFilterComposer f) f, + ) { + final $$GroupGameTableTableFilterComposer composer = $composerBuilder( + composer: this, + getCurrentColumn: (t) => t.id, + referencedTable: $db.groupGameTable, + getReferencedColumn: (t) => t.gameId, + builder: + ( + joinBuilder, { + $addJoinBuilderToRootComposer, + $removeJoinBuilderFromRootComposer, + }) => $$GroupGameTableTableFilterComposer( + $db: $db, + $table: $db.groupGameTable, + $addJoinBuilderToRootComposer: $addJoinBuilderToRootComposer, + joinBuilder: joinBuilder, + $removeJoinBuilderFromRootComposer: + $removeJoinBuilderFromRootComposer, + ), + ); + return f(composer); + } +} + +class $$GameTableTableOrderingComposer + extends Composer<_$AppDatabase, $GameTableTable> { + $$GameTableTableOrderingComposer({ + required super.$db, + required super.$table, + super.joinBuilder, + super.$addJoinBuilderToRootComposer, + super.$removeJoinBuilderFromRootComposer, + }); + ColumnOrderings get id => $composableBuilder( + column: $table.id, + builder: (column) => ColumnOrderings(column), + ); + + ColumnOrderings get name => $composableBuilder( + column: $table.name, + builder: (column) => ColumnOrderings(column), + ); + + ColumnOrderings get createdAt => $composableBuilder( + column: $table.createdAt, + builder: (column) => ColumnOrderings(column), + ); + + $$PlayerTableTableOrderingComposer get winnerId { + final $$PlayerTableTableOrderingComposer composer = $composerBuilder( + composer: this, + getCurrentColumn: (t) => t.winnerId, + referencedTable: $db.playerTable, + getReferencedColumn: (t) => t.id, + builder: + ( + joinBuilder, { + $addJoinBuilderToRootComposer, + $removeJoinBuilderFromRootComposer, + }) => $$PlayerTableTableOrderingComposer( + $db: $db, + $table: $db.playerTable, + $addJoinBuilderToRootComposer: $addJoinBuilderToRootComposer, + joinBuilder: joinBuilder, + $removeJoinBuilderFromRootComposer: + $removeJoinBuilderFromRootComposer, + ), + ); + return composer; + } +} + +class $$GameTableTableAnnotationComposer + extends Composer<_$AppDatabase, $GameTableTable> { + $$GameTableTableAnnotationComposer({ + required super.$db, + required super.$table, + super.joinBuilder, + super.$addJoinBuilderToRootComposer, + super.$removeJoinBuilderFromRootComposer, + }); + GeneratedColumn get id => + $composableBuilder(column: $table.id, builder: (column) => column); + + GeneratedColumn get name => + $composableBuilder(column: $table.name, builder: (column) => column); + + GeneratedColumn get createdAt => + $composableBuilder(column: $table.createdAt, builder: (column) => column); + + $$PlayerTableTableAnnotationComposer get winnerId { + final $$PlayerTableTableAnnotationComposer composer = $composerBuilder( + composer: this, + getCurrentColumn: (t) => t.winnerId, + referencedTable: $db.playerTable, + getReferencedColumn: (t) => t.id, + builder: + ( + joinBuilder, { + $addJoinBuilderToRootComposer, + $removeJoinBuilderFromRootComposer, + }) => $$PlayerTableTableAnnotationComposer( + $db: $db, + $table: $db.playerTable, + $addJoinBuilderToRootComposer: $addJoinBuilderToRootComposer, + joinBuilder: joinBuilder, + $removeJoinBuilderFromRootComposer: + $removeJoinBuilderFromRootComposer, + ), + ); + return composer; + } + + Expression playerGameTableRefs( + Expression Function($$PlayerGameTableTableAnnotationComposer a) f, + ) { + final $$PlayerGameTableTableAnnotationComposer composer = $composerBuilder( + composer: this, + getCurrentColumn: (t) => t.id, + referencedTable: $db.playerGameTable, + getReferencedColumn: (t) => t.gameId, + builder: + ( + joinBuilder, { + $addJoinBuilderToRootComposer, + $removeJoinBuilderFromRootComposer, + }) => $$PlayerGameTableTableAnnotationComposer( + $db: $db, + $table: $db.playerGameTable, + $addJoinBuilderToRootComposer: $addJoinBuilderToRootComposer, + joinBuilder: joinBuilder, + $removeJoinBuilderFromRootComposer: + $removeJoinBuilderFromRootComposer, + ), + ); + return f(composer); + } + + Expression groupGameTableRefs( + Expression Function($$GroupGameTableTableAnnotationComposer a) f, + ) { + final $$GroupGameTableTableAnnotationComposer composer = $composerBuilder( + composer: this, + getCurrentColumn: (t) => t.id, + referencedTable: $db.groupGameTable, + getReferencedColumn: (t) => t.gameId, + builder: + ( + joinBuilder, { + $addJoinBuilderToRootComposer, + $removeJoinBuilderFromRootComposer, + }) => $$GroupGameTableTableAnnotationComposer( + $db: $db, + $table: $db.groupGameTable, + $addJoinBuilderToRootComposer: $addJoinBuilderToRootComposer, + joinBuilder: joinBuilder, + $removeJoinBuilderFromRootComposer: + $removeJoinBuilderFromRootComposer, + ), + ); + return f(composer); + } +} + +class $$GameTableTableTableManager + extends + RootTableManager< + _$AppDatabase, + $GameTableTable, + GameTableData, + $$GameTableTableFilterComposer, + $$GameTableTableOrderingComposer, + $$GameTableTableAnnotationComposer, + $$GameTableTableCreateCompanionBuilder, + $$GameTableTableUpdateCompanionBuilder, + (GameTableData, $$GameTableTableReferences), + GameTableData, + PrefetchHooks Function({ + bool winnerId, + bool playerGameTableRefs, + bool groupGameTableRefs, + }) + > { + $$GameTableTableTableManager(_$AppDatabase db, $GameTableTable table) + : super( + TableManagerState( + db: db, + table: table, + createFilteringComposer: () => + $$GameTableTableFilterComposer($db: db, $table: table), + createOrderingComposer: () => + $$GameTableTableOrderingComposer($db: db, $table: table), + createComputedFieldComposer: () => + $$GameTableTableAnnotationComposer($db: db, $table: table), + updateCompanionCallback: + ({ + Value id = const Value.absent(), + Value name = const Value.absent(), + Value winnerId = const Value.absent(), + Value createdAt = const Value.absent(), + Value rowid = const Value.absent(), + }) => GameTableCompanion( + id: id, + name: name, + winnerId: winnerId, + createdAt: createdAt, + rowid: rowid, + ), + createCompanionCallback: + ({ + required String id, + required String name, + required String winnerId, + required DateTime createdAt, + Value rowid = const Value.absent(), + }) => GameTableCompanion.insert( + id: id, + name: name, + winnerId: winnerId, + createdAt: createdAt, + rowid: rowid, + ), + withReferenceMapper: (p0) => p0 + .map( + (e) => ( + e.readTable(table), + $$GameTableTableReferences(db, table, e), + ), + ) + .toList(), + prefetchHooksCallback: + ({ + winnerId = false, + playerGameTableRefs = false, + groupGameTableRefs = false, + }) { + return PrefetchHooks( + db: db, + explicitlyWatchedTables: [ + if (playerGameTableRefs) db.playerGameTable, + if (groupGameTableRefs) db.groupGameTable, + ], + addJoins: + < + T extends TableManagerState< + dynamic, + dynamic, + dynamic, + dynamic, + dynamic, + dynamic, + dynamic, + dynamic, + dynamic, + dynamic, + dynamic + > + >(state) { + if (winnerId) { + state = + state.withJoin( + currentTable: table, + currentColumn: table.winnerId, + referencedTable: $$GameTableTableReferences + ._winnerIdTable(db), + referencedColumn: $$GameTableTableReferences + ._winnerIdTable(db) + .id, + ) + as T; + } + + return state; + }, + getPrefetchedDataCallback: (items) async { + return [ + if (playerGameTableRefs) + await $_getPrefetchedData< + GameTableData, + $GameTableTable, + PlayerGameTableData + >( + currentTable: table, + referencedTable: $$GameTableTableReferences + ._playerGameTableRefsTable(db), + managerFromTypedResult: (p0) => + $$GameTableTableReferences( + db, + table, + p0, + ).playerGameTableRefs, + referencedItemsForCurrentItem: + (item, referencedItems) => referencedItems.where( + (e) => e.gameId == item.id, + ), + typedResults: items, + ), + if (groupGameTableRefs) + await $_getPrefetchedData< + GameTableData, + $GameTableTable, + GroupGameTableData + >( + currentTable: table, + referencedTable: $$GameTableTableReferences + ._groupGameTableRefsTable(db), + managerFromTypedResult: (p0) => + $$GameTableTableReferences( + db, + table, + p0, + ).groupGameTableRefs, + referencedItemsForCurrentItem: + (item, referencedItems) => referencedItems.where( + (e) => e.gameId == item.id, + ), + typedResults: items, + ), + ]; + }, + ); + }, + ), + ); +} + +typedef $$GameTableTableProcessedTableManager = + ProcessedTableManager< + _$AppDatabase, + $GameTableTable, + GameTableData, + $$GameTableTableFilterComposer, + $$GameTableTableOrderingComposer, + $$GameTableTableAnnotationComposer, + $$GameTableTableCreateCompanionBuilder, + $$GameTableTableUpdateCompanionBuilder, + (GameTableData, $$GameTableTableReferences), + GameTableData, + PrefetchHooks Function({ + bool winnerId, + bool playerGameTableRefs, + bool groupGameTableRefs, + }) >; typedef $$PlayerGroupTableTableCreateCompanionBuilder = PlayerGroupTableCompanion Function({ - required String userId, + required String playerId, required String groupId, Value rowid, }); typedef $$PlayerGroupTableTableUpdateCompanionBuilder = PlayerGroupTableCompanion Function({ - Value userId, + Value playerId, Value groupId, Value rowid, }); @@ -1382,19 +2955,19 @@ final class $$PlayerGroupTableTableReferences super.$_typedResult, ); - static $PlayerTableTable _userIdTable(_$AppDatabase db) => + static $PlayerTableTable _playerIdTable(_$AppDatabase db) => db.playerTable.createAlias( - $_aliasNameGenerator(db.playerGroupTable.userId, db.playerTable.id), + $_aliasNameGenerator(db.playerGroupTable.playerId, db.playerTable.id), ); - $$PlayerTableTableProcessedTableManager get userId { - final $_column = $_itemColumn('user_id')!; + $$PlayerTableTableProcessedTableManager get playerId { + final $_column = $_itemColumn('player_id')!; final manager = $$PlayerTableTableTableManager( $_db, $_db.playerTable, ).filter((f) => f.id.sqlEquals($_column)); - final item = $_typedResult.readTableOrNull(_userIdTable($_db)); + final item = $_typedResult.readTableOrNull(_playerIdTable($_db)); if (item == null) return manager; return ProcessedTableManager( manager.$state.copyWith(prefetchedData: [item]), @@ -1430,10 +3003,10 @@ class $$PlayerGroupTableTableFilterComposer super.$addJoinBuilderToRootComposer, super.$removeJoinBuilderFromRootComposer, }); - $$PlayerTableTableFilterComposer get userId { + $$PlayerTableTableFilterComposer get playerId { final $$PlayerTableTableFilterComposer composer = $composerBuilder( composer: this, - getCurrentColumn: (t) => t.userId, + getCurrentColumn: (t) => t.playerId, referencedTable: $db.playerTable, getReferencedColumn: (t) => t.id, builder: @@ -1486,10 +3059,10 @@ class $$PlayerGroupTableTableOrderingComposer super.$addJoinBuilderToRootComposer, super.$removeJoinBuilderFromRootComposer, }); - $$PlayerTableTableOrderingComposer get userId { + $$PlayerTableTableOrderingComposer get playerId { final $$PlayerTableTableOrderingComposer composer = $composerBuilder( composer: this, - getCurrentColumn: (t) => t.userId, + getCurrentColumn: (t) => t.playerId, referencedTable: $db.playerTable, getReferencedColumn: (t) => t.id, builder: @@ -1542,10 +3115,10 @@ class $$PlayerGroupTableTableAnnotationComposer super.$addJoinBuilderToRootComposer, super.$removeJoinBuilderFromRootComposer, }); - $$PlayerTableTableAnnotationComposer get userId { + $$PlayerTableTableAnnotationComposer get playerId { final $$PlayerTableTableAnnotationComposer composer = $composerBuilder( composer: this, - getCurrentColumn: (t) => t.userId, + getCurrentColumn: (t) => t.playerId, referencedTable: $db.playerTable, getReferencedColumn: (t) => t.id, builder: @@ -1602,7 +3175,7 @@ class $$PlayerGroupTableTableTableManager $$PlayerGroupTableTableUpdateCompanionBuilder, (PlayerGroupTableData, $$PlayerGroupTableTableReferences), PlayerGroupTableData, - PrefetchHooks Function({bool userId, bool groupId}) + PrefetchHooks Function({bool playerId, bool groupId}) > { $$PlayerGroupTableTableTableManager( _$AppDatabase db, @@ -1619,21 +3192,21 @@ class $$PlayerGroupTableTableTableManager $$PlayerGroupTableTableAnnotationComposer($db: db, $table: table), updateCompanionCallback: ({ - Value userId = const Value.absent(), + Value playerId = const Value.absent(), Value groupId = const Value.absent(), Value rowid = const Value.absent(), }) => PlayerGroupTableCompanion( - userId: userId, + playerId: playerId, groupId: groupId, rowid: rowid, ), createCompanionCallback: ({ - required String userId, + required String playerId, required String groupId, Value rowid = const Value.absent(), }) => PlayerGroupTableCompanion.insert( - userId: userId, + playerId: playerId, groupId: groupId, rowid: rowid, ), @@ -1645,7 +3218,7 @@ class $$PlayerGroupTableTableTableManager ), ) .toList(), - prefetchHooksCallback: ({userId = false, groupId = false}) { + prefetchHooksCallback: ({playerId = false, groupId = false}) { return PrefetchHooks( db: db, explicitlyWatchedTables: [], @@ -1665,17 +3238,17 @@ class $$PlayerGroupTableTableTableManager dynamic > >(state) { - if (userId) { + if (playerId) { state = state.withJoin( currentTable: table, - currentColumn: table.userId, + currentColumn: table.playerId, referencedTable: $$PlayerGroupTableTableReferences - ._userIdTable(db), + ._playerIdTable(db), referencedColumn: $$PlayerGroupTableTableReferences - ._userIdTable(db) + ._playerIdTable(db) .id, ) as T; @@ -1719,142 +3292,735 @@ typedef $$PlayerGroupTableTableProcessedTableManager = $$PlayerGroupTableTableUpdateCompanionBuilder, (PlayerGroupTableData, $$PlayerGroupTableTableReferences), PlayerGroupTableData, - PrefetchHooks Function({bool userId, bool groupId}) + PrefetchHooks Function({bool playerId, bool groupId}) >; -typedef $$GameTableTableCreateCompanionBuilder = - GameTableCompanion Function({ - required String id, - required String name, +typedef $$PlayerGameTableTableCreateCompanionBuilder = + PlayerGameTableCompanion Function({ + required String playerId, + required String gameId, Value rowid, }); -typedef $$GameTableTableUpdateCompanionBuilder = - GameTableCompanion Function({ - Value id, - Value name, +typedef $$PlayerGameTableTableUpdateCompanionBuilder = + PlayerGameTableCompanion Function({ + Value playerId, + Value gameId, Value rowid, }); -class $$GameTableTableFilterComposer - extends Composer<_$AppDatabase, $GameTableTable> { - $$GameTableTableFilterComposer({ +final class $$PlayerGameTableTableReferences + extends + BaseReferences< + _$AppDatabase, + $PlayerGameTableTable, + PlayerGameTableData + > { + $$PlayerGameTableTableReferences( + super.$_db, + super.$_table, + super.$_typedResult, + ); + + static $PlayerTableTable _playerIdTable(_$AppDatabase db) => + db.playerTable.createAlias( + $_aliasNameGenerator(db.playerGameTable.playerId, db.playerTable.id), + ); + + $$PlayerTableTableProcessedTableManager get playerId { + final $_column = $_itemColumn('player_id')!; + + final manager = $$PlayerTableTableTableManager( + $_db, + $_db.playerTable, + ).filter((f) => f.id.sqlEquals($_column)); + final item = $_typedResult.readTableOrNull(_playerIdTable($_db)); + if (item == null) return manager; + return ProcessedTableManager( + manager.$state.copyWith(prefetchedData: [item]), + ); + } + + static $GameTableTable _gameIdTable(_$AppDatabase db) => + db.gameTable.createAlias( + $_aliasNameGenerator(db.playerGameTable.gameId, db.gameTable.id), + ); + + $$GameTableTableProcessedTableManager get gameId { + final $_column = $_itemColumn('game_id')!; + + final manager = $$GameTableTableTableManager( + $_db, + $_db.gameTable, + ).filter((f) => f.id.sqlEquals($_column)); + final item = $_typedResult.readTableOrNull(_gameIdTable($_db)); + if (item == null) return manager; + return ProcessedTableManager( + manager.$state.copyWith(prefetchedData: [item]), + ); + } +} + +class $$PlayerGameTableTableFilterComposer + extends Composer<_$AppDatabase, $PlayerGameTableTable> { + $$PlayerGameTableTableFilterComposer({ required super.$db, required super.$table, super.joinBuilder, super.$addJoinBuilderToRootComposer, super.$removeJoinBuilderFromRootComposer, }); - ColumnFilters get id => $composableBuilder( - column: $table.id, - builder: (column) => ColumnFilters(column), - ); + $$PlayerTableTableFilterComposer get playerId { + final $$PlayerTableTableFilterComposer composer = $composerBuilder( + composer: this, + getCurrentColumn: (t) => t.playerId, + referencedTable: $db.playerTable, + getReferencedColumn: (t) => t.id, + builder: + ( + joinBuilder, { + $addJoinBuilderToRootComposer, + $removeJoinBuilderFromRootComposer, + }) => $$PlayerTableTableFilterComposer( + $db: $db, + $table: $db.playerTable, + $addJoinBuilderToRootComposer: $addJoinBuilderToRootComposer, + joinBuilder: joinBuilder, + $removeJoinBuilderFromRootComposer: + $removeJoinBuilderFromRootComposer, + ), + ); + return composer; + } - ColumnFilters get name => $composableBuilder( - column: $table.name, - builder: (column) => ColumnFilters(column), - ); + $$GameTableTableFilterComposer get gameId { + final $$GameTableTableFilterComposer composer = $composerBuilder( + composer: this, + getCurrentColumn: (t) => t.gameId, + referencedTable: $db.gameTable, + getReferencedColumn: (t) => t.id, + builder: + ( + joinBuilder, { + $addJoinBuilderToRootComposer, + $removeJoinBuilderFromRootComposer, + }) => $$GameTableTableFilterComposer( + $db: $db, + $table: $db.gameTable, + $addJoinBuilderToRootComposer: $addJoinBuilderToRootComposer, + joinBuilder: joinBuilder, + $removeJoinBuilderFromRootComposer: + $removeJoinBuilderFromRootComposer, + ), + ); + return composer; + } } -class $$GameTableTableOrderingComposer - extends Composer<_$AppDatabase, $GameTableTable> { - $$GameTableTableOrderingComposer({ +class $$PlayerGameTableTableOrderingComposer + extends Composer<_$AppDatabase, $PlayerGameTableTable> { + $$PlayerGameTableTableOrderingComposer({ required super.$db, required super.$table, super.joinBuilder, super.$addJoinBuilderToRootComposer, super.$removeJoinBuilderFromRootComposer, }); - ColumnOrderings get id => $composableBuilder( - column: $table.id, - builder: (column) => ColumnOrderings(column), - ); + $$PlayerTableTableOrderingComposer get playerId { + final $$PlayerTableTableOrderingComposer composer = $composerBuilder( + composer: this, + getCurrentColumn: (t) => t.playerId, + referencedTable: $db.playerTable, + getReferencedColumn: (t) => t.id, + builder: + ( + joinBuilder, { + $addJoinBuilderToRootComposer, + $removeJoinBuilderFromRootComposer, + }) => $$PlayerTableTableOrderingComposer( + $db: $db, + $table: $db.playerTable, + $addJoinBuilderToRootComposer: $addJoinBuilderToRootComposer, + joinBuilder: joinBuilder, + $removeJoinBuilderFromRootComposer: + $removeJoinBuilderFromRootComposer, + ), + ); + return composer; + } - ColumnOrderings get name => $composableBuilder( - column: $table.name, - builder: (column) => ColumnOrderings(column), - ); + $$GameTableTableOrderingComposer get gameId { + final $$GameTableTableOrderingComposer composer = $composerBuilder( + composer: this, + getCurrentColumn: (t) => t.gameId, + referencedTable: $db.gameTable, + getReferencedColumn: (t) => t.id, + builder: + ( + joinBuilder, { + $addJoinBuilderToRootComposer, + $removeJoinBuilderFromRootComposer, + }) => $$GameTableTableOrderingComposer( + $db: $db, + $table: $db.gameTable, + $addJoinBuilderToRootComposer: $addJoinBuilderToRootComposer, + joinBuilder: joinBuilder, + $removeJoinBuilderFromRootComposer: + $removeJoinBuilderFromRootComposer, + ), + ); + return composer; + } } -class $$GameTableTableAnnotationComposer - extends Composer<_$AppDatabase, $GameTableTable> { - $$GameTableTableAnnotationComposer({ +class $$PlayerGameTableTableAnnotationComposer + extends Composer<_$AppDatabase, $PlayerGameTableTable> { + $$PlayerGameTableTableAnnotationComposer({ required super.$db, required super.$table, super.joinBuilder, super.$addJoinBuilderToRootComposer, super.$removeJoinBuilderFromRootComposer, }); - GeneratedColumn get id => - $composableBuilder(column: $table.id, builder: (column) => column); + $$PlayerTableTableAnnotationComposer get playerId { + final $$PlayerTableTableAnnotationComposer composer = $composerBuilder( + composer: this, + getCurrentColumn: (t) => t.playerId, + referencedTable: $db.playerTable, + getReferencedColumn: (t) => t.id, + builder: + ( + joinBuilder, { + $addJoinBuilderToRootComposer, + $removeJoinBuilderFromRootComposer, + }) => $$PlayerTableTableAnnotationComposer( + $db: $db, + $table: $db.playerTable, + $addJoinBuilderToRootComposer: $addJoinBuilderToRootComposer, + joinBuilder: joinBuilder, + $removeJoinBuilderFromRootComposer: + $removeJoinBuilderFromRootComposer, + ), + ); + return composer; + } - GeneratedColumn get name => - $composableBuilder(column: $table.name, builder: (column) => column); + $$GameTableTableAnnotationComposer get gameId { + final $$GameTableTableAnnotationComposer composer = $composerBuilder( + composer: this, + getCurrentColumn: (t) => t.gameId, + referencedTable: $db.gameTable, + getReferencedColumn: (t) => t.id, + builder: + ( + joinBuilder, { + $addJoinBuilderToRootComposer, + $removeJoinBuilderFromRootComposer, + }) => $$GameTableTableAnnotationComposer( + $db: $db, + $table: $db.gameTable, + $addJoinBuilderToRootComposer: $addJoinBuilderToRootComposer, + joinBuilder: joinBuilder, + $removeJoinBuilderFromRootComposer: + $removeJoinBuilderFromRootComposer, + ), + ); + return composer; + } } -class $$GameTableTableTableManager +class $$PlayerGameTableTableTableManager extends RootTableManager< _$AppDatabase, - $GameTableTable, - GameTableData, - $$GameTableTableFilterComposer, - $$GameTableTableOrderingComposer, - $$GameTableTableAnnotationComposer, - $$GameTableTableCreateCompanionBuilder, - $$GameTableTableUpdateCompanionBuilder, - ( - GameTableData, - BaseReferences<_$AppDatabase, $GameTableTable, GameTableData>, - ), - GameTableData, - PrefetchHooks Function() + $PlayerGameTableTable, + PlayerGameTableData, + $$PlayerGameTableTableFilterComposer, + $$PlayerGameTableTableOrderingComposer, + $$PlayerGameTableTableAnnotationComposer, + $$PlayerGameTableTableCreateCompanionBuilder, + $$PlayerGameTableTableUpdateCompanionBuilder, + (PlayerGameTableData, $$PlayerGameTableTableReferences), + PlayerGameTableData, + PrefetchHooks Function({bool playerId, bool gameId}) > { - $$GameTableTableTableManager(_$AppDatabase db, $GameTableTable table) - : super( + $$PlayerGameTableTableTableManager( + _$AppDatabase db, + $PlayerGameTableTable table, + ) : super( TableManagerState( db: db, table: table, createFilteringComposer: () => - $$GameTableTableFilterComposer($db: db, $table: table), + $$PlayerGameTableTableFilterComposer($db: db, $table: table), createOrderingComposer: () => - $$GameTableTableOrderingComposer($db: db, $table: table), + $$PlayerGameTableTableOrderingComposer($db: db, $table: table), createComputedFieldComposer: () => - $$GameTableTableAnnotationComposer($db: db, $table: table), + $$PlayerGameTableTableAnnotationComposer($db: db, $table: table), updateCompanionCallback: ({ - Value id = const Value.absent(), - Value name = const Value.absent(), + Value playerId = const Value.absent(), + Value gameId = const Value.absent(), Value rowid = const Value.absent(), - }) => GameTableCompanion(id: id, name: name, rowid: rowid), + }) => PlayerGameTableCompanion( + playerId: playerId, + gameId: gameId, + rowid: rowid, + ), createCompanionCallback: ({ - required String id, - required String name, + required String playerId, + required String gameId, Value rowid = const Value.absent(), - }) => GameTableCompanion.insert(id: id, name: name, rowid: rowid), + }) => PlayerGameTableCompanion.insert( + playerId: playerId, + gameId: gameId, + rowid: rowid, + ), withReferenceMapper: (p0) => p0 - .map((e) => (e.readTable(table), BaseReferences(db, table, e))) + .map( + (e) => ( + e.readTable(table), + $$PlayerGameTableTableReferences(db, table, e), + ), + ) .toList(), - prefetchHooksCallback: null, + prefetchHooksCallback: ({playerId = false, gameId = false}) { + return PrefetchHooks( + db: db, + explicitlyWatchedTables: [], + addJoins: + < + T extends TableManagerState< + dynamic, + dynamic, + dynamic, + dynamic, + dynamic, + dynamic, + dynamic, + dynamic, + dynamic, + dynamic, + dynamic + > + >(state) { + if (playerId) { + state = + state.withJoin( + currentTable: table, + currentColumn: table.playerId, + referencedTable: + $$PlayerGameTableTableReferences + ._playerIdTable(db), + referencedColumn: + $$PlayerGameTableTableReferences + ._playerIdTable(db) + .id, + ) + as T; + } + if (gameId) { + state = + state.withJoin( + currentTable: table, + currentColumn: table.gameId, + referencedTable: + $$PlayerGameTableTableReferences + ._gameIdTable(db), + referencedColumn: + $$PlayerGameTableTableReferences + ._gameIdTable(db) + .id, + ) + as T; + } + + return state; + }, + getPrefetchedDataCallback: (items) async { + return []; + }, + ); + }, ), ); } -typedef $$GameTableTableProcessedTableManager = +typedef $$PlayerGameTableTableProcessedTableManager = ProcessedTableManager< _$AppDatabase, - $GameTableTable, - GameTableData, - $$GameTableTableFilterComposer, - $$GameTableTableOrderingComposer, - $$GameTableTableAnnotationComposer, - $$GameTableTableCreateCompanionBuilder, - $$GameTableTableUpdateCompanionBuilder, - ( - GameTableData, - BaseReferences<_$AppDatabase, $GameTableTable, GameTableData>, - ), - GameTableData, - PrefetchHooks Function() + $PlayerGameTableTable, + PlayerGameTableData, + $$PlayerGameTableTableFilterComposer, + $$PlayerGameTableTableOrderingComposer, + $$PlayerGameTableTableAnnotationComposer, + $$PlayerGameTableTableCreateCompanionBuilder, + $$PlayerGameTableTableUpdateCompanionBuilder, + (PlayerGameTableData, $$PlayerGameTableTableReferences), + PlayerGameTableData, + PrefetchHooks Function({bool playerId, bool gameId}) + >; +typedef $$GroupGameTableTableCreateCompanionBuilder = + GroupGameTableCompanion Function({ + required String groupId, + required String gameId, + Value rowid, + }); +typedef $$GroupGameTableTableUpdateCompanionBuilder = + GroupGameTableCompanion Function({ + Value groupId, + Value gameId, + Value rowid, + }); + +final class $$GroupGameTableTableReferences + extends + BaseReferences< + _$AppDatabase, + $GroupGameTableTable, + GroupGameTableData + > { + $$GroupGameTableTableReferences( + super.$_db, + super.$_table, + super.$_typedResult, + ); + + static $GroupTableTable _groupIdTable(_$AppDatabase db) => + db.groupTable.createAlias( + $_aliasNameGenerator(db.groupGameTable.groupId, db.groupTable.id), + ); + + $$GroupTableTableProcessedTableManager get groupId { + final $_column = $_itemColumn('group_id')!; + + final manager = $$GroupTableTableTableManager( + $_db, + $_db.groupTable, + ).filter((f) => f.id.sqlEquals($_column)); + final item = $_typedResult.readTableOrNull(_groupIdTable($_db)); + if (item == null) return manager; + return ProcessedTableManager( + manager.$state.copyWith(prefetchedData: [item]), + ); + } + + static $GameTableTable _gameIdTable(_$AppDatabase db) => + db.gameTable.createAlias( + $_aliasNameGenerator(db.groupGameTable.gameId, db.gameTable.id), + ); + + $$GameTableTableProcessedTableManager get gameId { + final $_column = $_itemColumn('game_id')!; + + final manager = $$GameTableTableTableManager( + $_db, + $_db.gameTable, + ).filter((f) => f.id.sqlEquals($_column)); + final item = $_typedResult.readTableOrNull(_gameIdTable($_db)); + if (item == null) return manager; + return ProcessedTableManager( + manager.$state.copyWith(prefetchedData: [item]), + ); + } +} + +class $$GroupGameTableTableFilterComposer + extends Composer<_$AppDatabase, $GroupGameTableTable> { + $$GroupGameTableTableFilterComposer({ + required super.$db, + required super.$table, + super.joinBuilder, + super.$addJoinBuilderToRootComposer, + super.$removeJoinBuilderFromRootComposer, + }); + $$GroupTableTableFilterComposer get groupId { + final $$GroupTableTableFilterComposer composer = $composerBuilder( + composer: this, + getCurrentColumn: (t) => t.groupId, + referencedTable: $db.groupTable, + getReferencedColumn: (t) => t.id, + builder: + ( + joinBuilder, { + $addJoinBuilderToRootComposer, + $removeJoinBuilderFromRootComposer, + }) => $$GroupTableTableFilterComposer( + $db: $db, + $table: $db.groupTable, + $addJoinBuilderToRootComposer: $addJoinBuilderToRootComposer, + joinBuilder: joinBuilder, + $removeJoinBuilderFromRootComposer: + $removeJoinBuilderFromRootComposer, + ), + ); + return composer; + } + + $$GameTableTableFilterComposer get gameId { + final $$GameTableTableFilterComposer composer = $composerBuilder( + composer: this, + getCurrentColumn: (t) => t.gameId, + referencedTable: $db.gameTable, + getReferencedColumn: (t) => t.id, + builder: + ( + joinBuilder, { + $addJoinBuilderToRootComposer, + $removeJoinBuilderFromRootComposer, + }) => $$GameTableTableFilterComposer( + $db: $db, + $table: $db.gameTable, + $addJoinBuilderToRootComposer: $addJoinBuilderToRootComposer, + joinBuilder: joinBuilder, + $removeJoinBuilderFromRootComposer: + $removeJoinBuilderFromRootComposer, + ), + ); + return composer; + } +} + +class $$GroupGameTableTableOrderingComposer + extends Composer<_$AppDatabase, $GroupGameTableTable> { + $$GroupGameTableTableOrderingComposer({ + required super.$db, + required super.$table, + super.joinBuilder, + super.$addJoinBuilderToRootComposer, + super.$removeJoinBuilderFromRootComposer, + }); + $$GroupTableTableOrderingComposer get groupId { + final $$GroupTableTableOrderingComposer composer = $composerBuilder( + composer: this, + getCurrentColumn: (t) => t.groupId, + referencedTable: $db.groupTable, + getReferencedColumn: (t) => t.id, + builder: + ( + joinBuilder, { + $addJoinBuilderToRootComposer, + $removeJoinBuilderFromRootComposer, + }) => $$GroupTableTableOrderingComposer( + $db: $db, + $table: $db.groupTable, + $addJoinBuilderToRootComposer: $addJoinBuilderToRootComposer, + joinBuilder: joinBuilder, + $removeJoinBuilderFromRootComposer: + $removeJoinBuilderFromRootComposer, + ), + ); + return composer; + } + + $$GameTableTableOrderingComposer get gameId { + final $$GameTableTableOrderingComposer composer = $composerBuilder( + composer: this, + getCurrentColumn: (t) => t.gameId, + referencedTable: $db.gameTable, + getReferencedColumn: (t) => t.id, + builder: + ( + joinBuilder, { + $addJoinBuilderToRootComposer, + $removeJoinBuilderFromRootComposer, + }) => $$GameTableTableOrderingComposer( + $db: $db, + $table: $db.gameTable, + $addJoinBuilderToRootComposer: $addJoinBuilderToRootComposer, + joinBuilder: joinBuilder, + $removeJoinBuilderFromRootComposer: + $removeJoinBuilderFromRootComposer, + ), + ); + return composer; + } +} + +class $$GroupGameTableTableAnnotationComposer + extends Composer<_$AppDatabase, $GroupGameTableTable> { + $$GroupGameTableTableAnnotationComposer({ + required super.$db, + required super.$table, + super.joinBuilder, + super.$addJoinBuilderToRootComposer, + super.$removeJoinBuilderFromRootComposer, + }); + $$GroupTableTableAnnotationComposer get groupId { + final $$GroupTableTableAnnotationComposer composer = $composerBuilder( + composer: this, + getCurrentColumn: (t) => t.groupId, + referencedTable: $db.groupTable, + getReferencedColumn: (t) => t.id, + builder: + ( + joinBuilder, { + $addJoinBuilderToRootComposer, + $removeJoinBuilderFromRootComposer, + }) => $$GroupTableTableAnnotationComposer( + $db: $db, + $table: $db.groupTable, + $addJoinBuilderToRootComposer: $addJoinBuilderToRootComposer, + joinBuilder: joinBuilder, + $removeJoinBuilderFromRootComposer: + $removeJoinBuilderFromRootComposer, + ), + ); + return composer; + } + + $$GameTableTableAnnotationComposer get gameId { + final $$GameTableTableAnnotationComposer composer = $composerBuilder( + composer: this, + getCurrentColumn: (t) => t.gameId, + referencedTable: $db.gameTable, + getReferencedColumn: (t) => t.id, + builder: + ( + joinBuilder, { + $addJoinBuilderToRootComposer, + $removeJoinBuilderFromRootComposer, + }) => $$GameTableTableAnnotationComposer( + $db: $db, + $table: $db.gameTable, + $addJoinBuilderToRootComposer: $addJoinBuilderToRootComposer, + joinBuilder: joinBuilder, + $removeJoinBuilderFromRootComposer: + $removeJoinBuilderFromRootComposer, + ), + ); + return composer; + } +} + +class $$GroupGameTableTableTableManager + extends + RootTableManager< + _$AppDatabase, + $GroupGameTableTable, + GroupGameTableData, + $$GroupGameTableTableFilterComposer, + $$GroupGameTableTableOrderingComposer, + $$GroupGameTableTableAnnotationComposer, + $$GroupGameTableTableCreateCompanionBuilder, + $$GroupGameTableTableUpdateCompanionBuilder, + (GroupGameTableData, $$GroupGameTableTableReferences), + GroupGameTableData, + PrefetchHooks Function({bool groupId, bool gameId}) + > { + $$GroupGameTableTableTableManager( + _$AppDatabase db, + $GroupGameTableTable table, + ) : super( + TableManagerState( + db: db, + table: table, + createFilteringComposer: () => + $$GroupGameTableTableFilterComposer($db: db, $table: table), + createOrderingComposer: () => + $$GroupGameTableTableOrderingComposer($db: db, $table: table), + createComputedFieldComposer: () => + $$GroupGameTableTableAnnotationComposer($db: db, $table: table), + updateCompanionCallback: + ({ + Value groupId = const Value.absent(), + Value gameId = const Value.absent(), + Value rowid = const Value.absent(), + }) => GroupGameTableCompanion( + groupId: groupId, + gameId: gameId, + rowid: rowid, + ), + createCompanionCallback: + ({ + required String groupId, + required String gameId, + Value rowid = const Value.absent(), + }) => GroupGameTableCompanion.insert( + groupId: groupId, + gameId: gameId, + rowid: rowid, + ), + withReferenceMapper: (p0) => p0 + .map( + (e) => ( + e.readTable(table), + $$GroupGameTableTableReferences(db, table, e), + ), + ) + .toList(), + prefetchHooksCallback: ({groupId = false, gameId = false}) { + return PrefetchHooks( + db: db, + explicitlyWatchedTables: [], + addJoins: + < + T extends TableManagerState< + dynamic, + dynamic, + dynamic, + dynamic, + dynamic, + dynamic, + dynamic, + dynamic, + dynamic, + dynamic, + dynamic + > + >(state) { + if (groupId) { + state = + state.withJoin( + currentTable: table, + currentColumn: table.groupId, + referencedTable: $$GroupGameTableTableReferences + ._groupIdTable(db), + referencedColumn: + $$GroupGameTableTableReferences + ._groupIdTable(db) + .id, + ) + as T; + } + if (gameId) { + state = + state.withJoin( + currentTable: table, + currentColumn: table.gameId, + referencedTable: $$GroupGameTableTableReferences + ._gameIdTable(db), + referencedColumn: + $$GroupGameTableTableReferences + ._gameIdTable(db) + .id, + ) + as T; + } + + return state; + }, + getPrefetchedDataCallback: (items) async { + return []; + }, + ); + }, + ), + ); +} + +typedef $$GroupGameTableTableProcessedTableManager = + ProcessedTableManager< + _$AppDatabase, + $GroupGameTableTable, + GroupGameTableData, + $$GroupGameTableTableFilterComposer, + $$GroupGameTableTableOrderingComposer, + $$GroupGameTableTableAnnotationComposer, + $$GroupGameTableTableCreateCompanionBuilder, + $$GroupGameTableTableUpdateCompanionBuilder, + (GroupGameTableData, $$GroupGameTableTableReferences), + GroupGameTableData, + PrefetchHooks Function({bool groupId, bool gameId}) >; class $AppDatabaseManager { @@ -1864,8 +4030,12 @@ class $AppDatabaseManager { $$PlayerTableTableTableManager(_db, _db.playerTable); $$GroupTableTableTableManager get groupTable => $$GroupTableTableTableManager(_db, _db.groupTable); - $$PlayerGroupTableTableTableManager get playerGroupTable => - $$PlayerGroupTableTableTableManager(_db, _db.playerGroupTable); $$GameTableTableTableManager get gameTable => $$GameTableTableTableManager(_db, _db.gameTable); + $$PlayerGroupTableTableTableManager get playerGroupTable => + $$PlayerGroupTableTableTableManager(_db, _db.playerGroupTable); + $$PlayerGameTableTableTableManager get playerGameTable => + $$PlayerGameTableTableTableManager(_db, _db.playerGameTable); + $$GroupGameTableTableTableManager get groupGameTable => + $$GroupGameTableTableTableManager(_db, _db.groupGameTable); } diff --git a/lib/data/db/tables/game_table.dart b/lib/data/db/tables/game_table.dart index 45bfb20..0fe5a3c 100644 --- a/lib/data/db/tables/game_table.dart +++ b/lib/data/db/tables/game_table.dart @@ -1,8 +1,12 @@ import 'package:drift/drift.dart'; +import 'package:game_tracker/data/db/tables/player_table.dart'; class GameTable extends Table { TextColumn get id => text()(); TextColumn get name => text()(); + TextColumn get winnerId => + text().references(PlayerTable, #id, onDelete: KeyAction.cascade)(); + DateTimeColumn get createdAt => dateTime()(); @override Set> get primaryKey => {id}; diff --git a/lib/data/db/tables/group_game_table.dart b/lib/data/db/tables/group_game_table.dart new file mode 100644 index 0000000..a16672e --- /dev/null +++ b/lib/data/db/tables/group_game_table.dart @@ -0,0 +1,13 @@ +import 'package:drift/drift.dart'; +import 'package:game_tracker/data/db/tables/game_table.dart'; +import 'package:game_tracker/data/db/tables/group_table.dart'; + +class GroupGameTable extends Table { + TextColumn get groupId => + text().references(GroupTable, #id, onDelete: KeyAction.cascade)(); + TextColumn get gameId => + text().references(GameTable, #id, onDelete: KeyAction.cascade)(); + + @override + Set> get primaryKey => {groupId, gameId}; +} diff --git a/lib/data/db/tables/group_table.dart b/lib/data/db/tables/group_table.dart index dc9335d..5c52355 100644 --- a/lib/data/db/tables/group_table.dart +++ b/lib/data/db/tables/group_table.dart @@ -3,6 +3,7 @@ import 'package:drift/drift.dart'; class GroupTable extends Table { TextColumn get id => text()(); TextColumn get name => text()(); + DateTimeColumn get createdAt => dateTime()(); @override Set> get primaryKey => {id}; diff --git a/lib/data/db/tables/player_game_table.dart b/lib/data/db/tables/player_game_table.dart new file mode 100644 index 0000000..74c36fe --- /dev/null +++ b/lib/data/db/tables/player_game_table.dart @@ -0,0 +1,13 @@ +import 'package:drift/drift.dart'; +import 'package:game_tracker/data/db/tables/game_table.dart'; +import 'package:game_tracker/data/db/tables/player_table.dart'; + +class PlayerGameTable extends Table { + TextColumn get playerId => + text().references(PlayerTable, #id, onDelete: KeyAction.cascade)(); + TextColumn get gameId => + text().references(GameTable, #id, onDelete: KeyAction.cascade)(); + + @override + Set> get primaryKey => {playerId, gameId}; +} diff --git a/lib/data/db/tables/player_group_table.dart b/lib/data/db/tables/player_group_table.dart index 096a981..da2521b 100644 --- a/lib/data/db/tables/player_group_table.dart +++ b/lib/data/db/tables/player_group_table.dart @@ -3,9 +3,11 @@ import 'package:game_tracker/data/db/tables/group_table.dart'; import 'package:game_tracker/data/db/tables/player_table.dart'; class PlayerGroupTable extends Table { - TextColumn get userId => text().references(PlayerTable, #id)(); - TextColumn get groupId => text().references(GroupTable, #id)(); + TextColumn get playerId => + text().references(PlayerTable, #id, onDelete: KeyAction.cascade)(); + TextColumn get groupId => + text().references(GroupTable, #id, onDelete: KeyAction.cascade)(); @override - Set> get primaryKey => {userId, groupId}; + Set> get primaryKey => {playerId, groupId}; } diff --git a/lib/data/db/tables/player_table.dart b/lib/data/db/tables/player_table.dart index 3d97459..794958e 100644 --- a/lib/data/db/tables/player_table.dart +++ b/lib/data/db/tables/player_table.dart @@ -3,6 +3,7 @@ import 'package:drift/drift.dart'; class PlayerTable extends Table { TextColumn get id => text()(); TextColumn get name => text()(); + DateTimeColumn get createdAt => dateTime()(); @override Set> get primaryKey => {id}; diff --git a/lib/data/dto/game.dart b/lib/data/dto/game.dart index 7457b54..96e9d73 100644 --- a/lib/data/dto/game.dart +++ b/lib/data/dto/game.dart @@ -1,6 +1,28 @@ +import 'package:clock/clock.dart'; +import 'package:game_tracker/data/dto/group.dart'; +import 'package:game_tracker/data/dto/player.dart'; +import 'package:uuid/uuid.dart'; + class Game { final String id; final String name; + final List? players; + final Group? group; + final String winner; + final DateTime createdAt; - Game({required this.id, required this.name}); + Game({ + String? id, + DateTime? createdAt, + required this.name, + this.players, + this.group, + this.winner = '', + }) : id = id ?? const Uuid().v4(), + createdAt = createdAt ?? clock.now(); + + @override + String toString() { + return 'Game{\n\tid: $id,\n\tname: $name,\n\tplayers: $players,\n\tgroup: $group,\n\twinner: $winner\n}'; + } } diff --git a/lib/data/dto/group.dart b/lib/data/dto/group.dart index 6f12fe9..46c6f91 100644 --- a/lib/data/dto/group.dart +++ b/lib/data/dto/group.dart @@ -1,9 +1,23 @@ +import 'package:clock/clock.dart'; import 'package:game_tracker/data/dto/player.dart'; +import 'package:uuid/uuid.dart'; class Group { final String id; final String name; final List members; + final DateTime createdAt; - Group({required this.id, required this.name, required this.members}); + Group({ + String? id, + DateTime? createdAt, + required this.name, + required this.members, + }) : id = id ?? const Uuid().v4(), + createdAt = createdAt ?? clock.now(); + + @override + String toString() { + return 'Group{id: $id, name: $name,members: $members}'; + } } diff --git a/lib/data/dto/player.dart b/lib/data/dto/player.dart index d5e84e8..4ef58b1 100644 --- a/lib/data/dto/player.dart +++ b/lib/data/dto/player.dart @@ -1,6 +1,17 @@ +import 'package:clock/clock.dart'; +import 'package:uuid/uuid.dart'; + class Player { final String id; final String name; + final DateTime createdAt; - Player({required this.id, required this.name}); + Player({String? id, DateTime? createdAt, required this.name}) + : id = id ?? const Uuid().v4(), + createdAt = createdAt ?? clock.now(); + + @override + String toString() { + return 'Player{id: $id,name: $name}'; + } } diff --git a/lib/main.dart b/lib/main.dart index 22f94c7..98c40f8 100644 --- a/lib/main.dart +++ b/lib/main.dart @@ -8,14 +8,14 @@ void main() { runApp( Provider( create: (context) => AppDatabase(), - child: const MyApp(), + child: const GameTracker(), dispose: (context, db) => db.close(), ), ); } -class MyApp extends StatelessWidget { - const MyApp({super.key}); +class GameTracker extends StatelessWidget { + const GameTracker({super.key}); @override Widget build(BuildContext context) { diff --git a/lib/presentation/views/main_menu/create_group_view.dart b/lib/presentation/views/main_menu/create_group_view.dart new file mode 100644 index 0000000..db8890f --- /dev/null +++ b/lib/presentation/views/main_menu/create_group_view.dart @@ -0,0 +1,309 @@ +import 'package:flutter/material.dart' hide ButtonStyle; +import 'package:game_tracker/core/custom_theme.dart'; +import 'package:game_tracker/core/enums.dart'; +import 'package:game_tracker/data/db/database.dart'; +import 'package:game_tracker/data/dto/group.dart'; +import 'package:game_tracker/data/dto/player.dart'; +import 'package:game_tracker/presentation/widgets/buttons/custom_width_button.dart'; +import 'package:game_tracker/presentation/widgets/custom_search_bar.dart'; +import 'package:game_tracker/presentation/widgets/text_input_field.dart'; +import 'package:game_tracker/presentation/widgets/tiles/text_icon_list_tile.dart'; +import 'package:game_tracker/presentation/widgets/tiles/text_icon_tile.dart'; +import 'package:game_tracker/presentation/widgets/top_centered_message.dart'; +import 'package:provider/provider.dart'; +import 'package:skeletonizer/skeletonizer.dart'; + +class CreateGroupView extends StatefulWidget { + const CreateGroupView({super.key}); + + @override + State createState() => _CreateGroupViewState(); +} + +class _CreateGroupViewState extends State { + List selectedPlayers = []; + List suggestedPlayers = []; + List allPlayers = []; + late final AppDatabase db; + late Future> _allPlayersFuture; + late final List skeletonData = List.filled( + 7, + Player(name: 'Player 0'), + ); + final _groupNameController = TextEditingController(); + final _searchBarController = TextEditingController(); + + @override + void initState() { + super.initState(); + db = Provider.of(context, listen: false); + _allPlayersFuture = db.playerDao.getAllPlayers(); + _allPlayersFuture.then((loadedPlayers) { + setState(() { + loadedPlayers.sort((a, b) => a.name.compareTo(b.name)); + allPlayers = [...loadedPlayers]; + suggestedPlayers = [...loadedPlayers]; + }); + }); + } + + @override + Widget build(BuildContext context) { + return SafeArea( + child: Scaffold( + backgroundColor: CustomTheme.backgroundColor, + appBar: AppBar( + backgroundColor: CustomTheme.backgroundColor, + scrolledUnderElevation: 0, + title: const Text( + 'Create new group', + style: TextStyle(fontSize: 20, fontWeight: FontWeight.bold), + ), + centerTitle: true, + ), + body: Column( + mainAxisAlignment: MainAxisAlignment.start, + children: [ + Container( + margin: const EdgeInsets.symmetric(horizontal: 12, vertical: 10), + child: TextInputField( + controller: _groupNameController, + hintText: 'Group name', + onChanged: (value) { + setState(() {}); + }, + ), + ), + Expanded( + child: Container( + margin: const EdgeInsets.symmetric( + horizontal: 12, + vertical: 10, + ), + padding: const EdgeInsets.symmetric( + vertical: 10, + horizontal: 10, + ), + decoration: BoxDecoration( + color: CustomTheme.boxColor, + border: Border.all(color: CustomTheme.boxBorder), + borderRadius: BorderRadius.circular(12), + ), + child: Column( + crossAxisAlignment: CrossAxisAlignment.start, + children: [ + CustomSearchBar( + controller: _searchBarController, + constraints: const BoxConstraints( + maxHeight: 45, + minHeight: 45, + ), + hintText: 'Search for players', + onChanged: (value) { + setState(() { + if (value.isEmpty) { + suggestedPlayers = allPlayers.where((player) { + return !selectedPlayers.contains(player); + }).toList(); + } else { + suggestedPlayers = allPlayers.where((player) { + final bool nameMatches = player.name + .toLowerCase() + .contains(value.toLowerCase()); + final bool isNotSelected = !selectedPlayers + .contains(player); + return nameMatches && isNotSelected; + }).toList(); + } + }); + }, + ), + const SizedBox(height: 10), + Text( + 'Ausgewählte Spieler: (${selectedPlayers.length})', + style: const TextStyle( + fontSize: 16, + fontWeight: FontWeight.bold, + ), + ), + const SizedBox(height: 10), + Wrap( + alignment: WrapAlignment.start, + crossAxisAlignment: WrapCrossAlignment.start, + spacing: 8.0, + runSpacing: 8.0, + children: [ + for (var player in selectedPlayers) + TextIconTile( + text: player.name, + onIconTap: () { + setState(() { + final currentSearch = _searchBarController.text + .toLowerCase(); + selectedPlayers.remove(player); + if (currentSearch.isEmpty || + player.name.toLowerCase().contains( + currentSearch, + )) { + suggestedPlayers.add(player); + suggestedPlayers.sort( + (a, b) => a.name.compareTo(b.name), + ); + } + }); + }, + ), + ], + ), + const SizedBox(height: 10), + const Text( + 'Alle Spieler:', + style: TextStyle( + fontSize: 16, + fontWeight: FontWeight.bold, + ), + ), + const SizedBox(height: 10), + FutureBuilder( + future: _allPlayersFuture, + builder: + ( + BuildContext context, + AsyncSnapshot> snapshot, + ) { + if (snapshot.hasError) { + return const Center( + child: TopCenteredMessage( + icon: Icons.report, + title: 'Error', + message: 'Player data couldn\'t\nbe loaded.', + ), + ); + } + if (snapshot.connectionState == + ConnectionState.done && + (!snapshot.hasData || + snapshot.data!.isEmpty || + (selectedPlayers.isEmpty && + allPlayers.isEmpty))) { + return const Center( + child: TopCenteredMessage( + icon: Icons.info, + title: 'Info', + message: 'No players created yet.', + ), + ); + } + final bool isLoading = + snapshot.connectionState == + ConnectionState.waiting; + return Expanded( + child: Skeletonizer( + effect: PulseEffect( + from: Colors.grey[800]!, + to: Colors.grey[600]!, + duration: const Duration(milliseconds: 800), + ), + enabled: isLoading, + enableSwitchAnimation: true, + switchAnimationConfig: + const SwitchAnimationConfig( + duration: Duration(milliseconds: 200), + switchInCurve: Curves.linear, + switchOutCurve: Curves.linear, + transitionBuilder: AnimatedSwitcher + .defaultTransitionBuilder, + layoutBuilder: + AnimatedSwitcher.defaultLayoutBuilder, + ), + child: + (suggestedPlayers.isEmpty && + allPlayers.isNotEmpty) + ? TopCenteredMessage( + icon: Icons.info, + title: 'Info', + message: + (selectedPlayers.length == + allPlayers.length) + ? 'No more players to add.' + : 'No players found with that name.', + ) + : ListView.builder( + itemCount: suggestedPlayers.length, + itemBuilder: + (BuildContext context, int index) { + return TextIconListTile( + text: suggestedPlayers[index] + .name, + onPressed: () { + setState(() { + if (!selectedPlayers.contains( + suggestedPlayers[index], + )) { + selectedPlayers.add( + suggestedPlayers[index], + ); + selectedPlayers.sort( + (a, b) => a.name + .compareTo(b.name), + ); + suggestedPlayers.remove( + suggestedPlayers[index], + ); + } + }); + }, + ); + }, + ), + ), + ); + }, + ), + ], + ), + ), + ), + CustomWidthButton( + text: 'Create group', + sizeRelativeToWidth: 0.95, + buttonType: ButtonType.primary, + onPressed: + (_groupNameController.text.isEmpty || selectedPlayers.isEmpty) + ? null + : () async { + bool success = await db.groupDao.addGroup( + group: Group( + name: _groupNameController.text, + members: selectedPlayers, + ), + ); + if (!context.mounted) return; + if (success) { + _groupNameController.clear(); + _searchBarController.clear(); + selectedPlayers.clear(); + Navigator.pop(context); + } else { + ScaffoldMessenger.of(context).showSnackBar( + SnackBar( + backgroundColor: CustomTheme.boxColor, + content: const Center( + child: Text( + 'Error while creating group, please try again', + style: TextStyle(color: Colors.white), + ), + ), + ), + ); + } + setState(() {}); + }, + ), + const SizedBox(height: 20), + ], + ), + ), + ); + } +} diff --git a/lib/presentation/views/main_menu/game_history_view.dart b/lib/presentation/views/main_menu/game_history_view.dart index de75ae6..a962c05 100644 --- a/lib/presentation/views/main_menu/game_history_view.dart +++ b/lib/presentation/views/main_menu/game_history_view.dart @@ -1,7 +1,7 @@ import 'package:flutter/material.dart'; import 'package:game_tracker/core/custom_theme.dart'; +import 'package:game_tracker/presentation/widgets/tiles/double_row_info_tile.dart'; import 'package:game_tracker/presentation/widgets/top_centered_message.dart'; -import 'package:game_tracker/presentation/widgets/double_row_info_tile.dart'; class GameHistoryView extends StatefulWidget { const GameHistoryView({super.key}); @@ -134,16 +134,16 @@ class _GameHistoryViewState extends State { children: [ Column( children: [ - Container(margin: EdgeInsets.only(bottom: 75)), + Container(margin: const EdgeInsets.only(bottom: 75)), Expanded( child: gameHistoryListView(allGameData, suggestedGameData), ), ], ), Container( - margin: EdgeInsets.only(top: 10, bottom: 10, left: 10, right: 10), + margin: const EdgeInsets.only(top: 10, bottom: 10, left: 10, right: 10), child: SearchBar( - leading: Icon(Icons.search), + leading: const Icon(Icons.search), onChanged: (value) { if (value.isEmpty) { setState(() { @@ -178,18 +178,26 @@ class _GameHistoryViewState extends State { Widget gameHistoryListView(allGameData, suggestedGameData) { if (suggestedGameData.isEmpty && allGameData.isEmpty) { - return TopCenteredMessage("Keine Spiele erstellt"); + return const TopCenteredMessage( + icon: Icons.info, + title: 'Info', + message: 'Keine Spiele erstellt', + ); } else if (suggestedGameData.isEmpty) { - return TopCenteredMessage("Kein Spiel mit den Suchparametern gefunden."); + return const TopCenteredMessage( + icon: Icons.search, + title: 'Info', + message: 'Kein Spiel mit den Suchparametern gefunden.', + ); } return ListView.builder( itemCount: suggestedGameData.length, itemBuilder: (context, index) { final currentGame = suggestedGameData[index]; return doubleRowInfoTile( - currentGame['game'] + ": ", + currentGame['game'] + ': ', currentGame['title'], - currentGame['players'].toString() + " Spieler", + "${currentGame['players']} Spieler", currentGame['group'], currentGame['date'], ); diff --git a/lib/presentation/views/main_menu/groups_view.dart b/lib/presentation/views/main_menu/groups_view.dart index 485d516..c45cf21 100644 --- a/lib/presentation/views/main_menu/groups_view.dart +++ b/lib/presentation/views/main_menu/groups_view.dart @@ -1,10 +1,129 @@ -import 'package:flutter/cupertino.dart'; +import 'package:flutter/material.dart'; +import 'package:game_tracker/core/custom_theme.dart'; +import 'package:game_tracker/data/db/database.dart'; +import 'package:game_tracker/data/dto/group.dart'; +import 'package:game_tracker/data/dto/player.dart'; +import 'package:game_tracker/presentation/views/main_menu/create_group_view.dart'; +import 'package:game_tracker/presentation/widgets/buttons/custom_width_button.dart'; +import 'package:game_tracker/presentation/widgets/tiles/group_tile.dart'; +import 'package:game_tracker/presentation/widgets/top_centered_message.dart'; +import 'package:provider/provider.dart'; +import 'package:skeletonizer/skeletonizer.dart'; -class GroupsView extends StatelessWidget { +class GroupsView extends StatefulWidget { const GroupsView({super.key}); + @override + State createState() => _GroupsViewState(); +} + +class _GroupsViewState extends State { + late Future> _allGroupsFuture; + late final AppDatabase db; + + final player = Player(name: 'Skeleton Player'); + late final List skeletonData = List.filled( + 7, + Group( + name: 'Skeleton Game', + members: [player, player, player, player, player, player], + ), + ); + + @override + void initState() { + super.initState(); + db = Provider.of(context, listen: false); + _allGroupsFuture = db.groupDao.getAllGroups(); + } + @override Widget build(BuildContext context) { - return const Center(child: Text('Groups View')); + return Scaffold( + backgroundColor: CustomTheme.backgroundColor, + body: Stack( + alignment: Alignment.center, + children: [ + FutureBuilder>( + future: _allGroupsFuture, + builder: + (BuildContext context, AsyncSnapshot> snapshot) { + if (snapshot.hasError) { + return const Center( + child: TopCenteredMessage( + icon: Icons.report, + title: 'Error', + message: 'Group data couldn\'t\nbe loaded.', + ), + ); + } + if (snapshot.connectionState == ConnectionState.done && + (!snapshot.hasData || snapshot.data!.isEmpty)) { + return const Center( + child: TopCenteredMessage( + icon: Icons.info, + title: 'Info', + message: 'No groups created yet.', + ), + ); + } + final bool isLoading = + snapshot.connectionState == ConnectionState.waiting; + final List groups = isLoading + ? skeletonData + : (snapshot.data ?? []); + return Skeletonizer( + effect: PulseEffect( + from: Colors.grey[800]!, + to: Colors.grey[600]!, + duration: const Duration(milliseconds: 800), + ), + enabled: isLoading, + enableSwitchAnimation: true, + switchAnimationConfig: const SwitchAnimationConfig( + duration: Duration(milliseconds: 200), + switchInCurve: Curves.linear, + switchOutCurve: Curves.linear, + transitionBuilder: + AnimatedSwitcher.defaultTransitionBuilder, + layoutBuilder: AnimatedSwitcher.defaultLayoutBuilder, + ), + child: ListView.builder( + padding: const EdgeInsets.only(bottom: 85), + itemCount: groups.length + 1, + itemBuilder: (BuildContext context, int index) { + if (index == groups.length) { + return const SizedBox(height: 60); + } + return GroupTile(group: groups[index]); + }, + ), + ); + }, + ), + + Positioned( + bottom: 80, + child: CustomWidthButton( + text: 'Create Group', + sizeRelativeToWidth: 0.90, + onPressed: () async { + await Navigator.push( + context, + MaterialPageRoute( + builder: (context) { + return const CreateGroupView(); + }, + ), + ); + setState(() { + _allGroupsFuture = db.groupDao.getAllGroups(); + }); + }, + ), + ), + ], + ), + ); } } diff --git a/lib/presentation/views/main_menu/home_view.dart b/lib/presentation/views/main_menu/home_view.dart index 141af77..34e4be3 100644 --- a/lib/presentation/views/main_menu/home_view.dart +++ b/lib/presentation/views/main_menu/home_view.dart @@ -1,10 +1,11 @@ import 'package:flutter/material.dart'; import 'package:game_tracker/data/db/database.dart'; -import 'package:game_tracker/presentation/widgets/game_tile.dart'; -import 'package:game_tracker/presentation/widgets/quick_create_button.dart'; +import 'package:game_tracker/presentation/widgets/buttons/quick_create_button.dart'; +import 'package:game_tracker/presentation/widgets/tiles/game_tile.dart'; import 'package:game_tracker/presentation/widgets/tiles/info_tile.dart'; import 'package:game_tracker/presentation/widgets/tiles/quick_info_tile.dart'; import 'package:provider/provider.dart'; +import 'package:skeletonizer/skeletonizer.dart'; class HomeView extends StatefulWidget { const HomeView({super.key}); @@ -16,6 +17,7 @@ class HomeView extends StatefulWidget { class _HomeViewState extends State { late Future _gameCountFuture; late Future _groupCountFuture; + bool isLoading = true; @override initState() { @@ -23,120 +25,165 @@ class _HomeViewState extends State { final db = Provider.of(context, listen: false); _gameCountFuture = db.gameDao.getGameCount(); _groupCountFuture = db.groupDao.getGroupCount(); + + Future.wait([_gameCountFuture, _groupCountFuture]).then((_) async { + await Future.delayed(const Duration(milliseconds: 50)); + if (mounted) { + setState(() { + isLoading = false; + }); + } + }); } @override Widget build(BuildContext context) { return LayoutBuilder( builder: (BuildContext context, BoxConstraints constraints) { - return SingleChildScrollView( - child: Column( - crossAxisAlignment: CrossAxisAlignment.center, - children: [ - Row( - mainAxisAlignment: MainAxisAlignment.center, - children: [ - FutureBuilder( - future: _gameCountFuture, - builder: (context, snapshot) { - final int count = (snapshot.hasData) ? snapshot.data! : 0; - return QuickInfoTile( - width: constraints.maxWidth * 0.45, - height: constraints.maxHeight * 0.15, - title: 'Games', - icon: Icons.groups_rounded, - value: count, - ); - }, - ), - SizedBox(width: constraints.maxWidth * 0.05), - FutureBuilder( - future: _groupCountFuture, - builder: (context, snapshot) { - final int count = - (snapshot.connectionState == ConnectionState.done && - snapshot.hasData) - ? snapshot.data! - : 0; - return QuickInfoTile( - width: constraints.maxWidth * 0.45, - height: constraints.maxHeight * 0.15, - title: 'Groups', - icon: Icons.groups_rounded, - value: count, - ); - }, - ), - ], - ), - Padding( - padding: const EdgeInsets.symmetric(vertical: 16.0), - child: InfoTile( - width: constraints.maxWidth * 0.95, - title: 'Recent Games', - icon: Icons.timer, - content: const Padding( - padding: EdgeInsets.symmetric(horizontal: 40.0), - child: Column( - mainAxisAlignment: MainAxisAlignment.start, - crossAxisAlignment: CrossAxisAlignment.start, - children: [ - GameTile( - gameTitle: 'Gamenight', - gameType: 'Cabo', - ruleset: 'Lowest Points', - players: '5 Players', - winner: 'Leonard', - ), - Padding( - padding: EdgeInsets.symmetric(vertical: 8.0), - child: Divider(), - ), - GameTile( - gameTitle: 'Schoolbreak', - gameType: 'Uno', - ruleset: 'Highest Points', - players: 'The Gang', - winner: 'Lina', - ), - SizedBox(height: 8), - ], - ), - ), - ), - ), - InfoTile( - width: constraints.maxWidth * 0.95, - title: 'Quick Create', - icon: Icons.add_box_rounded, - content: Column( - spacing: 8, + return Skeletonizer( + effect: PulseEffect( + from: Colors.grey[800]!, + to: Colors.grey[600]!, + duration: const Duration(milliseconds: 800), + ), + enabled: isLoading, + enableSwitchAnimation: true, + switchAnimationConfig: const SwitchAnimationConfig( + duration: Duration(milliseconds: 200), + switchInCurve: Curves.linear, + switchOutCurve: Curves.linear, + transitionBuilder: AnimatedSwitcher.defaultTransitionBuilder, + layoutBuilder: AnimatedSwitcher.defaultLayoutBuilder, + ), + child: SingleChildScrollView( + child: Column( + crossAxisAlignment: CrossAxisAlignment.center, + children: [ + Row( + mainAxisAlignment: MainAxisAlignment.center, children: [ - Row( - mainAxisAlignment: MainAxisAlignment.spaceEvenly, - children: [ - QuickCreateButton(text: 'Category 1', onPressed: () {}), - QuickCreateButton(text: 'Category 2', onPressed: () {}), - ], + FutureBuilder( + future: _gameCountFuture, + builder: (context, snapshot) { + final int count = (snapshot.hasData) + ? snapshot.data! + : 0; + return QuickInfoTile( + width: constraints.maxWidth * 0.45, + height: constraints.maxHeight * 0.15, + title: 'Games', + icon: Icons.groups_rounded, + value: count, + ); + }, ), - Row( - mainAxisAlignment: MainAxisAlignment.spaceEvenly, - children: [ - QuickCreateButton(text: 'Category 3', onPressed: () {}), - QuickCreateButton(text: 'Category 4', onPressed: () {}), - ], - ), - Row( - mainAxisAlignment: MainAxisAlignment.spaceEvenly, - children: [ - QuickCreateButton(text: 'Category 5', onPressed: () {}), - QuickCreateButton(text: 'Category 6', onPressed: () {}), - ], + SizedBox(width: constraints.maxWidth * 0.05), + FutureBuilder( + future: _groupCountFuture, + builder: (context, snapshot) { + final int count = + (snapshot.connectionState == ConnectionState.done && + snapshot.hasData) + ? snapshot.data! + : 0; + return QuickInfoTile( + width: constraints.maxWidth * 0.45, + height: constraints.maxHeight * 0.15, + title: 'Groups', + icon: Icons.groups_rounded, + value: count, + ); + }, ), ], ), - ), - ], + Padding( + padding: const EdgeInsets.symmetric(vertical: 16.0), + child: InfoTile( + width: constraints.maxWidth * 0.95, + title: 'Recent Games', + icon: Icons.timer, + content: const Padding( + padding: EdgeInsets.symmetric(horizontal: 40.0), + child: Column( + mainAxisAlignment: MainAxisAlignment.start, + crossAxisAlignment: CrossAxisAlignment.start, + children: [ + GameTile( + gameTitle: 'Gamenight', + gameType: 'Cabo', + ruleset: 'Lowest Points', + players: '5 Players', + winner: 'Leonard', + ), + Padding( + padding: EdgeInsets.symmetric(vertical: 8.0), + child: Divider(), + ), + GameTile( + gameTitle: 'Schoolbreak', + gameType: 'Uno', + ruleset: 'Highest Points', + players: 'The Gang', + winner: 'Lina', + ), + SizedBox(height: 8), + ], + ), + ), + ), + ), + InfoTile( + width: constraints.maxWidth * 0.95, + title: 'Quick Create', + icon: Icons.add_box_rounded, + content: Column( + spacing: 8, + children: [ + Row( + mainAxisAlignment: MainAxisAlignment.spaceEvenly, + children: [ + QuickCreateButton( + text: 'Category 1', + onPressed: () {}, + ), + QuickCreateButton( + text: 'Category 2', + onPressed: () {}, + ), + ], + ), + Row( + mainAxisAlignment: MainAxisAlignment.spaceEvenly, + children: [ + QuickCreateButton( + text: 'Category 3', + onPressed: () {}, + ), + QuickCreateButton( + text: 'Category 4', + onPressed: () {}, + ), + ], + ), + Row( + mainAxisAlignment: MainAxisAlignment.spaceEvenly, + children: [ + QuickCreateButton( + text: 'Category 5', + onPressed: () {}, + ), + QuickCreateButton( + text: 'Category 6', + onPressed: () {}, + ), + ], + ), + ], + ), + ), + ], + ), ), ); }, diff --git a/lib/presentation/widgets/buttons/custom_width_button.dart b/lib/presentation/widgets/buttons/custom_width_button.dart new file mode 100644 index 0000000..17c9dc5 --- /dev/null +++ b/lib/presentation/widgets/buttons/custom_width_button.dart @@ -0,0 +1,120 @@ +import 'package:flutter/material.dart'; +import 'package:game_tracker/core/custom_theme.dart'; +import 'package:game_tracker/core/enums.dart'; + +class CustomWidthButton extends StatelessWidget { + const CustomWidthButton({ + super.key, + required this.text, + this.buttonType = ButtonType.primary, + required this.sizeRelativeToWidth, + this.onPressed, + }); + + final String text; + final double sizeRelativeToWidth; + final VoidCallback? onPressed; + final ButtonType buttonType; + + @override + Widget build(BuildContext context) { + final Color buttonBackgroundColor; + final Color disabledBackgroundColor; + final Color borderSideColor; + final Color textcolor; + final Color disabledTextColor; + + if (buttonType == ButtonType.primary) { + textcolor = Colors.white; + disabledTextColor = Color.lerp(textcolor, Colors.black, 0.5)!; + buttonBackgroundColor = CustomTheme.primaryColor; + disabledBackgroundColor = Color.lerp( + buttonBackgroundColor, + Colors.black, + 0.5, + )!; + + return ElevatedButton( + onPressed: onPressed, + style: ElevatedButton.styleFrom( + foregroundColor: textcolor, + disabledForegroundColor: disabledTextColor, + backgroundColor: buttonBackgroundColor, + disabledBackgroundColor: disabledBackgroundColor, + animationDuration: const Duration(), + minimumSize: Size( + MediaQuery.sizeOf(context).width * sizeRelativeToWidth, + 60, + ), + shape: RoundedRectangleBorder( + borderRadius: BorderRadius.circular(12), + ), + ), + child: Text( + text, + style: const TextStyle(fontWeight: FontWeight.w500, fontSize: 22), + ), + ); + } else if (buttonType == ButtonType.secondary) { + textcolor = CustomTheme.primaryColor; + disabledTextColor = Color.lerp(textcolor, Colors.black, 0.5)!; + buttonBackgroundColor = Colors.transparent; + disabledBackgroundColor = Colors.transparent; + borderSideColor = onPressed != null + ? CustomTheme.primaryColor + : Color.lerp(CustomTheme.primaryColor, Colors.black, 0.5)!; + + return OutlinedButton( + onPressed: onPressed, + style: OutlinedButton.styleFrom( + foregroundColor: textcolor, + disabledForegroundColor: disabledTextColor, + backgroundColor: buttonBackgroundColor, + disabledBackgroundColor: disabledBackgroundColor, + animationDuration: const Duration(), + minimumSize: Size( + MediaQuery.sizeOf(context).width * sizeRelativeToWidth, + 60, + ), + side: BorderSide(color: borderSideColor, width: 2), + shape: RoundedRectangleBorder( + borderRadius: BorderRadius.circular(12), + ), + ), + child: Text( + text, + style: const TextStyle(fontWeight: FontWeight.w500, fontSize: 22), + ), + ); + } else { + textcolor = CustomTheme.primaryColor; + disabledTextColor = Color.lerp( + CustomTheme.primaryColor, + Colors.black, + 0.5, + )!; + buttonBackgroundColor = Colors.transparent; + disabledBackgroundColor = Colors.transparent; + + return TextButton( + onPressed: onPressed, + style: TextButton.styleFrom( + foregroundColor: textcolor, + disabledForegroundColor: disabledTextColor, + backgroundColor: buttonBackgroundColor, + disabledBackgroundColor: disabledBackgroundColor, + animationDuration: const Duration(), + minimumSize: Size( + MediaQuery.sizeOf(context).width * sizeRelativeToWidth, + 60, + ), + side: const BorderSide(style: BorderStyle.none), + ), + child: Text( + text, + style: const TextStyle(fontWeight: FontWeight.w500, fontSize: 22), + ), + ); + } + } +} diff --git a/lib/presentation/widgets/quick_create_button.dart b/lib/presentation/widgets/buttons/quick_create_button.dart similarity index 100% rename from lib/presentation/widgets/quick_create_button.dart rename to lib/presentation/widgets/buttons/quick_create_button.dart diff --git a/lib/presentation/widgets/custom_search_bar.dart b/lib/presentation/widgets/custom_search_bar.dart new file mode 100644 index 0000000..b482efb --- /dev/null +++ b/lib/presentation/widgets/custom_search_bar.dart @@ -0,0 +1,36 @@ +import 'package:flutter/material.dart'; +import 'package:game_tracker/core/custom_theme.dart'; + +class CustomSearchBar extends StatelessWidget { + final TextEditingController controller; + final String hintText; + final ValueChanged? onChanged; + final BoxConstraints? constraints; + + const CustomSearchBar({ + super.key, + required this.controller, + required this.hintText, + this.onChanged, + this.constraints, + }); + + @override + Widget build(BuildContext context) { + return SearchBar( + controller: controller, + constraints: + constraints ?? const BoxConstraints(maxHeight: 45, minHeight: 45), + hintText: hintText, + onChanged: onChanged, + hintStyle: WidgetStateProperty.all(const TextStyle(fontSize: 16)), + leading: const Icon(Icons.search), + backgroundColor: WidgetStateProperty.all(CustomTheme.boxColor), + side: WidgetStateProperty.all(BorderSide(color: CustomTheme.boxBorder)), + shape: WidgetStateProperty.all( + RoundedRectangleBorder(borderRadius: BorderRadius.circular(12)), + ), + elevation: WidgetStateProperty.all(0), + ); + } +} diff --git a/lib/presentation/widgets/text_input_field.dart b/lib/presentation/widgets/text_input_field.dart new file mode 100644 index 0000000..6cd9d75 --- /dev/null +++ b/lib/presentation/widgets/text_input_field.dart @@ -0,0 +1,38 @@ +import 'package:flutter/material.dart'; +import 'package:game_tracker/core/custom_theme.dart'; + +class TextInputField extends StatelessWidget { + final TextEditingController controller; + final ValueChanged? onChanged; + final String hintText; + + const TextInputField({ + super.key, + required this.controller, + required this.hintText, + this.onChanged, + }); + + @override + Widget build(BuildContext context) { + return TextField( + controller: controller, + onChanged: onChanged, + decoration: InputDecoration( + filled: true, + fillColor: CustomTheme.boxColor, + hintText: hintText, + hintStyle: const TextStyle(fontSize: 18), + enabledBorder: OutlineInputBorder( + borderRadius: const BorderRadius.all(Radius.circular(12)), + borderSide: BorderSide(color: CustomTheme.boxBorder), + ), + focusedBorder: OutlineInputBorder( + borderRadius: const BorderRadius.all(Radius.circular(12)), + borderSide: BorderSide(color: CustomTheme.boxBorder), + ), + floatingLabelBehavior: FloatingLabelBehavior.never, + ), + ); + } +} diff --git a/lib/presentation/widgets/double_row_info_tile.dart b/lib/presentation/widgets/tiles/double_row_info_tile.dart similarity index 72% rename from lib/presentation/widgets/double_row_info_tile.dart rename to lib/presentation/widgets/tiles/double_row_info_tile.dart index 621cc74..57404ff 100644 --- a/lib/presentation/widgets/double_row_info_tile.dart +++ b/lib/presentation/widgets/tiles/double_row_info_tile.dart @@ -9,8 +9,8 @@ Widget doubleRowInfoTile( String titleLowerRight, ) { return Container( - margin: EdgeInsets.symmetric(vertical: 5, horizontal: 10), - padding: EdgeInsets.all(10), + margin: const EdgeInsets.symmetric(vertical: 5, horizontal: 10), + padding: const EdgeInsets.all(10), decoration: BoxDecoration( borderRadius: BorderRadius.circular(20), color: CustomTheme.secondaryColor, @@ -22,18 +22,18 @@ Widget doubleRowInfoTile( Expanded( flex: 10, child: Text( - "$titleOneUpperLeft $titleTwoUpperLeft", - style: TextStyle(fontSize: 20), + '$titleOneUpperLeft $titleTwoUpperLeft', + style: const TextStyle(fontSize: 20), overflow: TextOverflow.ellipsis, maxLines: 1, ), ), - Spacer(), + const Spacer(), Expanded( flex: 3, child: Text( - "$titleUpperRight", - style: TextStyle(fontSize: 20), + titleUpperRight, + style: const TextStyle(fontSize: 20), overflow: TextOverflow.ellipsis, maxLines: 1, textAlign: TextAlign.end, @@ -46,18 +46,18 @@ Widget doubleRowInfoTile( Expanded( flex: 10, child: Text( - "$titleLowerLeft", - style: TextStyle(fontSize: 20), + titleLowerLeft, + style: const TextStyle(fontSize: 20), overflow: TextOverflow.ellipsis, maxLines: 1, ), ), - Spacer(), + const Spacer(), Expanded( flex: 4, child: Text( - "$titleLowerRight", - style: TextStyle(fontSize: 20), + titleLowerRight, + style: const TextStyle(fontSize: 20), overflow: TextOverflow.ellipsis, maxLines: 1, textAlign: TextAlign.end, diff --git a/lib/presentation/widgets/game_tile.dart b/lib/presentation/widgets/tiles/game_tile.dart similarity index 71% rename from lib/presentation/widgets/game_tile.dart rename to lib/presentation/widgets/tiles/game_tile.dart index c79a6b7..fcd2f65 100644 --- a/lib/presentation/widgets/game_tile.dart +++ b/lib/presentation/widgets/tiles/game_tile.dart @@ -1,5 +1,6 @@ import 'package:flutter/material.dart'; import 'package:game_tracker/core/custom_theme.dart'; +import 'package:skeletonizer/skeletonizer.dart'; class GameTile extends StatefulWidget { final String gameTitle; @@ -48,9 +49,11 @@ class _GameTileState extends State { borderRadius: BorderRadius.circular(4), color: CustomTheme.primaryColor, ), - child: Text( - widget.ruleset, - style: const TextStyle(fontWeight: FontWeight.bold), + child: Skeleton.ignore( + child: Text( + widget.ruleset, + style: const TextStyle(fontWeight: FontWeight.bold), + ), ), ), Center( @@ -68,19 +71,21 @@ class _GameTileState extends State { borderRadius: BorderRadius.circular(4), color: Colors.yellow.shade300, ), - child: Row( - mainAxisAlignment: MainAxisAlignment.center, - children: [ - const Icon(Icons.emoji_events, color: Colors.black, size: 20), - Text( - widget.winner, - textAlign: TextAlign.center, - style: const TextStyle( - fontWeight: FontWeight.bold, - color: Colors.black87, + child: Skeleton.ignore( + child: Row( + mainAxisAlignment: MainAxisAlignment.center, + children: [ + const Icon(Icons.emoji_events, color: Colors.black, size: 20), + Text( + widget.winner, + textAlign: TextAlign.center, + style: const TextStyle( + fontWeight: FontWeight.bold, + color: Colors.black87, + ), ), - ), - ], + ], + ), ), ), ), diff --git a/lib/presentation/widgets/tiles/group_tile.dart b/lib/presentation/widgets/tiles/group_tile.dart new file mode 100644 index 0000000..fa91477 --- /dev/null +++ b/lib/presentation/widgets/tiles/group_tile.dart @@ -0,0 +1,68 @@ +import 'package:flutter/material.dart'; +import 'package:game_tracker/core/custom_theme.dart'; +import 'package:game_tracker/data/dto/group.dart'; +import 'package:game_tracker/presentation/widgets/tiles/text_icon_tile.dart'; + +class GroupTile extends StatelessWidget { + const GroupTile({super.key, required this.group}); + + final Group group; + + @override + Widget build(BuildContext context) { + return Container( + margin: const EdgeInsets.symmetric(horizontal: 12, vertical: 10), + padding: const EdgeInsets.symmetric(vertical: 5, horizontal: 10), + decoration: BoxDecoration( + color: CustomTheme.boxColor, + border: Border.all(color: CustomTheme.boxBorder), + borderRadius: BorderRadius.circular(12), + ), + child: Column( + crossAxisAlignment: CrossAxisAlignment.start, + children: [ + Row( + mainAxisAlignment: MainAxisAlignment.spaceBetween, + children: [ + Flexible( + child: Text( + group.name, + overflow: TextOverflow.ellipsis, + style: const TextStyle( + fontWeight: FontWeight.bold, + fontSize: 18, + ), + ), + ), + Row( + children: [ + Text( + '${group.members.length}', + style: const TextStyle( + fontWeight: FontWeight.w900, + fontSize: 18, + ), + ), + const SizedBox(width: 3), + const Icon(Icons.group, size: 22), + ], + ), + ], + ), + const SizedBox(height: 5), + Wrap( + alignment: WrapAlignment.start, + crossAxisAlignment: WrapCrossAlignment.start, + spacing: 12.0, + runSpacing: 8.0, + children: [ + for (var member in group.members) + TextIconTile(text: member.name, iconEnabled: false), + ], + ), + const SizedBox(height: 2.5), + ], + ), + ); + } +} diff --git a/lib/presentation/widgets/tiles/text_icon_list_tile.dart b/lib/presentation/widgets/tiles/text_icon_list_tile.dart new file mode 100644 index 0000000..5e272c9 --- /dev/null +++ b/lib/presentation/widgets/tiles/text_icon_list_tile.dart @@ -0,0 +1,52 @@ +import 'package:flutter/material.dart'; +import 'package:game_tracker/core/custom_theme.dart'; + +class TextIconListTile extends StatelessWidget { + final String text; + final VoidCallback? onPressed; + final bool iconEnabled; + + const TextIconListTile({ + super.key, + required this.text, + this.onPressed, + this.iconEnabled = true, + }); + + @override + Widget build(BuildContext context) { + return Container( + margin: const EdgeInsets.symmetric(horizontal: 5, vertical: 5), + padding: const EdgeInsets.symmetric(horizontal: 15), + decoration: BoxDecoration( + color: CustomTheme.boxColor, + border: Border.all(color: CustomTheme.boxBorder), + borderRadius: BorderRadius.circular(12), + ), + child: Row( + mainAxisAlignment: MainAxisAlignment.spaceBetween, + mainAxisSize: MainAxisSize.max, + children: [ + Flexible( + child: Container( + padding: const EdgeInsets.symmetric(vertical: 12.5), + child: Text( + text, + overflow: TextOverflow.ellipsis, + style: const TextStyle( + fontSize: 16, + fontWeight: FontWeight.w500, + ), + ), + ), + ), + if (iconEnabled) + GestureDetector( + onTap: onPressed, + child: const Icon(Icons.add, size: 20), + ), + ], + ), + ); + } +} diff --git a/lib/presentation/widgets/tiles/text_icon_tile.dart b/lib/presentation/widgets/tiles/text_icon_tile.dart new file mode 100644 index 0000000..2544837 --- /dev/null +++ b/lib/presentation/widgets/tiles/text_icon_tile.dart @@ -0,0 +1,47 @@ +import 'package:flutter/material.dart'; +import 'package:game_tracker/core/custom_theme.dart'; + +class TextIconTile extends StatelessWidget { + final String text; + final bool iconEnabled; + final VoidCallback? onIconTap; + + const TextIconTile({ + super.key, + required this.text, + this.onIconTap, + this.iconEnabled = true, + }); + + @override + Widget build(BuildContext context) { + return Container( + padding: const EdgeInsets.all(5), + decoration: BoxDecoration( + color: CustomTheme.onBoxColor, + borderRadius: BorderRadius.circular(12), + ), + child: Row( + mainAxisAlignment: MainAxisAlignment.spaceBetween, + mainAxisSize: MainAxisSize.min, + children: [ + if (iconEnabled) const SizedBox(width: 3), + Flexible( + child: Text( + text, + overflow: TextOverflow.ellipsis, + style: const TextStyle(fontSize: 14, fontWeight: FontWeight.w500), + ), + ), + if (iconEnabled) ...[ + const SizedBox(width: 3), + GestureDetector( + onTap: onIconTap, + child: const Icon(Icons.close, size: 20), + ), + ], + ], + ), + ); + } +} diff --git a/lib/presentation/widgets/top_centered_message.dart b/lib/presentation/widgets/top_centered_message.dart index 6fe34ff..a5deea2 100644 --- a/lib/presentation/widgets/top_centered_message.dart +++ b/lib/presentation/widgets/top_centered_message.dart @@ -1,14 +1,39 @@ import 'package:flutter/material.dart'; -Widget TopCenteredMessage(String message) { - return Container( - padding: EdgeInsets.only(top: 100), - margin: EdgeInsets.only(left: 10, right: 10), - alignment: Alignment.topCenter, - child: Text( - "$message", - style: TextStyle(fontSize: 20), - textAlign: TextAlign.center, - ), - ); +class TopCenteredMessage extends StatelessWidget { + const TopCenteredMessage({ + super.key, + required this.icon, + required this.title, + required this.message, + }); + + final String title; + final String message; + final IconData icon; + + @override + Widget build(BuildContext context) { + return Container( + padding: const EdgeInsets.only(top: 100), + margin: const EdgeInsets.symmetric(horizontal: 10), + alignment: Alignment.topCenter, + child: Column( + children: [ + Icon(icon, size: 45), + const SizedBox(height: 10), + Text( + title, + style: const TextStyle(fontSize: 18, fontWeight: FontWeight.bold), + textAlign: TextAlign.center, + ), + Text( + message, + style: const TextStyle(fontSize: 16), + textAlign: TextAlign.center, + ), + ], + ), + ); + } } diff --git a/pubspec.yaml b/pubspec.yaml index 5fa8019..b17f409 100644 --- a/pubspec.yaml +++ b/pubspec.yaml @@ -18,6 +18,9 @@ dependencies: drift_flutter: ^0.2.4 path_provider: ^2.1.5 provider: ^6.1.5 + skeletonizer: ^2.1.0+1 + uuid: ^4.5.2 + clock: ^1.1.2 dev_dependencies: flutter_test: diff --git a/test/db_tests/game_test.dart b/test/db_tests/game_test.dart new file mode 100644 index 0000000..d726425 --- /dev/null +++ b/test/db_tests/game_test.dart @@ -0,0 +1,116 @@ +import 'package:clock/clock.dart'; +import 'package:drift/drift.dart'; +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/data/dto/group.dart'; +import 'package:game_tracker/data/dto/player.dart'; + +void main() { + late AppDatabase database; + late Player player1; + late Player player2; + late Player player3; + late Player player4; + late Player player5; + late Group testgroup; + late Game testgame; + final fixedDate = DateTime(2025, 19, 11, 00, 11, 23); + final fakeClock = Clock(() => fixedDate); + + setUp(() { + database = AppDatabase( + DatabaseConnection( + NativeDatabase.memory(), + // Recommended for widget tests to avoid test errors. + closeStreamsSynchronously: true, + ), + ); + + withClock(fakeClock, () { + player1 = Player(name: 'Alice'); + player2 = Player(name: 'Bob'); + player3 = Player(name: 'Charlie'); + player4 = Player(name: 'Diana'); + player5 = Player(name: 'Eve'); + testgroup = Group( + name: 'Test Group', + members: [player1, player2, player3], + ); + testgame = Game( + name: 'Test Game', + group: testgroup, + players: [player4, player5], + ); + }); + }); + tearDown(() async { + await database.close(); + }); + + group('game tests', () { + test('game is added correctly', () async { + await database.gameDao.addGame(game: testgame); + + final result = await database.gameDao.getGameById(gameId: testgame.id); + + expect(result.id, testgame.id); + expect(result.name, testgame.name); + expect(result.winner, testgame.winner); + expect(result.createdAt, testgame.createdAt); + + if (result.group != null) { + expect(result.group!.members.length, testgroup.members.length); + + for (int i = 0; i < testgroup.members.length; i++) { + expect(result.group!.members[i].id, testgroup.members[i].id); + expect(result.group!.members[i].name, testgroup.members[i].name); + } + } else { + fail('Group is null'); + } + if (result.players != null) { + expect(result.players!.length, testgame.players!.length); + + for (int i = 0; i < testgame.players!.length; i++) { + expect(result.players![i].id, testgame.players![i].id); + expect(result.players![i].name, testgame.players![i].name); + expect(result.players![i].createdAt, testgame.players![i].createdAt); + } + } else { + fail('Players is null'); + } + }); + + test('game is deleted correctly', () async { + await database.gameDao.addGame(game: testgame); + + final gameDeleted = await database.gameDao.deleteGame( + gameId: testgame.id, + ); + expect(gameDeleted, true); + + final gameExists = await database.gameDao.gameExists(gameId: testgame.id); + expect(gameExists, false); + }); + + test('get game count works correctly', () async { + final initialCount = await database.gameDao.getGameCount(); + expect(initialCount, 0); + + await database.gameDao.addGame(game: testgame); + + final gameAdded = await database.gameDao.getGameCount(); + expect(gameAdded, 1); + + final gameRemoved = await database.gameDao.deleteGame( + gameId: testgame.id, + ); + expect(gameRemoved, true); + + final finalCount = await database.gameDao.getGameCount(); + expect(finalCount, 0); + }); + }); +} diff --git a/test/db_tests/group_test.dart b/test/db_tests/group_test.dart new file mode 100644 index 0000000..a076ab0 --- /dev/null +++ b/test/db_tests/group_test.dart @@ -0,0 +1,188 @@ +import 'package:clock/clock.dart'; +import 'package:drift/drift.dart'; +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/group.dart'; +import 'package:game_tracker/data/dto/player.dart'; + +void main() { + late AppDatabase database; + late Player player1; + late Player player2; + late Player player3; + late Player player4; + late Group testgroup; + late Group testgroup2; + final fixedDate = DateTime(2025, 19, 11, 00, 11, 23); + final fakeClock = Clock(() => fixedDate); + + setUp(() { + database = AppDatabase( + DatabaseConnection( + NativeDatabase.memory(), + // Recommended for widget tests to avoid test errors. + closeStreamsSynchronously: true, + ), + ); + + withClock(fakeClock, () { + player1 = Player(name: 'Alice'); + player2 = Player(name: 'Bob'); + player3 = Player(name: 'Charlie'); + player4 = Player(name: 'Diana'); + testgroup = Group( + name: 'Test Group', + members: [player1, player2, player3], + ); + testgroup2 = Group( + id: 'gr2', + name: 'Second Group', + members: [player2, player3, player4], + ); + }); + }); + tearDown(() async { + await database.close(); + }); + group('group tests', () { + test('all groups get fetched correctly', () async { + await database.groupDao.addGroup(group: testgroup); + await database.groupDao.addGroup(group: testgroup2); + + final allGroups = await database.groupDao.getAllGroups(); + expect(allGroups.length, 2); + + final fetchedGroup1 = allGroups.firstWhere((g) => g.id == testgroup.id); + expect(fetchedGroup1.name, testgroup.name); + expect(fetchedGroup1.members.length, testgroup.members.length); + expect(fetchedGroup1.members.elementAt(0).id, player1.id); + expect(fetchedGroup1.members.elementAt(0).createdAt, player1.createdAt); + + final fetchedGroup2 = allGroups.firstWhere((g) => g.id == testgroup2.id); + expect(fetchedGroup2.name, testgroup2.name); + expect(fetchedGroup2.members.length, testgroup2.members.length); + expect(fetchedGroup2.members.elementAt(0).id, player2.id); + expect(fetchedGroup2.members.elementAt(0).createdAt, player2.createdAt); + }); + + test('group and group members gets added correctly', () async { + await database.groupDao.addGroup(group: testgroup); + + final result = await database.groupDao.getGroupById( + groupId: testgroup.id, + ); + + expect(result.id, testgroup.id); + expect(result.name, testgroup.name); + expect(result.createdAt, testgroup.createdAt); + + expect(result.members.length, testgroup.members.length); + for (int i = 0; i < testgroup.members.length; i++) { + expect(result.members[i].id, testgroup.members[i].id); + expect(result.members[i].name, testgroup.members[i].name); + expect(result.members[i].createdAt, testgroup.members[i].createdAt); + } + }); + + test('group gets deleted correctly', () async { + await database.groupDao.addGroup(group: testgroup); + + final groupDeleted = await database.groupDao.deleteGroup( + groupId: testgroup.id, + ); + expect(groupDeleted, true); + + final groupExists = await database.groupDao.groupExists( + groupId: testgroup.id, + ); + expect(groupExists, false); + }); + + test('group name gets updated correcly ', () async { + await database.groupDao.addGroup(group: testgroup); + + const newGroupName = 'new group name'; + + await database.groupDao.updateGroupname( + groupId: testgroup.id, + newName: newGroupName, + ); + + final result = await database.groupDao.getGroupById( + groupId: testgroup.id, + ); + expect(result.name, newGroupName); + }); + + test('Adding player to group works correctly', () async { + await database.groupDao.addGroup(group: testgroup); + + await database.playerGroupDao.addPlayerToGroup( + player: player4, + groupId: testgroup.id, + ); + + final playerAdded = await database.playerGroupDao.isPlayerInGroup( + playerId: player4.id, + groupId: testgroup.id, + ); + + expect(playerAdded, true); + + final playerNotAdded = !await database.playerGroupDao.isPlayerInGroup( + playerId: '', + groupId: testgroup.id, + ); + + expect(playerNotAdded, true); + + final result = await database.groupDao.getGroupById( + groupId: testgroup.id, + ); + expect(result.members.length, testgroup.members.length + 1); + + final addedPlayer = result.members.firstWhere((p) => p.id == player4.id); + expect(addedPlayer.name, player4.name); + expect(addedPlayer.createdAt, player4.createdAt); + }); + + test('Removing player from group works correctly', () async { + await database.groupDao.addGroup(group: testgroup); + + final playerToRemove = testgroup.members[0]; + + final removed = await database.playerGroupDao.removePlayerFromGroup( + playerId: playerToRemove.id, + groupId: testgroup.id, + ); + expect(removed, true); + + final result = await database.groupDao.getGroupById( + groupId: testgroup.id, + ); + expect(result.members.length, testgroup.members.length - 1); + + final playerExists = result.members.any((p) => p.id == playerToRemove.id); + expect(playerExists, false); + }); + + test('get group count works correctly', () async { + final initialCount = await database.groupDao.getGroupCount(); + expect(initialCount, 0); + + await database.groupDao.addGroup(group: testgroup); + + final groupAdded = await database.groupDao.getGroupCount(); + expect(groupAdded, 1); + + final groupRemoved = await database.groupDao.deleteGroup( + groupId: testgroup.id, + ); + expect(groupRemoved, true); + + final finalCount = await database.groupDao.getGroupCount(); + expect(finalCount, 0); + }); + }); +} diff --git a/test/db_tests/player_test.dart b/test/db_tests/player_test.dart new file mode 100644 index 0000000..fa65f67 --- /dev/null +++ b/test/db_tests/player_test.dart @@ -0,0 +1,112 @@ +import 'package:clock/clock.dart'; +import 'package:drift/drift.dart'; +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/player.dart'; + +void main() { + late AppDatabase database; + late Player testPlayer; + late Player testPlayer2; + final fixedDate = DateTime(2025, 19, 11, 00, 11, 23); + final fakeClock = Clock(() => fixedDate); + + setUp(() { + database = AppDatabase( + DatabaseConnection( + NativeDatabase.memory(), + // Recommended for widget tests to avoid test errors. + closeStreamsSynchronously: true, + ), + ); + + withClock(fakeClock, () { + testPlayer = Player(name: 'Test Player'); + testPlayer2 = Player(name: 'Second Group'); + }); + }); + tearDown(() async { + await database.close(); + }); + + group('player tests', () { + test('all players get fetched correctly', () async { + await database.playerDao.addPlayer(player: testPlayer); + await database.playerDao.addPlayer(player: testPlayer2); + + final allPlayers = await database.playerDao.getAllPlayers(); + expect(allPlayers.length, 2); + + final fetchedPlayer1 = allPlayers.firstWhere( + (g) => g.id == testPlayer.id, + ); + expect(fetchedPlayer1.name, testPlayer.name); + expect(fetchedPlayer1.createdAt, testPlayer.createdAt); + + final fetchedPlayer2 = allPlayers.firstWhere( + (g) => g.id == testPlayer2.id, + ); + expect(fetchedPlayer2.name, testPlayer2.name); + expect(fetchedPlayer2.createdAt, testPlayer2.createdAt); + }); + + test('players get inserted correcly ', () async { + await database.playerDao.addPlayer(player: testPlayer); + final result = await database.playerDao.getPlayerById( + playerId: testPlayer.id, + ); + + expect(result.id, testPlayer.id); + expect(result.name, testPlayer.name); + expect(result.createdAt, testPlayer.createdAt); + }); + + test('players get deleted correcly ', () async { + await database.playerDao.addPlayer(player: testPlayer); + final playerDeleted = await database.playerDao.deletePlayer( + playerId: testPlayer.id, + ); + expect(playerDeleted, true); + + final playerExists = await database.playerDao.playerExists( + playerId: testPlayer.id, + ); + expect(playerExists, false); + }); + + test('player name gets updated correcly ', () async { + await database.playerDao.addPlayer(player: testPlayer); + + const newPlayerName = 'new player name'; + + await database.playerDao.updatePlayername( + playerId: testPlayer.id, + newName: newPlayerName, + ); + + final result = await database.playerDao.getPlayerById( + playerId: testPlayer.id, + ); + expect(result.name, newPlayerName); + }); + + test('get player count works correctly', () async { + final initialCount = await database.playerDao.getPlayerCount(); + expect(initialCount, 0); + + await database.playerDao.addPlayer(player: testPlayer); + + final playerAdded = await database.playerDao.getPlayerCount(); + expect(playerAdded, 1); + + final playerRemoved = await database.playerDao.deletePlayer( + playerId: testPlayer.id, + ); + expect(playerRemoved, true); + + final finalCount = await database.playerDao.getPlayerCount(); + expect(finalCount, 0); + }); + }); +} diff --git a/test/widget_test.dart b/test/widget_test.dart deleted file mode 100644 index 25cbc0e..0000000 --- a/test/widget_test.dart +++ /dev/null @@ -1,30 +0,0 @@ -// This is a basic Flutter widget test. -// -// To perform an interaction with a widget in your test, use the WidgetTester -// utility in the flutter_test package. For example, you can send tap and scroll -// gestures. You can also use WidgetTester to find child widgets in the widget -// tree, read text, and verify that the values of widget properties are correct. - -import 'package:flutter/material.dart'; -import 'package:flutter_test/flutter_test.dart'; - -import 'package:game_tracker/main.dart'; - -void main() { - testWidgets('Counter increments smoke test', (WidgetTester tester) async { - // Build our app and trigger a frame. - await tester.pumpWidget(const MyApp()); - - // Verify that our counter starts at 0. - expect(find.text('0'), findsOneWidget); - expect(find.text('1'), findsNothing); - - // Tap the '+' icon and trigger a frame. - await tester.tap(find.byIcon(Icons.add)); - await tester.pump(); - - // Verify that our counter has incremented. - expect(find.text('0'), findsNothing); - expect(find.text('1'), findsOneWidget); - }); -}