From e1426810f284d44da94ac00134fcf51bdcc750f0 Mon Sep 17 00:00:00 2001 From: Felix Kirchner Date: Sat, 8 Nov 2025 16:14:02 +0000 Subject: [PATCH 001/141] .gitea/PULL_REQUEST_TEMPLATE.md aktualisiert --- .gitea/PULL_REQUEST_TEMPLATE.md | 22 +++++++++++----------- 1 file changed, 11 insertions(+), 11 deletions(-) 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?* From 4c1d91ae99fd60093e7c7b3049a8c580f7202fe8 Mon Sep 17 00:00:00 2001 From: Felix Kirchner Date: Mon, 10 Nov 2025 12:52:56 +0000 Subject: [PATCH 002/141] .gitea/ISSUE_TEMPLATE/FEATURE.md aktualisiert --- .gitea/ISSUE_TEMPLATE/FEATURE.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.gitea/ISSUE_TEMPLATE/FEATURE.md b/.gitea/ISSUE_TEMPLATE/FEATURE.md index 809509b..d7ff58e 100644 --- a/.gitea/ISSUE_TEMPLATE/FEATURE.md +++ b/.gitea/ISSUE_TEMPLATE/FEATURE.md @@ -7,7 +7,7 @@ assignees: '' --- -# 🚀 Feature +# Feature ## Description [Detailed explanation of the proposed feature] From e61f9e5e64dd7979f111f49045e601b4913c5cfa Mon Sep 17 00:00:00 2001 From: Felix Kirchner Date: Mon, 10 Nov 2025 12:59:16 +0000 Subject: [PATCH 003/141] .gitea/ISSUE_TEMPLATE/FEATURE.md aktualisiert --- .gitea/ISSUE_TEMPLATE/FEATURE.md | 17 +++++++---------- 1 file changed, 7 insertions(+), 10 deletions(-) diff --git a/.gitea/ISSUE_TEMPLATE/FEATURE.md b/.gitea/ISSUE_TEMPLATE/FEATURE.md index d7ff58e..01e7a5f 100644 --- a/.gitea/ISSUE_TEMPLATE/FEATURE.md +++ b/.gitea/ISSUE_TEMPLATE/FEATURE.md @@ -1,6 +1,6 @@ --- name: Feature -about: New feature for the app +about: Neues Feature für die App title: '' labels: 'Task\Feature' assignees: '' @@ -9,14 +9,11 @@ assignees: '' # 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 From 2c0e9967952b86e9f57a28a9945e9a0a7051d2aa Mon Sep 17 00:00:00 2001 From: Felix Kirchner Date: Mon, 10 Nov 2025 13:02:21 +0000 Subject: [PATCH 004/141] .gitea/ISSUE_TEMPLATE/BUG_REPORT.md aktualisiert --- .gitea/ISSUE_TEMPLATE/BUG_REPORT.md | 37 ++++++++++++++--------------- 1 file changed, 18 insertions(+), 19 deletions(-) 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 From 55e5e3cbeb7667c582f0b3a293cadd3a51643d23 Mon Sep 17 00:00:00 2001 From: Felix Kirchner Date: Mon, 10 Nov 2025 13:04:10 +0000 Subject: [PATCH 005/141] .gitea/ISSUE_TEMPLATE/ENHANCEMENT.md aktualisiert --- .gitea/ISSUE_TEMPLATE/ENHANCEMENT.md | 16 ++++++++-------- 1 file changed, 8 insertions(+), 8 deletions(-) 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 From b83fe03f35e87fd9ba2c6beda361bf434deaca2d Mon Sep 17 00:00:00 2001 From: Felix Kirchner Date: Wed, 12 Nov 2025 10:54:05 +0100 Subject: [PATCH 006/141] Renamed app --- lib/main.dart | 6 +++--- test/widget_test.dart | 3 +-- 2 files changed, 4 insertions(+), 5 deletions(-) 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/test/widget_test.dart b/test/widget_test.dart index 25cbc0e..cb44eec 100644 --- a/test/widget_test.dart +++ b/test/widget_test.dart @@ -7,13 +7,12 @@ 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()); + await tester.pumpWidget(const GameTracker()); // Verify that our counter starts at 0. expect(find.text('0'), findsOneWidget); From 25c7b37df3bc18d87bf964348765eaafed4bf57d Mon Sep 17 00:00:00 2001 From: Felix Kirchner Date: Wed, 12 Nov 2025 10:57:46 +0100 Subject: [PATCH 007/141] updated userId to playerId --- lib/data/dao/player_group_dao.dart | 14 +-- lib/data/db/database.g.dart | 128 +++++++++++---------- lib/data/db/tables/player_group_table.dart | 4 +- 3 files changed, 74 insertions(+), 72 deletions(-) diff --git a/lib/data/dao/player_group_dao.dart b/lib/data/dao/player_group_dao.dart index b68ed09..e51c325 100644 --- a/lib/data/dao/player_group_dao.dart +++ b/lib/data/dao/player_group_dao.dart @@ -19,26 +19,26 @@ class PlayerGroupDao extends DatabaseAccessor List groupMembers = []; for (var entry in result) { - final player = await db.playerDao.getPlayerById(entry.userId); + final player = await db.playerDao.getPlayerById(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(String playerId, 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 [playerId] and [groupId]. + Future addPlayerToGroup(String playerId, String groupId) async { await into(playerGroupTable).insert( - PlayerGroupTableCompanion.insert(userId: userId, groupId: groupId), + PlayerGroupTableCompanion.insert(playerId: playerId, groupId: groupId), ); } } diff --git a/lib/data/db/database.g.dart b/lib/data/db/database.g.dart index 4075912..d4e9e94 100644 --- a/lib/data/db/database.g.dart +++ b/lib/data/db/database.g.dart @@ -419,10 +419,12 @@ class $PlayerGroupTableTable extends PlayerGroupTable final GeneratedDatabase attachedDatabase; final String? _alias; $PlayerGroupTableTable(this.attachedDatabase, [this._alias]); - static const VerificationMeta _userIdMeta = const VerificationMeta('userId'); + static const VerificationMeta _playerIdMeta = const VerificationMeta( + 'playerId', + ); @override - late final GeneratedColumn userId = GeneratedColumn( - 'user_id', + late final GeneratedColumn playerId = GeneratedColumn( + 'player_id', aliasedName, false, type: DriftSqlType.string, @@ -446,7 +448,7 @@ class $PlayerGroupTableTable extends PlayerGroupTable ), ); @override - List get $columns => [userId, groupId]; + List get $columns => [playerId, groupId]; @override String get aliasedName => _alias ?? actualTableName; @override @@ -459,13 +461,13 @@ class $PlayerGroupTableTable extends PlayerGroupTable }) { final context = VerificationContext(); final data = instance.toColumns(true); - if (data.containsKey('user_id')) { + if (data.containsKey('player_id')) { context.handle( - _userIdMeta, - userId.isAcceptableOrUnknown(data['user_id']!, _userIdMeta), + _playerIdMeta, + playerId.isAcceptableOrUnknown(data['player_id']!, _playerIdMeta), ); } else if (isInserting) { - context.missing(_userIdMeta); + context.missing(_playerIdMeta); } if (data.containsKey('group_id')) { context.handle( @@ -479,14 +481,14 @@ class $PlayerGroupTableTable extends PlayerGroupTable } @override - Set get $primaryKey => {userId, groupId}; + Set get $primaryKey => {playerId, groupId}; @override PlayerGroupTableData map(Map data, {String? tablePrefix}) { final effectivePrefix = tablePrefix != null ? '$tablePrefix.' : ''; return PlayerGroupTableData( - userId: attachedDatabase.typeMapping.read( + playerId: attachedDatabase.typeMapping.read( DriftSqlType.string, - data['${effectivePrefix}user_id'], + data['${effectivePrefix}player_id'], )!, groupId: attachedDatabase.typeMapping.read( DriftSqlType.string, @@ -503,20 +505,20 @@ class $PlayerGroupTableTable extends PlayerGroupTable class PlayerGroupTableData extends DataClass implements Insertable { - final String userId; + final String playerId; final String groupId; - const PlayerGroupTableData({required this.userId, required this.groupId}); + const PlayerGroupTableData({required this.playerId, required this.groupId}); @override Map toColumns(bool nullToAbsent) { final map = {}; - map['user_id'] = Variable(userId); + map['player_id'] = Variable(playerId); map['group_id'] = Variable(groupId); return map; } PlayerGroupTableCompanion toCompanion(bool nullToAbsent) { return PlayerGroupTableCompanion( - userId: Value(userId), + playerId: Value(playerId), groupId: Value(groupId), ); } @@ -527,7 +529,7 @@ class PlayerGroupTableData extends DataClass }) { serializer ??= driftRuntimeOptions.defaultSerializer; return PlayerGroupTableData( - userId: serializer.fromJson(json['userId']), + playerId: serializer.fromJson(json['playerId']), groupId: serializer.fromJson(json['groupId']), ); } @@ -535,19 +537,19 @@ class PlayerGroupTableData extends DataClass Map toJson({ValueSerializer? serializer}) { serializer ??= driftRuntimeOptions.defaultSerializer; return { - 'userId': serializer.toJson(userId), + 'playerId': serializer.toJson(playerId), 'groupId': serializer.toJson(groupId), }; } - PlayerGroupTableData copyWith({String? userId, String? groupId}) => + PlayerGroupTableData copyWith({String? playerId, String? groupId}) => PlayerGroupTableData( - userId: userId ?? this.userId, + playerId: playerId ?? this.playerId, groupId: groupId ?? this.groupId, ); PlayerGroupTableData copyWithCompanion(PlayerGroupTableCompanion data) { return PlayerGroupTableData( - userId: data.userId.present ? data.userId.value : this.userId, + playerId: data.playerId.present ? data.playerId.value : this.playerId, groupId: data.groupId.present ? data.groupId.value : this.groupId, ); } @@ -555,56 +557,56 @@ class PlayerGroupTableData extends DataClass @override String toString() { return (StringBuffer('PlayerGroupTableData(') - ..write('userId: $userId, ') + ..write('playerId: $playerId, ') ..write('groupId: $groupId') ..write(')')) .toString(); } @override - int get hashCode => Object.hash(userId, groupId); + int get hashCode => Object.hash(playerId, groupId); @override bool operator ==(Object other) => identical(this, other) || (other is PlayerGroupTableData && - other.userId == this.userId && + other.playerId == this.playerId && other.groupId == this.groupId); } class PlayerGroupTableCompanion extends UpdateCompanion { - final Value userId; + final Value playerId; final Value groupId; final Value rowid; const PlayerGroupTableCompanion({ - this.userId = const Value.absent(), + this.playerId = const Value.absent(), this.groupId = const Value.absent(), this.rowid = const Value.absent(), }); PlayerGroupTableCompanion.insert({ - required String userId, + required String playerId, required String groupId, this.rowid = const Value.absent(), - }) : userId = Value(userId), + }) : playerId = Value(playerId), groupId = Value(groupId); static Insertable custom({ - Expression? userId, + Expression? playerId, Expression? groupId, Expression? rowid, }) { return RawValuesInsertable({ - if (userId != null) 'user_id': userId, + if (playerId != null) 'player_id': playerId, if (groupId != null) 'group_id': groupId, if (rowid != null) 'rowid': rowid, }); } PlayerGroupTableCompanion copyWith({ - Value? userId, + Value? playerId, Value? groupId, Value? rowid, }) { return PlayerGroupTableCompanion( - userId: userId ?? this.userId, + playerId: playerId ?? this.playerId, groupId: groupId ?? this.groupId, rowid: rowid ?? this.rowid, ); @@ -613,8 +615,8 @@ class PlayerGroupTableCompanion extends UpdateCompanion { @override Map toColumns(bool nullToAbsent) { final map = {}; - if (userId.present) { - map['user_id'] = Variable(userId.value); + if (playerId.present) { + map['player_id'] = Variable(playerId.value); } if (groupId.present) { map['group_id'] = Variable(groupId.value); @@ -628,7 +630,7 @@ class PlayerGroupTableCompanion extends UpdateCompanion { @override String toString() { return (StringBuffer('PlayerGroupTableCompanion(') - ..write('userId: $userId, ') + ..write('playerId: $playerId, ') ..write('groupId: $groupId, ') ..write('rowid: $rowid') ..write(')')) @@ -890,7 +892,7 @@ final class $$PlayerTableTableReferences db.playerGroupTable, aliasName: $_aliasNameGenerator( db.playerTable.id, - db.playerGroupTable.userId, + db.playerGroupTable.playerId, ), ); @@ -898,7 +900,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), @@ -935,7 +937,7 @@ class $$PlayerTableTableFilterComposer composer: this, getCurrentColumn: (t) => t.id, referencedTable: $db.playerGroupTable, - getReferencedColumn: (t) => t.userId, + getReferencedColumn: (t) => t.playerId, builder: ( joinBuilder, { @@ -996,7 +998,7 @@ class $$PlayerTableTableAnnotationComposer composer: this, getCurrentColumn: (t) => t.id, referencedTable: $db.playerGroupTable, - getReferencedColumn: (t) => t.userId, + getReferencedColumn: (t) => t.playerId, builder: ( joinBuilder, { @@ -1087,7 +1089,7 @@ class $$PlayerTableTableTableManager p0, ).playerGroupTableRefs, referencedItemsForCurrentItem: (item, referencedItems) => - referencedItems.where((e) => e.userId == item.id), + referencedItems.where((e) => e.playerId == item.id), typedResults: items, ), ]; @@ -1358,13 +1360,13 @@ typedef $$GroupTableTableProcessedTableManager = >; 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 +1384,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 +1432,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 +1488,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 +1544,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 +1604,7 @@ class $$PlayerGroupTableTableTableManager $$PlayerGroupTableTableUpdateCompanionBuilder, (PlayerGroupTableData, $$PlayerGroupTableTableReferences), PlayerGroupTableData, - PrefetchHooks Function({bool userId, bool groupId}) + PrefetchHooks Function({bool playerId, bool groupId}) > { $$PlayerGroupTableTableTableManager( _$AppDatabase db, @@ -1619,21 +1621,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 +1647,7 @@ class $$PlayerGroupTableTableTableManager ), ) .toList(), - prefetchHooksCallback: ({userId = false, groupId = false}) { + prefetchHooksCallback: ({playerId = false, groupId = false}) { return PrefetchHooks( db: db, explicitlyWatchedTables: [], @@ -1665,17 +1667,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,7 +1721,7 @@ typedef $$PlayerGroupTableTableProcessedTableManager = $$PlayerGroupTableTableUpdateCompanionBuilder, (PlayerGroupTableData, $$PlayerGroupTableTableReferences), PlayerGroupTableData, - PrefetchHooks Function({bool userId, bool groupId}) + PrefetchHooks Function({bool playerId, bool groupId}) >; typedef $$GameTableTableCreateCompanionBuilder = GameTableCompanion Function({ diff --git a/lib/data/db/tables/player_group_table.dart b/lib/data/db/tables/player_group_table.dart index 096a981..61e2ed8 100644 --- a/lib/data/db/tables/player_group_table.dart +++ b/lib/data/db/tables/player_group_table.dart @@ -3,9 +3,9 @@ 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 playerId => text().references(PlayerTable, #id)(); TextColumn get groupId => text().references(GroupTable, #id)(); @override - Set> get primaryKey => {userId, groupId}; + Set> get primaryKey => {playerId, groupId}; } From a922f24150318995b4bfa4b090cd5e1f6dca977f Mon Sep 17 00:00:00 2001 From: Felix Kirchner Date: Wed, 12 Nov 2025 11:41:06 +0100 Subject: [PATCH 008/141] Added basic structure for game implementation --- lib/data/dao/game_dao.dart | 26 +- lib/data/dao/group_dao.dart | 12 +- lib/data/dao/group_game_dao.dart | 33 + lib/data/dao/group_game_dao.g.dart | 10 + lib/data/dao/player_game_dao.dart | 40 + lib/data/dao/player_game_dao.g.dart | 10 + lib/data/db/database.dart | 22 +- lib/data/db/database.g.dart | 1824 ++++++++++++++++++++- lib/data/db/tables/game_table.dart | 1 + lib/data/db/tables/group_game_table.dart | 11 + lib/data/db/tables/player_game_table.dart | 11 + lib/data/dto/game.dart | 14 +- 12 files changed, 1924 insertions(+), 90 deletions(-) create mode 100644 lib/data/dao/group_game_dao.dart create mode 100644 lib/data/dao/group_game_dao.g.dart create mode 100644 lib/data/dao/player_game_dao.dart create mode 100644 lib/data/dao/player_game_dao.g.dart create mode 100644 lib/data/db/tables/group_game_table.dart create mode 100644 lib/data/db/tables/player_game_table.dart diff --git a/lib/data/dao/game_dao.dart b/lib/data/dao/game_dao.dart index 3b6529a..5894ed5 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'; @@ -16,11 +18,27 @@ class GameDao extends DatabaseAccessor with _$GameDaoMixin { return result.map((row) => Game(id: row.id, name: row.name)).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(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.hasGamePlayers(gameId)) { + players = await db.playerGameDao.getPlayersByGameId(gameId); + } + Group? group; + if (await db.groupGameDao.hasGameGroup(gameId)) { + group = await db.groupGameDao.getGroupByGameId(gameId); + } + + return Game( + id: result.id, + name: result.name, + players: players, + group: group, + winner: result.winnerId, + ); } /// Retrieves the number of games in the database. diff --git a/lib/data/dao/group_dao.dart b/lib/data/dao/group_dao.dart index 7dc144d..a92247a 100644 --- a/lib/data/dao/group_dao.dart +++ b/lib/data/dao/group_dao.dart @@ -19,14 +19,14 @@ class GroupDao extends DatabaseAccessor with _$GroupDaoMixin { .toList(); } - /// 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(String groupId) async { + final query = select(groupTable)..where((g) => g.id.equals(groupId)); final result = await query.getSingle(); - List members = []; - - members = await db.playerGroupDao.getPlayersOfGroupById(id); + List members = await db.playerGroupDao.getPlayersOfGroupById( + groupId, + ); return Group(id: result.id, name: result.name, members: members); } diff --git a/lib/data/dao/group_game_dao.dart b/lib/data/dao/group_game_dao.dart new file mode 100644 index 0000000..851e032 --- /dev/null +++ b/lib/data/dao/group_game_dao.dart @@ -0,0 +1,33 @@ +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(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; + } + + Future getGroupByGameId(String gameId) async { + final result = await (select( + groupGameTable, + )..where((g) => g.gameId.equals(gameId))).getSingle(); + + final group = await db.groupDao.getGroupById(result.groupId); + return group; + } +} 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..f1aa46f --- /dev/null +++ b/lib/data/dao/group_game_dao.g.dart @@ -0,0 +1,10 @@ +// GENERATED CODE - DO NOT MODIFY BY HAND + +part of 'group_game_dao.dart'; + +// ignore_for_file: type=lint +mixin _$GroupGameDaoMixin on DatabaseAccessor { + $PlayerTableTable get playerTable => attachedDatabase.playerTable; + $GroupTableTable get groupTable => attachedDatabase.groupTable; + $GroupGameTableTable get groupGameTable => attachedDatabase.groupGameTable; +} diff --git a/lib/data/dao/player_game_dao.dart b/lib/data/dao/player_game_dao.dart new file mode 100644 index 0000000..c05edd1 --- /dev/null +++ b/lib/data/dao/player_game_dao.dart @@ -0,0 +1,40 @@ +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 hasGamePlayers(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(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(row.playerId), + ); + final players = await Future.wait(futures); + return players.whereType().toList(); + } +} 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..0d5f5e1 --- /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; + $GroupTableTable get groupTable => attachedDatabase.groupTable; + $PlayerGameTableTable get playerGameTable => attachedDatabase.playerGameTable; +} diff --git a/lib/data/db/database.dart b/lib/data/db/database.dart index e35513e..b0662aa 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, + PlayerGroupTable, + PlayerGameTable, + GroupGameTable, + GameTable, + ], + daos: [ + GroupDao, + PlayerDao, + 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 d4e9e94..74efba1 100644 --- a/lib/data/db/database.g.dart +++ b/lib/data/db/database.g.dart @@ -638,6 +638,452 @@ class PlayerGroupTableCompanion extends UpdateCompanion { } } +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)', + ), + ); + 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 group_table (id)', + ), + ); + @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 player_table (id)', + ), + ); + 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 group_table (id)', + ), + ); + @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(); + } +} + class $GameTableTable extends GameTable with TableInfo<$GameTableTable, GameTableData> { @override @@ -662,8 +1108,19 @@ 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, + true, + type: DriftSqlType.string, + requiredDuringInsert: false, + ); + @override + List get $columns => [id, name, winnerId]; @override String get aliasedName => _alias ?? actualTableName; @override @@ -689,6 +1146,12 @@ class $GameTableTable extends GameTable } else if (isInserting) { context.missing(_nameMeta); } + if (data.containsKey('winner_id')) { + context.handle( + _winnerIdMeta, + winnerId.isAcceptableOrUnknown(data['winner_id']!, _winnerIdMeta), + ); + } return context; } @@ -706,6 +1169,10 @@ class $GameTableTable extends GameTable DriftSqlType.string, data['${effectivePrefix}name'], )!, + winnerId: attachedDatabase.typeMapping.read( + DriftSqlType.string, + data['${effectivePrefix}winner_id'], + ), ); } @@ -718,17 +1185,27 @@ 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; + const GameTableData({required this.id, required this.name, this.winnerId}); @override Map toColumns(bool nullToAbsent) { final map = {}; map['id'] = Variable(id); map['name'] = Variable(name); + if (!nullToAbsent || winnerId != null) { + map['winner_id'] = Variable(winnerId); + } return map; } GameTableCompanion toCompanion(bool nullToAbsent) { - return GameTableCompanion(id: Value(id), name: Value(name)); + return GameTableCompanion( + id: Value(id), + name: Value(name), + winnerId: winnerId == null && nullToAbsent + ? const Value.absent() + : Value(winnerId), + ); } factory GameTableData.fromJson( @@ -739,6 +1216,7 @@ class GameTableData extends DataClass implements Insertable { return GameTableData( id: serializer.fromJson(json['id']), name: serializer.fromJson(json['name']), + winnerId: serializer.fromJson(json['winnerId']), ); } @override @@ -747,15 +1225,24 @@ class GameTableData extends DataClass implements Insertable { return { 'id': serializer.toJson(id), 'name': serializer.toJson(name), + 'winnerId': serializer.toJson(winnerId), }; } - GameTableData copyWith({String? id, String? name}) => - GameTableData(id: id ?? this.id, name: name ?? this.name); + GameTableData copyWith({ + String? id, + String? name, + Value winnerId = const Value.absent(), + }) => GameTableData( + id: id ?? this.id, + name: name ?? this.name, + winnerId: winnerId.present ? winnerId.value : this.winnerId, + ); 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, ); } @@ -763,44 +1250,51 @@ class GameTableData extends DataClass implements Insertable { String toString() { return (StringBuffer('GameTableData(') ..write('id: $id, ') - ..write('name: $name') + ..write('name: $name, ') + ..write('winnerId: $winnerId') ..write(')')) .toString(); } @override - int get hashCode => Object.hash(id, name); + int get hashCode => Object.hash(id, name, winnerId); @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); } class GameTableCompanion extends UpdateCompanion { final Value id; final Value name; + final Value winnerId; final Value rowid; const GameTableCompanion({ this.id = const Value.absent(), this.name = const Value.absent(), + this.winnerId = const Value.absent(), this.rowid = const Value.absent(), }); GameTableCompanion.insert({ required String id, required String name, + this.winnerId = const Value.absent(), this.rowid = const Value.absent(), }) : id = Value(id), name = Value(name); static Insertable custom({ Expression? id, Expression? name, + Expression? winnerId, Expression? rowid, }) { return RawValuesInsertable({ if (id != null) 'id': id, if (name != null) 'name': name, + if (winnerId != null) 'winner_id': winnerId, if (rowid != null) 'rowid': rowid, }); } @@ -808,11 +1302,13 @@ class GameTableCompanion extends UpdateCompanion { GameTableCompanion copyWith({ Value? id, Value? name, + Value? winnerId, Value? rowid, }) { return GameTableCompanion( id: id ?? this.id, name: name ?? this.name, + winnerId: winnerId ?? this.winnerId, rowid: rowid ?? this.rowid, ); } @@ -826,6 +1322,9 @@ class GameTableCompanion extends UpdateCompanion { if (name.present) { map['name'] = Variable(name.value); } + if (winnerId.present) { + map['winner_id'] = Variable(winnerId.value); + } if (rowid.present) { map['rowid'] = Variable(rowid.value); } @@ -837,6 +1336,7 @@ class GameTableCompanion extends UpdateCompanion { return (StringBuffer('GameTableCompanion(') ..write('id: $id, ') ..write('name: $name, ') + ..write('winnerId: $winnerId, ') ..write('rowid: $rowid') ..write(')')) .toString(); @@ -851,13 +1351,19 @@ abstract class _$AppDatabase extends GeneratedDatabase { late final $PlayerGroupTableTable playerGroupTable = $PlayerGroupTableTable( this, ); + late final $PlayerGameTableTable playerGameTable = $PlayerGameTableTable( + this, + ); + late final $GroupGameTableTable groupGameTable = $GroupGameTableTable(this); late final $GameTableTable gameTable = $GameTableTable(this); late final GroupDao groupDao = GroupDao(this as AppDatabase); late final PlayerDao playerDao = PlayerDao(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>(); @@ -866,6 +1372,8 @@ abstract class _$AppDatabase extends GeneratedDatabase { playerTable, groupTable, playerGroupTable, + playerGameTable, + groupGameTable, gameTable, ]; } @@ -909,6 +1417,50 @@ 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), + ); + } + + static MultiTypedResultKey<$GroupGameTableTable, List> + _groupGameTableRefsTable(_$AppDatabase db) => MultiTypedResultKey.fromTable( + db.groupGameTable, + aliasName: $_aliasNameGenerator( + db.playerTable.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 $$PlayerTableTableFilterComposer @@ -954,6 +1506,56 @@ 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); + } + + 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 $$PlayerTableTableOrderingComposer @@ -1015,6 +1617,56 @@ 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); + } + + 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 $$PlayerTableTableTableManager @@ -1030,7 +1682,11 @@ class $$PlayerTableTableTableManager $$PlayerTableTableUpdateCompanionBuilder, (PlayerTableData, $$PlayerTableTableReferences), PlayerTableData, - PrefetchHooks Function({bool playerGroupTableRefs}) + PrefetchHooks Function({ + bool playerGroupTableRefs, + bool playerGameTableRefs, + bool groupGameTableRefs, + }) > { $$PlayerTableTableTableManager(_$AppDatabase db, $PlayerTableTable table) : super( @@ -1064,38 +1720,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.playerId == item.id), - typedResults: items, - ), - ]; + prefetchHooksCallback: + ({ + playerGroupTableRefs = false, + playerGameTableRefs = false, + groupGameTableRefs = false, + }) { + return PrefetchHooks( + db: db, + explicitlyWatchedTables: [ + if (playerGroupTableRefs) db.playerGroupTable, + if (playerGameTableRefs) db.playerGameTable, + if (groupGameTableRefs) db.groupGameTable, + ], + 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.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, + ), + if (groupGameTableRefs) + await $_getPrefetchedData< + PlayerTableData, + $PlayerTableTable, + GroupGameTableData + >( + currentTable: table, + referencedTable: $$PlayerTableTableReferences + ._groupGameTableRefsTable(db), + managerFromTypedResult: (p0) => + $$PlayerTableTableReferences( + db, + table, + p0, + ).groupGameTableRefs, + referencedItemsForCurrentItem: + (item, referencedItems) => referencedItems.where( + (e) => e.groupId == item.id, + ), + typedResults: items, + ), + ]; + }, + ); }, - ); - }, ), ); } @@ -1112,7 +1819,11 @@ typedef $$PlayerTableTableProcessedTableManager = $$PlayerTableTableUpdateCompanionBuilder, (PlayerTableData, $$PlayerTableTableReferences), PlayerTableData, - PrefetchHooks Function({bool playerGroupTableRefs}) + PrefetchHooks Function({ + bool playerGroupTableRefs, + bool playerGameTableRefs, + bool groupGameTableRefs, + }) >; typedef $$GroupTableTableCreateCompanionBuilder = GroupTableCompanion Function({ @@ -1153,6 +1864,47 @@ final class $$GroupTableTableReferences manager.$state.copyWith(prefetchedData: cache), ); } + + static MultiTypedResultKey<$PlayerGameTableTable, List> + _playerGameTableRefsTable(_$AppDatabase db) => MultiTypedResultKey.fromTable( + db.playerGameTable, + aliasName: $_aliasNameGenerator( + db.groupTable.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.groupTable.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 $$GroupTableTableFilterComposer @@ -1198,6 +1950,56 @@ class $$GroupTableTableFilterComposer ); 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.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 $$GroupTableTableOrderingComposer @@ -1259,6 +2061,56 @@ class $$GroupTableTableAnnotationComposer ); 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.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 $$GroupTableTableTableManager @@ -1274,7 +2126,11 @@ class $$GroupTableTableTableManager $$GroupTableTableUpdateCompanionBuilder, (GroupTableData, $$GroupTableTableReferences), GroupTableData, - PrefetchHooks Function({bool playerGroupTableRefs}) + PrefetchHooks Function({ + bool playerGroupTableRefs, + bool playerGameTableRefs, + bool groupGameTableRefs, + }) > { $$GroupTableTableTableManager(_$AppDatabase db, $GroupTableTable table) : super( @@ -1308,38 +2164,89 @@ 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, + playerGameTableRefs = false, + groupGameTableRefs = false, + }) { + return PrefetchHooks( + db: db, + explicitlyWatchedTables: [ + if (playerGroupTableRefs) db.playerGroupTable, + if (playerGameTableRefs) db.playerGameTable, + 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 (playerGameTableRefs) + await $_getPrefetchedData< + GroupTableData, + $GroupTableTable, + PlayerGameTableData + >( + currentTable: table, + referencedTable: $$GroupTableTableReferences + ._playerGameTableRefsTable(db), + managerFromTypedResult: (p0) => + $$GroupTableTableReferences( + db, + table, + p0, + ).playerGameTableRefs, + referencedItemsForCurrentItem: + (item, referencedItems) => referencedItems.where( + (e) => e.gameId == 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.gameId == item.id, + ), + typedResults: items, + ), + ]; + }, + ); }, - ); - }, ), ); } @@ -1356,7 +2263,11 @@ typedef $$GroupTableTableProcessedTableManager = $$GroupTableTableUpdateCompanionBuilder, (GroupTableData, $$GroupTableTableReferences), GroupTableData, - PrefetchHooks Function({bool playerGroupTableRefs}) + PrefetchHooks Function({ + bool playerGroupTableRefs, + bool playerGameTableRefs, + bool groupGameTableRefs, + }) >; typedef $$PlayerGroupTableTableCreateCompanionBuilder = PlayerGroupTableCompanion Function({ @@ -1723,16 +2634,746 @@ typedef $$PlayerGroupTableTableProcessedTableManager = PlayerGroupTableData, PrefetchHooks Function({bool playerId, bool groupId}) >; +typedef $$PlayerGameTableTableCreateCompanionBuilder = + PlayerGameTableCompanion Function({ + required String playerId, + required String gameId, + Value rowid, + }); +typedef $$PlayerGameTableTableUpdateCompanionBuilder = + PlayerGameTableCompanion Function({ + Value playerId, + Value gameId, + Value rowid, + }); + +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 $GroupTableTable _gameIdTable(_$AppDatabase db) => + db.groupTable.createAlias( + $_aliasNameGenerator(db.playerGameTable.gameId, db.groupTable.id), + ); + + $$GroupTableTableProcessedTableManager get gameId { + final $_column = $_itemColumn('game_id')!; + + final manager = $$GroupTableTableTableManager( + $_db, + $_db.groupTable, + ).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, + }); + $$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; + } + + $$GroupTableTableFilterComposer get gameId { + final $$GroupTableTableFilterComposer composer = $composerBuilder( + composer: this, + getCurrentColumn: (t) => t.gameId, + 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; + } +} + +class $$PlayerGameTableTableOrderingComposer + extends Composer<_$AppDatabase, $PlayerGameTableTable> { + $$PlayerGameTableTableOrderingComposer({ + required super.$db, + required super.$table, + super.joinBuilder, + super.$addJoinBuilderToRootComposer, + super.$removeJoinBuilderFromRootComposer, + }); + $$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; + } + + $$GroupTableTableOrderingComposer get gameId { + final $$GroupTableTableOrderingComposer composer = $composerBuilder( + composer: this, + getCurrentColumn: (t) => t.gameId, + 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; + } +} + +class $$PlayerGameTableTableAnnotationComposer + extends Composer<_$AppDatabase, $PlayerGameTableTable> { + $$PlayerGameTableTableAnnotationComposer({ + required super.$db, + required super.$table, + super.joinBuilder, + super.$addJoinBuilderToRootComposer, + super.$removeJoinBuilderFromRootComposer, + }); + $$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; + } + + $$GroupTableTableAnnotationComposer get gameId { + final $$GroupTableTableAnnotationComposer composer = $composerBuilder( + composer: this, + getCurrentColumn: (t) => t.gameId, + 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; + } +} + +class $$PlayerGameTableTableTableManager + extends + RootTableManager< + _$AppDatabase, + $PlayerGameTableTable, + PlayerGameTableData, + $$PlayerGameTableTableFilterComposer, + $$PlayerGameTableTableOrderingComposer, + $$PlayerGameTableTableAnnotationComposer, + $$PlayerGameTableTableCreateCompanionBuilder, + $$PlayerGameTableTableUpdateCompanionBuilder, + (PlayerGameTableData, $$PlayerGameTableTableReferences), + PlayerGameTableData, + PrefetchHooks Function({bool playerId, bool gameId}) + > { + $$PlayerGameTableTableTableManager( + _$AppDatabase db, + $PlayerGameTableTable table, + ) : super( + TableManagerState( + db: db, + table: table, + createFilteringComposer: () => + $$PlayerGameTableTableFilterComposer($db: db, $table: table), + createOrderingComposer: () => + $$PlayerGameTableTableOrderingComposer($db: db, $table: table), + createComputedFieldComposer: () => + $$PlayerGameTableTableAnnotationComposer($db: db, $table: table), + updateCompanionCallback: + ({ + Value playerId = const Value.absent(), + Value gameId = const Value.absent(), + Value rowid = const Value.absent(), + }) => PlayerGameTableCompanion( + playerId: playerId, + gameId: gameId, + rowid: rowid, + ), + createCompanionCallback: + ({ + required String playerId, + required String gameId, + Value rowid = const Value.absent(), + }) => PlayerGameTableCompanion.insert( + playerId: playerId, + gameId: gameId, + rowid: rowid, + ), + withReferenceMapper: (p0) => p0 + .map( + (e) => ( + e.readTable(table), + $$PlayerGameTableTableReferences(db, table, e), + ), + ) + .toList(), + 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 $$PlayerGameTableTableProcessedTableManager = + ProcessedTableManager< + _$AppDatabase, + $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 $PlayerTableTable _groupIdTable(_$AppDatabase db) => + db.playerTable.createAlias( + $_aliasNameGenerator(db.groupGameTable.groupId, db.playerTable.id), + ); + + $$PlayerTableTableProcessedTableManager get groupId { + final $_column = $_itemColumn('group_id')!; + + final manager = $$PlayerTableTableTableManager( + $_db, + $_db.playerTable, + ).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 $GroupTableTable _gameIdTable(_$AppDatabase db) => + db.groupTable.createAlias( + $_aliasNameGenerator(db.groupGameTable.gameId, db.groupTable.id), + ); + + $$GroupTableTableProcessedTableManager get gameId { + final $_column = $_itemColumn('game_id')!; + + final manager = $$GroupTableTableTableManager( + $_db, + $_db.groupTable, + ).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, + }); + $$PlayerTableTableFilterComposer get groupId { + final $$PlayerTableTableFilterComposer composer = $composerBuilder( + composer: this, + getCurrentColumn: (t) => t.groupId, + 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; + } + + $$GroupTableTableFilterComposer get gameId { + final $$GroupTableTableFilterComposer composer = $composerBuilder( + composer: this, + getCurrentColumn: (t) => t.gameId, + 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; + } +} + +class $$GroupGameTableTableOrderingComposer + extends Composer<_$AppDatabase, $GroupGameTableTable> { + $$GroupGameTableTableOrderingComposer({ + required super.$db, + required super.$table, + super.joinBuilder, + super.$addJoinBuilderToRootComposer, + super.$removeJoinBuilderFromRootComposer, + }); + $$PlayerTableTableOrderingComposer get groupId { + final $$PlayerTableTableOrderingComposer composer = $composerBuilder( + composer: this, + getCurrentColumn: (t) => t.groupId, + 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; + } + + $$GroupTableTableOrderingComposer get gameId { + final $$GroupTableTableOrderingComposer composer = $composerBuilder( + composer: this, + getCurrentColumn: (t) => t.gameId, + 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; + } +} + +class $$GroupGameTableTableAnnotationComposer + extends Composer<_$AppDatabase, $GroupGameTableTable> { + $$GroupGameTableTableAnnotationComposer({ + required super.$db, + required super.$table, + super.joinBuilder, + super.$addJoinBuilderToRootComposer, + super.$removeJoinBuilderFromRootComposer, + }); + $$PlayerTableTableAnnotationComposer get groupId { + final $$PlayerTableTableAnnotationComposer composer = $composerBuilder( + composer: this, + getCurrentColumn: (t) => t.groupId, + 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; + } + + $$GroupTableTableAnnotationComposer get gameId { + final $$GroupTableTableAnnotationComposer composer = $composerBuilder( + composer: this, + getCurrentColumn: (t) => t.gameId, + 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; + } +} + +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}) + >; typedef $$GameTableTableCreateCompanionBuilder = GameTableCompanion Function({ required String id, required String name, + Value winnerId, Value rowid, }); typedef $$GameTableTableUpdateCompanionBuilder = GameTableCompanion Function({ Value id, Value name, + Value winnerId, Value rowid, }); @@ -1754,6 +3395,11 @@ class $$GameTableTableFilterComposer column: $table.name, builder: (column) => ColumnFilters(column), ); + + ColumnFilters get winnerId => $composableBuilder( + column: $table.winnerId, + builder: (column) => ColumnFilters(column), + ); } class $$GameTableTableOrderingComposer @@ -1774,6 +3420,11 @@ class $$GameTableTableOrderingComposer column: $table.name, builder: (column) => ColumnOrderings(column), ); + + ColumnOrderings get winnerId => $composableBuilder( + column: $table.winnerId, + builder: (column) => ColumnOrderings(column), + ); } class $$GameTableTableAnnotationComposer @@ -1790,6 +3441,9 @@ class $$GameTableTableAnnotationComposer GeneratedColumn get name => $composableBuilder(column: $table.name, builder: (column) => column); + + GeneratedColumn get winnerId => + $composableBuilder(column: $table.winnerId, builder: (column) => column); } class $$GameTableTableTableManager @@ -1825,14 +3479,26 @@ class $$GameTableTableTableManager ({ Value id = const Value.absent(), Value name = const Value.absent(), + Value winnerId = const Value.absent(), Value rowid = const Value.absent(), - }) => GameTableCompanion(id: id, name: name, rowid: rowid), + }) => GameTableCompanion( + id: id, + name: name, + winnerId: winnerId, + rowid: rowid, + ), createCompanionCallback: ({ required String id, required String name, + Value winnerId = const Value.absent(), Value rowid = const Value.absent(), - }) => GameTableCompanion.insert(id: id, name: name, rowid: rowid), + }) => GameTableCompanion.insert( + id: id, + name: name, + winnerId: winnerId, + rowid: rowid, + ), withReferenceMapper: (p0) => p0 .map((e) => (e.readTable(table), BaseReferences(db, table, e))) .toList(), @@ -1868,6 +3534,10 @@ class $AppDatabaseManager { $$GroupTableTableTableManager(_db, _db.groupTable); $$PlayerGroupTableTableTableManager get playerGroupTable => $$PlayerGroupTableTableTableManager(_db, _db.playerGroupTable); + $$PlayerGameTableTableTableManager get playerGameTable => + $$PlayerGameTableTableTableManager(_db, _db.playerGameTable); + $$GroupGameTableTableTableManager get groupGameTable => + $$GroupGameTableTableTableManager(_db, _db.groupGameTable); $$GameTableTableTableManager get gameTable => $$GameTableTableTableManager(_db, _db.gameTable); } diff --git a/lib/data/db/tables/game_table.dart b/lib/data/db/tables/game_table.dart index 45bfb20..0772647 100644 --- a/lib/data/db/tables/game_table.dart +++ b/lib/data/db/tables/game_table.dart @@ -3,6 +3,7 @@ import 'package:drift/drift.dart'; class GameTable extends Table { TextColumn get id => text()(); TextColumn get name => text()(); + TextColumn get winnerId => text().nullable()(); @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..f70206f --- /dev/null +++ b/lib/data/db/tables/group_game_table.dart @@ -0,0 +1,11 @@ +import 'package:drift/drift.dart'; +import 'package:game_tracker/data/db/tables/group_table.dart'; +import 'package:game_tracker/data/db/tables/player_table.dart'; + +class GroupGameTable extends Table { + TextColumn get groupId => text().references(PlayerTable, #id)(); + TextColumn get gameId => text().references(GroupTable, #id)(); + + @override + Set> get primaryKey => {groupId, gameId}; +} 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..95ef4db --- /dev/null +++ b/lib/data/db/tables/player_game_table.dart @@ -0,0 +1,11 @@ +import 'package:drift/drift.dart'; +import 'package:game_tracker/data/db/tables/group_table.dart'; +import 'package:game_tracker/data/db/tables/player_table.dart'; + +class PlayerGameTable extends Table { + TextColumn get playerId => text().references(PlayerTable, #id)(); + TextColumn get gameId => text().references(GroupTable, #id)(); + + @override + Set> get primaryKey => {playerId, gameId}; +} diff --git a/lib/data/dto/game.dart b/lib/data/dto/game.dart index 7457b54..2c09851 100644 --- a/lib/data/dto/game.dart +++ b/lib/data/dto/game.dart @@ -1,6 +1,18 @@ +import 'package:game_tracker/data/dto/group.dart'; +import 'package:game_tracker/data/dto/player.dart'; + class Game { final String id; final String name; + final List? players; + final Group? group; + final String? winner; - Game({required this.id, required this.name}); + Game({ + this.players, + this.group, + this.winner, + required this.id, + required this.name, + }); } From b6700bafd9c7441de21eae4c98ba17248b742dd0 Mon Sep 17 00:00:00 2001 From: Felix Kirchner Date: Wed, 12 Nov 2025 12:03:08 +0100 Subject: [PATCH 009/141] Added on delete cascade --- lib/data/db/tables/group_game_table.dart | 6 ++++-- lib/data/db/tables/player_game_table.dart | 6 ++++-- lib/data/db/tables/player_group_table.dart | 6 ++++-- 3 files changed, 12 insertions(+), 6 deletions(-) diff --git a/lib/data/db/tables/group_game_table.dart b/lib/data/db/tables/group_game_table.dart index f70206f..6be12bc 100644 --- a/lib/data/db/tables/group_game_table.dart +++ b/lib/data/db/tables/group_game_table.dart @@ -3,8 +3,10 @@ import 'package:game_tracker/data/db/tables/group_table.dart'; import 'package:game_tracker/data/db/tables/player_table.dart'; class GroupGameTable extends Table { - TextColumn get groupId => text().references(PlayerTable, #id)(); - TextColumn get gameId => text().references(GroupTable, #id)(); + TextColumn get groupId => + text().references(PlayerTable, #id, onDelete: KeyAction.cascade)(); + TextColumn get gameId => + text().references(GroupTable, #id, onDelete: KeyAction.cascade)(); @override Set> get primaryKey => {groupId, gameId}; diff --git a/lib/data/db/tables/player_game_table.dart b/lib/data/db/tables/player_game_table.dart index 95ef4db..79b6df2 100644 --- a/lib/data/db/tables/player_game_table.dart +++ b/lib/data/db/tables/player_game_table.dart @@ -3,8 +3,10 @@ import 'package:game_tracker/data/db/tables/group_table.dart'; import 'package:game_tracker/data/db/tables/player_table.dart'; class PlayerGameTable extends Table { - TextColumn get playerId => text().references(PlayerTable, #id)(); - TextColumn get gameId => text().references(GroupTable, #id)(); + TextColumn get playerId => + text().references(PlayerTable, #id, onDelete: KeyAction.cascade)(); + TextColumn get gameId => + text().references(GroupTable, #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 61e2ed8..da2521b 100644 --- a/lib/data/db/tables/player_group_table.dart +++ b/lib/data/db/tables/player_group_table.dart @@ -3,8 +3,10 @@ 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 playerId => 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 => {playerId, groupId}; From d07943add9ed0146f6ff611c4026cbf114052ca0 Mon Sep 17 00:00:00 2001 From: Felix Kirchner Date: Wed, 12 Nov 2025 12:04:33 +0100 Subject: [PATCH 010/141] Added methods for inserting games and groups into the db --- lib/data/dao/game_dao.dart | 21 +++++++++++++++++++++ lib/data/dao/group_dao.dart | 25 ++++++++++++++++++++----- lib/data/dao/group_game_dao.dart | 8 ++++++++ lib/data/dao/player_game_dao.dart | 8 ++++++++ lib/data/db/tables/game_table.dart | 1 + 5 files changed, 58 insertions(+), 5 deletions(-) diff --git a/lib/data/dao/game_dao.dart b/lib/data/dao/game_dao.dart index 5894ed5..ba9c7df 100644 --- a/lib/data/dao/game_dao.dart +++ b/lib/data/dao/game_dao.dart @@ -41,6 +41,27 @@ class GameDao extends DatabaseAccessor with _$GameDaoMixin { ); } + Future addGame(Game game) async { + await db.transaction(() async { + for (final p in game.players ?? []) { + await db.playerDao.addPlayer(p); + await db.playerGameDao.addPlayerToGame(game.id, p.id); + } + if (game.group != null) { + await db.groupDao.addGroup(game.group!); + await db.groupGameDao.addGroupToGame(game.id, game.group!.id); + } + await into(gameTable).insert( + GameTableCompanion.insert( + id: game.id, + name: game.name, + winnerId: Value(game.winner), + ), + mode: InsertMode.insertOrReplace, + ); + }); + } + /// Retrieves the number of games in the database. Future getGameCount() async { final count = diff --git a/lib/data/dao/group_dao.dart b/lib/data/dao/group_dao.dart index a92247a..ace60c4 100644 --- a/lib/data/dao/group_dao.dart +++ b/lib/data/dao/group_dao.dart @@ -32,11 +32,26 @@ class GroupDao extends DatabaseAccessor with _$GroupDaoMixin { } /// 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(Group group) async { + await db.transaction(() async { + await into( + groupTable, + ).insert(GroupTableCompanion.insert(id: group.id, name: group.name)); + await db.batch( + (b) => b.insertAll( + db.playerGroupTable, + group.members + .map( + (member) => PlayerGroupTableCompanion.insert( + playerId: member.id, + groupId: group.id, + ), + ) + .toList(), + ), + ); + }); } /// Deletes the group with the given [id] from the database. diff --git a/lib/data/dao/group_game_dao.dart b/lib/data/dao/group_game_dao.dart index 851e032..b29db1c 100644 --- a/lib/data/dao/group_game_dao.dart +++ b/lib/data/dao/group_game_dao.dart @@ -30,4 +30,12 @@ class GroupGameDao extends DatabaseAccessor final group = await db.groupDao.getGroupById(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/player_game_dao.dart b/lib/data/dao/player_game_dao.dart index c05edd1..e597462 100644 --- a/lib/data/dao/player_game_dao.dart +++ b/lib/data/dao/player_game_dao.dart @@ -37,4 +37,12 @@ class PlayerGameDao extends DatabaseAccessor 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(String gameId, String playerId) async { + await into(playerGameTable).insert( + PlayerGameTableCompanion.insert(playerId: playerId, gameId: gameId), + ); + } } diff --git a/lib/data/db/tables/game_table.dart b/lib/data/db/tables/game_table.dart index 0772647..2c42213 100644 --- a/lib/data/db/tables/game_table.dart +++ b/lib/data/db/tables/game_table.dart @@ -3,6 +3,7 @@ import 'package:drift/drift.dart'; class GameTable extends Table { TextColumn get id => text()(); TextColumn get name => text()(); + // todo: winner id needs to be deleted when corresponding player gets deleted TextColumn get winnerId => text().nullable()(); @override From ca40ae668dc2f4e5a32d1c0b3e0d9c950d8280d3 Mon Sep 17 00:00:00 2001 From: Felix Kirchner Date: Wed, 12 Nov 2025 13:11:48 +0100 Subject: [PATCH 011/141] Updated methods with named parameters --- lib/data/dao/game_dao.dart | 20 +++++++++-------- lib/data/dao/group_dao.dart | 15 ++++++++----- lib/data/dao/group_game_dao.dart | 6 ++--- lib/data/dao/player_dao.dart | 35 +++++++++++++++++++----------- lib/data/dao/player_game_dao.dart | 11 ++++++---- lib/data/dao/player_group_dao.dart | 14 ++++++++---- 6 files changed, 62 insertions(+), 39 deletions(-) diff --git a/lib/data/dao/game_dao.dart b/lib/data/dao/game_dao.dart index ba9c7df..775c509 100644 --- a/lib/data/dao/game_dao.dart +++ b/lib/data/dao/game_dao.dart @@ -19,17 +19,17 @@ class GameDao extends DatabaseAccessor with _$GameDaoMixin { } /// Retrieves a [Game] by its [gameId]. - Future getGameById(String gameId) async { + Future getGameById({required String gameId}) async { final query = select(gameTable)..where((g) => g.id.equals(gameId)); final result = await query.getSingle(); List? players; - if (await db.playerGameDao.hasGamePlayers(gameId)) { - players = await db.playerGameDao.getPlayersByGameId(gameId); + if (await db.playerGameDao.hasGamePlayers(gameId: gameId)) { + players = await db.playerGameDao.getPlayersByGameId(gameId: gameId); } Group? group; - if (await db.groupGameDao.hasGameGroup(gameId)) { - group = await db.groupGameDao.getGroupByGameId(gameId); + if (await db.groupGameDao.hasGameGroup(gameId: gameId)) { + group = await db.groupGameDao.getGroupByGameId(gameId: gameId); } return Game( @@ -41,14 +41,16 @@ class GameDao extends DatabaseAccessor with _$GameDaoMixin { ); } - Future addGame(Game game) async { + /// 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(p); - await db.playerGameDao.addPlayerToGame(game.id, p.id); + await db.playerDao.addPlayer(player: p); + await db.playerGameDao.addPlayerToGame(gameId: game.id, playerId: p.id); } if (game.group != null) { - await db.groupDao.addGroup(game.group!); + await db.groupDao.addGroup(group: game.group!); await db.groupGameDao.addGroupToGame(game.id, game.group!.id); } await into(gameTable).insert( diff --git a/lib/data/dao/group_dao.dart b/lib/data/dao/group_dao.dart index ace60c4..d449326 100644 --- a/lib/data/dao/group_dao.dart +++ b/lib/data/dao/group_dao.dart @@ -20,12 +20,12 @@ class GroupDao extends DatabaseAccessor with _$GroupDaoMixin { } /// Retrieves a [Group] by its [groupId], including its members. - Future getGroupById(String groupId) async { + Future getGroupById({required String groupId}) async { final query = select(groupTable)..where((g) => g.id.equals(groupId)); final result = await query.getSingle(); List members = await db.playerGroupDao.getPlayersOfGroupById( - groupId, + groupId: groupId, ); return Group(id: result.id, name: result.name, members: members); @@ -33,7 +33,7 @@ class GroupDao extends DatabaseAccessor with _$GroupDaoMixin { /// Adds a new group with the given [id] and [name] to the database. /// This method also adds the group's members to the [PlayerGroupTable]. - Future addGroup(Group group) async { + Future addGroup({required Group group}) async { await db.transaction(() async { await into( groupTable, @@ -56,15 +56,18 @@ class GroupDao extends DatabaseAccessor with _$GroupDaoMixin { /// 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 id, + required String newName, + }) async { final rowsAffected = await (update(groupTable)..where((g) => g.id.equals(id))).write( GroupTableCompanion(name: Value(newName)), diff --git a/lib/data/dao/group_game_dao.dart b/lib/data/dao/group_game_dao.dart index b29db1c..88b8fad 100644 --- a/lib/data/dao/group_game_dao.dart +++ b/lib/data/dao/group_game_dao.dart @@ -12,7 +12,7 @@ class GroupGameDao extends DatabaseAccessor /// Checks if there is a group associated with the given [gameId]. /// Returns `true` if there is a group, otherwise `false`. - Future hasGameGroup(String gameId) async { + Future hasGameGroup({required String gameId}) async { final count = await (selectOnly(groupGameTable) ..where(groupGameTable.gameId.equals(gameId)) @@ -22,12 +22,12 @@ class GroupGameDao extends DatabaseAccessor return (count ?? 0) > 0; } - Future getGroupByGameId(String gameId) async { + Future getGroupByGameId({required String gameId}) async { final result = await (select( groupGameTable, )..where((g) => g.gameId.equals(gameId))).getSingle(); - final group = await db.groupDao.getGroupById(result.groupId); + final group = await db.groupDao.getGroupById(groupId: result.groupId); return group; } diff --git a/lib/data/dao/player_dao.dart b/lib/data/dao/player_dao.dart index 2d3c0ab..01e7163 100644 --- a/lib/data/dao/player_dao.dart +++ b/lib/data/dao/player_dao.dart @@ -17,38 +17,47 @@ class PlayerDao extends DatabaseAccessor with _$PlayerDaoMixin { } /// 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); } /// 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)); + } else { + await updatePlayername(playerId: player.id, newName: player.name); + } } /// 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)), ); } diff --git a/lib/data/dao/player_game_dao.dart b/lib/data/dao/player_game_dao.dart index e597462..333dc28 100644 --- a/lib/data/dao/player_game_dao.dart +++ b/lib/data/dao/player_game_dao.dart @@ -12,7 +12,7 @@ class PlayerGameDao extends DatabaseAccessor /// Checks if there are any players associated with the given [gameId]. /// Returns `true` if there are players, otherwise `false`. - Future hasGamePlayers(String gameId) async { + Future hasGamePlayers({required String gameId}) async { final count = await (selectOnly(playerGameTable) ..where(playerGameTable.gameId.equals(gameId)) @@ -24,7 +24,7 @@ class PlayerGameDao extends DatabaseAccessor /// Retrieves a list of [Player]s associated with the given [gameId]. /// Returns an empty list if no players are found. - Future> getPlayersByGameId(String gameId) async { + Future> getPlayersByGameId({required String gameId}) async { final result = await (select( playerGameTable, )..where((p) => p.gameId.equals(gameId))).get(); @@ -32,7 +32,7 @@ class PlayerGameDao extends DatabaseAccessor if (result.isEmpty) return []; final futures = result.map( - (row) => db.playerDao.getPlayerById(row.playerId), + (row) => db.playerDao.getPlayerById(playerId: row.playerId), ); final players = await Future.wait(futures); return players.whereType().toList(); @@ -40,7 +40,10 @@ class PlayerGameDao extends DatabaseAccessor /// Associates a player with a game by inserting a record into the /// [PlayerGameTable]. - Future addPlayerToGame(String gameId, String playerId) async { + 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_group_dao.dart b/lib/data/dao/player_group_dao.dart index e51c325..5b2a095 100644 --- a/lib/data/dao/player_group_dao.dart +++ b/lib/data/dao/player_group_dao.dart @@ -11,7 +11,7 @@ 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(); @@ -19,7 +19,7 @@ class PlayerGroupDao extends DatabaseAccessor List groupMembers = []; for (var entry in result) { - final player = await db.playerDao.getPlayerById(entry.playerId); + final player = await db.playerDao.getPlayerById(playerId: entry.playerId); groupMembers.add(player); } @@ -28,7 +28,10 @@ class PlayerGroupDao extends DatabaseAccessor /// 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 playerId, String groupId) async { + Future removePlayerFromGroup({ + required String playerId, + required String groupId, + }) async { final query = delete(playerGroupTable) ..where((p) => p.playerId.equals(playerId) & p.groupId.equals(groupId)); final rowsAffected = await query.go(); @@ -36,7 +39,10 @@ class PlayerGroupDao extends DatabaseAccessor } /// Adds a player to a group with the given [playerId] and [groupId]. - Future addPlayerToGroup(String playerId, String groupId) async { + Future addPlayerToGroup({ + required String playerId, + required String groupId, + }) async { await into(playerGroupTable).insert( PlayerGroupTableCompanion.insert(playerId: playerId, groupId: groupId), ); From ac99217b72f8c7cba43bf68bf58f6a7b9c52f776 Mon Sep 17 00:00:00 2001 From: Felix Kirchner Date: Wed, 12 Nov 2025 13:12:26 +0100 Subject: [PATCH 012/141] Added reference on winner --- lib/data/db/tables/game_table.dart | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/lib/data/db/tables/game_table.dart b/lib/data/db/tables/game_table.dart index 2c42213..9651a79 100644 --- a/lib/data/db/tables/game_table.dart +++ b/lib/data/db/tables/game_table.dart @@ -1,10 +1,11 @@ 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()(); - // todo: winner id needs to be deleted when corresponding player gets deleted - TextColumn get winnerId => text().nullable()(); + TextColumn get winnerId => + text().references(PlayerTable, #id, onDelete: KeyAction.cascade)(); @override Set> get primaryKey => {id}; From 67d5f7e8919cf1c60c5c770005300166dac89bc8 Mon Sep 17 00:00:00 2001 From: Felix Kirchner Date: Wed, 12 Nov 2025 20:01:31 +0100 Subject: [PATCH 013/141] Updated order --- lib/data/db/database.dart | 4 +- lib/data/db/database.g.dart | 1369 +++++++++++++++++++++-------------- 2 files changed, 817 insertions(+), 556 deletions(-) diff --git a/lib/data/db/database.dart b/lib/data/db/database.dart index b0662aa..73ad73e 100644 --- a/lib/data/db/database.dart +++ b/lib/data/db/database.dart @@ -20,14 +20,14 @@ part 'database.g.dart'; tables: [ PlayerTable, GroupTable, + GameTable, PlayerGroupTable, PlayerGameTable, GroupGameTable, - GameTable, ], daos: [ - GroupDao, PlayerDao, + GroupDao, GameDao, PlayerGroupDao, PlayerGameDao, diff --git a/lib/data/db/database.g.dart b/lib/data/db/database.g.dart index 74efba1..453fcb0 100644 --- a/lib/data/db/database.g.dart +++ b/lib/data/db/database.g.dart @@ -413,6 +413,268 @@ class GroupTableCompanion extends UpdateCompanion { } } +class $GameTableTable extends GameTable + with TableInfo<$GameTableTable, GameTableData> { + @override + final GeneratedDatabase attachedDatabase; + final String? _alias; + $GameTableTable(this.attachedDatabase, [this._alias]); + static const VerificationMeta _idMeta = const VerificationMeta('id'); + @override + late final GeneratedColumn id = GeneratedColumn( + 'id', + aliasedName, + false, + type: DriftSqlType.string, + requiredDuringInsert: true, + ); + static const VerificationMeta _nameMeta = const VerificationMeta('name'); + @override + late final GeneratedColumn name = GeneratedColumn( + 'name', + aliasedName, + false, + type: DriftSqlType.string, + requiredDuringInsert: true, + ); + static const VerificationMeta _winnerIdMeta = const VerificationMeta( + 'winnerId', + ); + @override + late final GeneratedColumn winnerId = GeneratedColumn( + 'winner_id', + aliasedName, + false, + type: DriftSqlType.string, + requiredDuringInsert: true, + defaultConstraints: GeneratedColumn.constraintIsAlways( + 'REFERENCES player_table (id) ON DELETE CASCADE', + ), + ); + @override + List get $columns => [id, name, winnerId]; + @override + String get aliasedName => _alias ?? actualTableName; + @override + String get actualTableName => $name; + static const String $name = 'game_table'; + @override + VerificationContext validateIntegrity( + Insertable instance, { + bool isInserting = false, + }) { + final context = VerificationContext(); + final data = instance.toColumns(true); + if (data.containsKey('id')) { + context.handle(_idMeta, id.isAcceptableOrUnknown(data['id']!, _idMeta)); + } else if (isInserting) { + context.missing(_idMeta); + } + if (data.containsKey('name')) { + context.handle( + _nameMeta, + name.isAcceptableOrUnknown(data['name']!, _nameMeta), + ); + } 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); + } + return context; + } + + @override + Set get $primaryKey => {id}; + @override + GameTableData map(Map data, {String? tablePrefix}) { + final effectivePrefix = tablePrefix != null ? '$tablePrefix.' : ''; + return GameTableData( + id: attachedDatabase.typeMapping.read( + DriftSqlType.string, + data['${effectivePrefix}id'], + )!, + name: attachedDatabase.typeMapping.read( + DriftSqlType.string, + data['${effectivePrefix}name'], + )!, + winnerId: attachedDatabase.typeMapping.read( + DriftSqlType.string, + data['${effectivePrefix}winner_id'], + )!, + ); + } + + @override + $GameTableTable createAlias(String alias) { + return $GameTableTable(attachedDatabase, alias); + } +} + +class GameTableData extends DataClass implements Insertable { + final String id; + final String name; + final String winnerId; + const GameTableData({ + required this.id, + required this.name, + required this.winnerId, + }); + @override + Map toColumns(bool nullToAbsent) { + final map = {}; + map['id'] = Variable(id); + map['name'] = Variable(name); + map['winner_id'] = Variable(winnerId); + return map; + } + + GameTableCompanion toCompanion(bool nullToAbsent) { + return GameTableCompanion( + id: Value(id), + name: Value(name), + winnerId: Value(winnerId), + ); + } + + factory GameTableData.fromJson( + Map json, { + ValueSerializer? serializer, + }) { + serializer ??= driftRuntimeOptions.defaultSerializer; + return GameTableData( + id: serializer.fromJson(json['id']), + name: serializer.fromJson(json['name']), + winnerId: serializer.fromJson(json['winnerId']), + ); + } + @override + Map toJson({ValueSerializer? serializer}) { + serializer ??= driftRuntimeOptions.defaultSerializer; + return { + 'id': serializer.toJson(id), + 'name': serializer.toJson(name), + 'winnerId': serializer.toJson(winnerId), + }; + } + + GameTableData copyWith({String? id, String? name, String? winnerId}) => + GameTableData( + id: id ?? this.id, + name: name ?? this.name, + winnerId: winnerId ?? this.winnerId, + ); + 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, + ); + } + + @override + String toString() { + return (StringBuffer('GameTableData(') + ..write('id: $id, ') + ..write('name: $name, ') + ..write('winnerId: $winnerId') + ..write(')')) + .toString(); + } + + @override + int get hashCode => Object.hash(id, name, winnerId); + @override + bool operator ==(Object other) => + identical(this, other) || + (other is GameTableData && + other.id == this.id && + other.name == this.name && + other.winnerId == this.winnerId); +} + +class GameTableCompanion extends UpdateCompanion { + final Value id; + final Value name; + final Value winnerId; + final Value rowid; + const GameTableCompanion({ + this.id = const Value.absent(), + this.name = const Value.absent(), + this.winnerId = const Value.absent(), + this.rowid = const Value.absent(), + }); + GameTableCompanion.insert({ + required String id, + required String name, + required String winnerId, + this.rowid = const Value.absent(), + }) : id = Value(id), + name = Value(name), + winnerId = Value(winnerId); + static Insertable custom({ + Expression? id, + Expression? name, + Expression? winnerId, + Expression? rowid, + }) { + return RawValuesInsertable({ + if (id != null) 'id': id, + if (name != null) 'name': name, + if (winnerId != null) 'winner_id': winnerId, + if (rowid != null) 'rowid': rowid, + }); + } + + GameTableCompanion copyWith({ + Value? id, + Value? name, + Value? winnerId, + Value? rowid, + }) { + return GameTableCompanion( + id: id ?? this.id, + name: name ?? this.name, + winnerId: winnerId ?? this.winnerId, + rowid: rowid ?? this.rowid, + ); + } + + @override + Map toColumns(bool nullToAbsent) { + final map = {}; + if (id.present) { + map['id'] = Variable(id.value); + } + if (name.present) { + map['name'] = Variable(name.value); + } + if (winnerId.present) { + map['winner_id'] = Variable(winnerId.value); + } + if (rowid.present) { + map['rowid'] = Variable(rowid.value); + } + return map; + } + + @override + String toString() { + return (StringBuffer('GameTableCompanion(') + ..write('id: $id, ') + ..write('name: $name, ') + ..write('winnerId: $winnerId, ') + ..write('rowid: $rowid') + ..write(')')) + .toString(); + } +} + class $PlayerGroupTableTable extends PlayerGroupTable with TableInfo<$PlayerGroupTableTable, PlayerGroupTableData> { @override @@ -430,7 +692,7 @@ class $PlayerGroupTableTable extends PlayerGroupTable type: DriftSqlType.string, requiredDuringInsert: true, defaultConstraints: GeneratedColumn.constraintIsAlways( - 'REFERENCES player_table (id)', + 'REFERENCES player_table (id) ON DELETE CASCADE', ), ); static const VerificationMeta _groupIdMeta = const VerificationMeta( @@ -444,7 +706,7 @@ class $PlayerGroupTableTable extends PlayerGroupTable type: DriftSqlType.string, requiredDuringInsert: true, defaultConstraints: GeneratedColumn.constraintIsAlways( - 'REFERENCES group_table (id)', + 'REFERENCES group_table (id) ON DELETE CASCADE', ), ); @override @@ -655,7 +917,7 @@ class $PlayerGameTableTable extends PlayerGameTable type: DriftSqlType.string, requiredDuringInsert: true, defaultConstraints: GeneratedColumn.constraintIsAlways( - 'REFERENCES player_table (id)', + 'REFERENCES player_table (id) ON DELETE CASCADE', ), ); static const VerificationMeta _gameIdMeta = const VerificationMeta('gameId'); @@ -667,7 +929,7 @@ class $PlayerGameTableTable extends PlayerGameTable type: DriftSqlType.string, requiredDuringInsert: true, defaultConstraints: GeneratedColumn.constraintIsAlways( - 'REFERENCES group_table (id)', + 'REFERENCES game_table (id) ON DELETE CASCADE', ), ); @override @@ -878,7 +1140,7 @@ class $GroupGameTableTable extends GroupGameTable type: DriftSqlType.string, requiredDuringInsert: true, defaultConstraints: GeneratedColumn.constraintIsAlways( - 'REFERENCES player_table (id)', + 'REFERENCES player_table (id) ON DELETE CASCADE', ), ); static const VerificationMeta _gameIdMeta = const VerificationMeta('gameId'); @@ -890,7 +1152,7 @@ class $GroupGameTableTable extends GroupGameTable type: DriftSqlType.string, requiredDuringInsert: true, defaultConstraints: GeneratedColumn.constraintIsAlways( - 'REFERENCES group_table (id)', + 'REFERENCES group_table (id) ON DELETE CASCADE', ), ); @override @@ -1084,270 +1346,12 @@ class GroupGameTableCompanion extends UpdateCompanion { } } -class $GameTableTable extends GameTable - with TableInfo<$GameTableTable, GameTableData> { - @override - final GeneratedDatabase attachedDatabase; - final String? _alias; - $GameTableTable(this.attachedDatabase, [this._alias]); - static const VerificationMeta _idMeta = const VerificationMeta('id'); - @override - late final GeneratedColumn id = GeneratedColumn( - 'id', - aliasedName, - false, - type: DriftSqlType.string, - requiredDuringInsert: true, - ); - static const VerificationMeta _nameMeta = const VerificationMeta('name'); - @override - late final GeneratedColumn name = GeneratedColumn( - 'name', - aliasedName, - false, - type: DriftSqlType.string, - requiredDuringInsert: true, - ); - static const VerificationMeta _winnerIdMeta = const VerificationMeta( - 'winnerId', - ); - @override - late final GeneratedColumn winnerId = GeneratedColumn( - 'winner_id', - aliasedName, - true, - type: DriftSqlType.string, - requiredDuringInsert: false, - ); - @override - List get $columns => [id, name, winnerId]; - @override - String get aliasedName => _alias ?? actualTableName; - @override - String get actualTableName => $name; - static const String $name = 'game_table'; - @override - VerificationContext validateIntegrity( - Insertable instance, { - bool isInserting = false, - }) { - final context = VerificationContext(); - final data = instance.toColumns(true); - if (data.containsKey('id')) { - context.handle(_idMeta, id.isAcceptableOrUnknown(data['id']!, _idMeta)); - } else if (isInserting) { - context.missing(_idMeta); - } - if (data.containsKey('name')) { - context.handle( - _nameMeta, - name.isAcceptableOrUnknown(data['name']!, _nameMeta), - ); - } else if (isInserting) { - context.missing(_nameMeta); - } - if (data.containsKey('winner_id')) { - context.handle( - _winnerIdMeta, - winnerId.isAcceptableOrUnknown(data['winner_id']!, _winnerIdMeta), - ); - } - return context; - } - - @override - Set get $primaryKey => {id}; - @override - GameTableData map(Map data, {String? tablePrefix}) { - final effectivePrefix = tablePrefix != null ? '$tablePrefix.' : ''; - return GameTableData( - id: attachedDatabase.typeMapping.read( - DriftSqlType.string, - data['${effectivePrefix}id'], - )!, - name: attachedDatabase.typeMapping.read( - DriftSqlType.string, - data['${effectivePrefix}name'], - )!, - winnerId: attachedDatabase.typeMapping.read( - DriftSqlType.string, - data['${effectivePrefix}winner_id'], - ), - ); - } - - @override - $GameTableTable createAlias(String alias) { - return $GameTableTable(attachedDatabase, alias); - } -} - -class GameTableData extends DataClass implements Insertable { - final String id; - final String name; - final String? winnerId; - const GameTableData({required this.id, required this.name, this.winnerId}); - @override - Map toColumns(bool nullToAbsent) { - final map = {}; - map['id'] = Variable(id); - map['name'] = Variable(name); - if (!nullToAbsent || winnerId != null) { - map['winner_id'] = Variable(winnerId); - } - return map; - } - - GameTableCompanion toCompanion(bool nullToAbsent) { - return GameTableCompanion( - id: Value(id), - name: Value(name), - winnerId: winnerId == null && nullToAbsent - ? const Value.absent() - : Value(winnerId), - ); - } - - factory GameTableData.fromJson( - Map json, { - ValueSerializer? serializer, - }) { - serializer ??= driftRuntimeOptions.defaultSerializer; - return GameTableData( - id: serializer.fromJson(json['id']), - name: serializer.fromJson(json['name']), - winnerId: serializer.fromJson(json['winnerId']), - ); - } - @override - Map toJson({ValueSerializer? serializer}) { - serializer ??= driftRuntimeOptions.defaultSerializer; - return { - 'id': serializer.toJson(id), - 'name': serializer.toJson(name), - 'winnerId': serializer.toJson(winnerId), - }; - } - - GameTableData copyWith({ - String? id, - String? name, - Value winnerId = const Value.absent(), - }) => GameTableData( - id: id ?? this.id, - name: name ?? this.name, - winnerId: winnerId.present ? winnerId.value : this.winnerId, - ); - 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, - ); - } - - @override - String toString() { - return (StringBuffer('GameTableData(') - ..write('id: $id, ') - ..write('name: $name, ') - ..write('winnerId: $winnerId') - ..write(')')) - .toString(); - } - - @override - int get hashCode => Object.hash(id, name, winnerId); - @override - bool operator ==(Object other) => - identical(this, other) || - (other is GameTableData && - other.id == this.id && - other.name == this.name && - other.winnerId == this.winnerId); -} - -class GameTableCompanion extends UpdateCompanion { - final Value id; - final Value name; - final Value winnerId; - final Value rowid; - const GameTableCompanion({ - this.id = const Value.absent(), - this.name = const Value.absent(), - this.winnerId = const Value.absent(), - this.rowid = const Value.absent(), - }); - GameTableCompanion.insert({ - required String id, - required String name, - this.winnerId = const Value.absent(), - this.rowid = const Value.absent(), - }) : id = Value(id), - name = Value(name); - static Insertable custom({ - Expression? id, - Expression? name, - Expression? winnerId, - Expression? rowid, - }) { - return RawValuesInsertable({ - if (id != null) 'id': id, - if (name != null) 'name': name, - if (winnerId != null) 'winner_id': winnerId, - if (rowid != null) 'rowid': rowid, - }); - } - - GameTableCompanion copyWith({ - Value? id, - Value? name, - Value? winnerId, - Value? rowid, - }) { - return GameTableCompanion( - id: id ?? this.id, - name: name ?? this.name, - winnerId: winnerId ?? this.winnerId, - rowid: rowid ?? this.rowid, - ); - } - - @override - Map toColumns(bool nullToAbsent) { - final map = {}; - if (id.present) { - map['id'] = Variable(id.value); - } - if (name.present) { - map['name'] = Variable(name.value); - } - if (winnerId.present) { - map['winner_id'] = Variable(winnerId.value); - } - if (rowid.present) { - map['rowid'] = Variable(rowid.value); - } - return map; - } - - @override - String toString() { - return (StringBuffer('GameTableCompanion(') - ..write('id: $id, ') - ..write('name: $name, ') - ..write('winnerId: $winnerId, ') - ..write('rowid: $rowid') - ..write(')')) - .toString(); - } -} - abstract class _$AppDatabase extends GeneratedDatabase { _$AppDatabase(QueryExecutor e) : super(e); $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, ); @@ -1355,7 +1359,6 @@ abstract class _$AppDatabase extends GeneratedDatabase { this, ); late final $GroupGameTableTable groupGameTable = $GroupGameTableTable(this); - late final $GameTableTable gameTable = $GameTableTable(this); late final GroupDao groupDao = GroupDao(this as AppDatabase); late final PlayerDao playerDao = PlayerDao(this as AppDatabase); late final GameDao gameDao = GameDao(this as AppDatabase); @@ -1371,11 +1374,63 @@ abstract class _$AppDatabase extends GeneratedDatabase { List get allSchemaEntities => [ playerTable, groupTable, + gameTable, playerGroupTable, playerGameTable, groupGameTable, - gameTable, ]; + @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( + 'player_table', + limitUpdateKind: UpdateKind.delete, + ), + result: [TableUpdate('group_game_table', kind: UpdateKind.delete)], + ), + WritePropagation( + on: TableUpdateQuery.onTableName( + 'group_table', + limitUpdateKind: UpdateKind.delete, + ), + result: [TableUpdate('group_game_table', kind: UpdateKind.delete)], + ), + ]); } typedef $$PlayerTableTableCreateCompanionBuilder = @@ -1395,6 +1450,24 @@ 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, @@ -1482,6 +1555,31 @@ class $$PlayerTableTableFilterComposer 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, ) { @@ -1593,6 +1691,31 @@ class $$PlayerTableTableAnnotationComposer GeneratedColumn get name => $composableBuilder(column: $table.name, 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, ) { @@ -1683,6 +1806,7 @@ class $$PlayerTableTableTableManager (PlayerTableData, $$PlayerTableTableReferences), PlayerTableData, PrefetchHooks Function({ + bool gameTableRefs, bool playerGroupTableRefs, bool playerGameTableRefs, bool groupGameTableRefs, @@ -1722,6 +1846,7 @@ class $$PlayerTableTableTableManager .toList(), prefetchHooksCallback: ({ + gameTableRefs = false, playerGroupTableRefs = false, playerGameTableRefs = false, groupGameTableRefs = false, @@ -1729,6 +1854,7 @@ class $$PlayerTableTableTableManager return PrefetchHooks( db: db, explicitlyWatchedTables: [ + if (gameTableRefs) db.gameTable, if (playerGroupTableRefs) db.playerGroupTable, if (playerGameTableRefs) db.playerGameTable, if (groupGameTableRefs) db.groupGameTable, @@ -1736,6 +1862,27 @@ class $$PlayerTableTableTableManager 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, @@ -1820,6 +1967,7 @@ typedef $$PlayerTableTableProcessedTableManager = (PlayerTableData, $$PlayerTableTableReferences), PlayerTableData, PrefetchHooks Function({ + bool gameTableRefs, bool playerGroupTableRefs, bool playerGameTableRefs, bool groupGameTableRefs, @@ -1865,29 +2013,6 @@ final class $$GroupTableTableReferences ); } - static MultiTypedResultKey<$PlayerGameTableTable, List> - _playerGameTableRefsTable(_$AppDatabase db) => MultiTypedResultKey.fromTable( - db.playerGameTable, - aliasName: $_aliasNameGenerator( - db.groupTable.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, @@ -1951,31 +2076,6 @@ class $$GroupTableTableFilterComposer 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.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, ) { @@ -2062,31 +2162,6 @@ class $$GroupTableTableAnnotationComposer 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.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, ) { @@ -2128,7 +2203,6 @@ class $$GroupTableTableTableManager GroupTableData, PrefetchHooks Function({ bool playerGroupTableRefs, - bool playerGameTableRefs, bool groupGameTableRefs, }) > { @@ -2165,16 +2239,11 @@ class $$GroupTableTableTableManager ) .toList(), prefetchHooksCallback: - ({ - playerGroupTableRefs = false, - playerGameTableRefs = false, - groupGameTableRefs = false, - }) { + ({playerGroupTableRefs = false, groupGameTableRefs = false}) { return PrefetchHooks( db: db, explicitlyWatchedTables: [ if (playerGroupTableRefs) db.playerGroupTable, - if (playerGameTableRefs) db.playerGameTable, if (groupGameTableRefs) db.groupGameTable, ], addJoins: null, @@ -2201,27 +2270,6 @@ class $$GroupTableTableTableManager ), typedResults: items, ), - if (playerGameTableRefs) - await $_getPrefetchedData< - GroupTableData, - $GroupTableTable, - PlayerGameTableData - >( - currentTable: table, - referencedTable: $$GroupTableTableReferences - ._playerGameTableRefsTable(db), - managerFromTypedResult: (p0) => - $$GroupTableTableReferences( - db, - table, - p0, - ).playerGameTableRefs, - referencedItemsForCurrentItem: - (item, referencedItems) => referencedItems.where( - (e) => e.gameId == item.id, - ), - typedResults: items, - ), if (groupGameTableRefs) await $_getPrefetchedData< GroupTableData, @@ -2265,10 +2313,385 @@ typedef $$GroupTableTableProcessedTableManager = GroupTableData, PrefetchHooks Function({ bool playerGroupTableRefs, - bool playerGameTableRefs, bool groupGameTableRefs, }) >; +typedef $$GameTableTableCreateCompanionBuilder = + GameTableCompanion Function({ + required String id, + required String name, + required String winnerId, + Value rowid, + }); +typedef $$GameTableTableUpdateCompanionBuilder = + GameTableCompanion Function({ + Value id, + Value name, + Value winnerId, + 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), + ); + } +} + +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), + ); + + $$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); + } +} + +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), + ); + + $$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); + + $$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); + } +} + +class $$GameTableTableTableManager + extends + RootTableManager< + _$AppDatabase, + $GameTableTable, + GameTableData, + $$GameTableTableFilterComposer, + $$GameTableTableOrderingComposer, + $$GameTableTableAnnotationComposer, + $$GameTableTableCreateCompanionBuilder, + $$GameTableTableUpdateCompanionBuilder, + (GameTableData, $$GameTableTableReferences), + GameTableData, + PrefetchHooks Function({bool winnerId, bool playerGameTableRefs}) + > { + $$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 rowid = const Value.absent(), + }) => GameTableCompanion( + id: id, + name: name, + winnerId: winnerId, + rowid: rowid, + ), + createCompanionCallback: + ({ + required String id, + required String name, + required String winnerId, + Value rowid = const Value.absent(), + }) => GameTableCompanion.insert( + id: id, + name: name, + winnerId: winnerId, + rowid: rowid, + ), + withReferenceMapper: (p0) => p0 + .map( + (e) => ( + e.readTable(table), + $$GameTableTableReferences(db, table, e), + ), + ) + .toList(), + prefetchHooksCallback: + ({winnerId = false, playerGameTableRefs = false}) { + return PrefetchHooks( + db: db, + explicitlyWatchedTables: [ + if (playerGameTableRefs) db.playerGameTable, + ], + 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, + ), + ]; + }, + ); + }, + ), + ); +} + +typedef $$GameTableTableProcessedTableManager = + ProcessedTableManager< + _$AppDatabase, + $GameTableTable, + GameTableData, + $$GameTableTableFilterComposer, + $$GameTableTableOrderingComposer, + $$GameTableTableAnnotationComposer, + $$GameTableTableCreateCompanionBuilder, + $$GameTableTableUpdateCompanionBuilder, + (GameTableData, $$GameTableTableReferences), + GameTableData, + PrefetchHooks Function({bool winnerId, bool playerGameTableRefs}) + >; typedef $$PlayerGroupTableTableCreateCompanionBuilder = PlayerGroupTableCompanion Function({ required String playerId, @@ -2679,17 +3102,17 @@ final class $$PlayerGameTableTableReferences ); } - static $GroupTableTable _gameIdTable(_$AppDatabase db) => - db.groupTable.createAlias( - $_aliasNameGenerator(db.playerGameTable.gameId, db.groupTable.id), + static $GameTableTable _gameIdTable(_$AppDatabase db) => + db.gameTable.createAlias( + $_aliasNameGenerator(db.playerGameTable.gameId, db.gameTable.id), ); - $$GroupTableTableProcessedTableManager get gameId { + $$GameTableTableProcessedTableManager get gameId { final $_column = $_itemColumn('game_id')!; - final manager = $$GroupTableTableTableManager( + final manager = $$GameTableTableTableManager( $_db, - $_db.groupTable, + $_db.gameTable, ).filter((f) => f.id.sqlEquals($_column)); final item = $_typedResult.readTableOrNull(_gameIdTable($_db)); if (item == null) return manager; @@ -2731,20 +3154,20 @@ class $$PlayerGameTableTableFilterComposer return composer; } - $$GroupTableTableFilterComposer get gameId { - final $$GroupTableTableFilterComposer composer = $composerBuilder( + $$GameTableTableFilterComposer get gameId { + final $$GameTableTableFilterComposer composer = $composerBuilder( composer: this, getCurrentColumn: (t) => t.gameId, - referencedTable: $db.groupTable, + referencedTable: $db.gameTable, getReferencedColumn: (t) => t.id, builder: ( joinBuilder, { $addJoinBuilderToRootComposer, $removeJoinBuilderFromRootComposer, - }) => $$GroupTableTableFilterComposer( + }) => $$GameTableTableFilterComposer( $db: $db, - $table: $db.groupTable, + $table: $db.gameTable, $addJoinBuilderToRootComposer: $addJoinBuilderToRootComposer, joinBuilder: joinBuilder, $removeJoinBuilderFromRootComposer: @@ -2787,20 +3210,20 @@ class $$PlayerGameTableTableOrderingComposer return composer; } - $$GroupTableTableOrderingComposer get gameId { - final $$GroupTableTableOrderingComposer composer = $composerBuilder( + $$GameTableTableOrderingComposer get gameId { + final $$GameTableTableOrderingComposer composer = $composerBuilder( composer: this, getCurrentColumn: (t) => t.gameId, - referencedTable: $db.groupTable, + referencedTable: $db.gameTable, getReferencedColumn: (t) => t.id, builder: ( joinBuilder, { $addJoinBuilderToRootComposer, $removeJoinBuilderFromRootComposer, - }) => $$GroupTableTableOrderingComposer( + }) => $$GameTableTableOrderingComposer( $db: $db, - $table: $db.groupTable, + $table: $db.gameTable, $addJoinBuilderToRootComposer: $addJoinBuilderToRootComposer, joinBuilder: joinBuilder, $removeJoinBuilderFromRootComposer: @@ -2843,20 +3266,20 @@ class $$PlayerGameTableTableAnnotationComposer return composer; } - $$GroupTableTableAnnotationComposer get gameId { - final $$GroupTableTableAnnotationComposer composer = $composerBuilder( + $$GameTableTableAnnotationComposer get gameId { + final $$GameTableTableAnnotationComposer composer = $composerBuilder( composer: this, getCurrentColumn: (t) => t.gameId, - referencedTable: $db.groupTable, + referencedTable: $db.gameTable, getReferencedColumn: (t) => t.id, builder: ( joinBuilder, { $addJoinBuilderToRootComposer, $removeJoinBuilderFromRootComposer, - }) => $$GroupTableTableAnnotationComposer( + }) => $$GameTableTableAnnotationComposer( $db: $db, - $table: $db.groupTable, + $table: $db.gameTable, $addJoinBuilderToRootComposer: $addJoinBuilderToRootComposer, joinBuilder: joinBuilder, $removeJoinBuilderFromRootComposer: @@ -3362,168 +3785,6 @@ typedef $$GroupGameTableTableProcessedTableManager = GroupGameTableData, PrefetchHooks Function({bool groupId, bool gameId}) >; -typedef $$GameTableTableCreateCompanionBuilder = - GameTableCompanion Function({ - required String id, - required String name, - Value winnerId, - Value rowid, - }); -typedef $$GameTableTableUpdateCompanionBuilder = - GameTableCompanion Function({ - Value id, - Value name, - Value winnerId, - Value rowid, - }); - -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 winnerId => $composableBuilder( - column: $table.winnerId, - builder: (column) => ColumnFilters(column), - ); -} - -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 winnerId => $composableBuilder( - column: $table.winnerId, - builder: (column) => ColumnOrderings(column), - ); -} - -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 winnerId => - $composableBuilder(column: $table.winnerId, builder: (column) => column); -} - -class $$GameTableTableTableManager - extends - RootTableManager< - _$AppDatabase, - $GameTableTable, - GameTableData, - $$GameTableTableFilterComposer, - $$GameTableTableOrderingComposer, - $$GameTableTableAnnotationComposer, - $$GameTableTableCreateCompanionBuilder, - $$GameTableTableUpdateCompanionBuilder, - ( - GameTableData, - BaseReferences<_$AppDatabase, $GameTableTable, GameTableData>, - ), - GameTableData, - PrefetchHooks Function() - > { - $$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 rowid = const Value.absent(), - }) => GameTableCompanion( - id: id, - name: name, - winnerId: winnerId, - rowid: rowid, - ), - createCompanionCallback: - ({ - required String id, - required String name, - Value winnerId = const Value.absent(), - Value rowid = const Value.absent(), - }) => GameTableCompanion.insert( - id: id, - name: name, - winnerId: winnerId, - rowid: rowid, - ), - withReferenceMapper: (p0) => p0 - .map((e) => (e.readTable(table), BaseReferences(db, table, e))) - .toList(), - prefetchHooksCallback: null, - ), - ); -} - -typedef $$GameTableTableProcessedTableManager = - ProcessedTableManager< - _$AppDatabase, - $GameTableTable, - GameTableData, - $$GameTableTableFilterComposer, - $$GameTableTableOrderingComposer, - $$GameTableTableAnnotationComposer, - $$GameTableTableCreateCompanionBuilder, - $$GameTableTableUpdateCompanionBuilder, - ( - GameTableData, - BaseReferences<_$AppDatabase, $GameTableTable, GameTableData>, - ), - GameTableData, - PrefetchHooks Function() - >; class $AppDatabaseManager { final _$AppDatabase _db; @@ -3532,12 +3793,12 @@ class $AppDatabaseManager { $$PlayerTableTableTableManager(_db, _db.playerTable); $$GroupTableTableTableManager get groupTable => $$GroupTableTableTableManager(_db, _db.groupTable); + $$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); - $$GameTableTableTableManager get gameTable => - $$GameTableTableTableManager(_db, _db.gameTable); } From 3f5a8406753867a8564fefbb7b771ecbbeb53b85 Mon Sep 17 00:00:00 2001 From: Felix Kirchner Date: Wed, 12 Nov 2025 20:01:44 +0100 Subject: [PATCH 014/141] Added toString methods --- lib/data/dto/game.dart | 9 +++++++-- lib/data/dto/group.dart | 5 +++++ lib/data/dto/player.dart | 5 +++++ 3 files changed, 17 insertions(+), 2 deletions(-) diff --git a/lib/data/dto/game.dart b/lib/data/dto/game.dart index 2c09851..125af48 100644 --- a/lib/data/dto/game.dart +++ b/lib/data/dto/game.dart @@ -6,13 +6,18 @@ class Game { final String name; final List? players; final Group? group; - final String? winner; + final String winner; Game({ this.players, this.group, - this.winner, + this.winner = '', required this.id, required this.name, }); + + @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..427a52b 100644 --- a/lib/data/dto/group.dart +++ b/lib/data/dto/group.dart @@ -6,4 +6,9 @@ class Group { final List members; Group({required this.id, required this.name, required this.members}); + + @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..631a51f 100644 --- a/lib/data/dto/player.dart +++ b/lib/data/dto/player.dart @@ -3,4 +3,9 @@ class Player { final String name; Player({required this.id, required this.name}); + + @override + String toString() { + return 'Player{id: $id,name: $name}'; + } } From 93a4ccaee0d924d3c933715f0229d46440805505 Mon Sep 17 00:00:00 2001 From: Felix Kirchner Date: Wed, 12 Nov 2025 20:02:01 +0100 Subject: [PATCH 015/141] Added missing methods and implemented tests --- lib/data/dao/game_dao.dart | 18 ++- lib/data/dao/game_dao.g.dart | 1 + lib/data/dao/group_dao.dart | 15 ++- lib/data/dao/player_game_dao.g.dart | 2 +- lib/data/dao/player_group_dao.dart | 37 +++++- lib/data/db/tables/player_game_table.dart | 4 +- lib/main.dart | 30 +++++ test/db_tests/game_test.dart | 111 ++++++++++++++++++ test/db_tests/group_test.dart | 130 ++++++++++++++++++++++ test/db_tests/player_test.dart | 66 +++++++++++ test/widget_test.dart | 29 ----- 11 files changed, 402 insertions(+), 41 deletions(-) create mode 100644 test/db_tests/game_test.dart create mode 100644 test/db_tests/group_test.dart create mode 100644 test/db_tests/player_test.dart delete mode 100644 test/widget_test.dart diff --git a/lib/data/dao/game_dao.dart b/lib/data/dao/game_dao.dart index 775c509..9379623 100644 --- a/lib/data/dao/game_dao.dart +++ b/lib/data/dao/game_dao.dart @@ -57,13 +57,21 @@ class GameDao extends DatabaseAccessor with _$GameDaoMixin { GameTableCompanion.insert( id: game.id, name: game.name, - winnerId: Value(game.winner), + winnerId: game.winner, ), 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. Future getGameCount() async { final count = @@ -72,4 +80,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 d449326..1f0e2c8 100644 --- a/lib/data/dao/group_dao.dart +++ b/lib/data/dao/group_dao.dart @@ -51,6 +51,9 @@ class GroupDao extends DatabaseAccessor with _$GroupDaoMixin { .toList(), ), ); + await Future.wait( + group.members.map((player) => db.playerDao.addPlayer(player: player)), + ); }); } @@ -65,11 +68,11 @@ class GroupDao extends DatabaseAccessor with _$GroupDaoMixin { /// 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({ - required String id, + 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; @@ -83,4 +86,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/player_game_dao.g.dart b/lib/data/dao/player_game_dao.g.dart index 0d5f5e1..4d0a192 100644 --- a/lib/data/dao/player_game_dao.g.dart +++ b/lib/data/dao/player_game_dao.g.dart @@ -5,6 +5,6 @@ part of 'player_game_dao.dart'; // ignore_for_file: type=lint mixin _$PlayerGameDaoMixin on DatabaseAccessor { $PlayerTableTable get playerTable => attachedDatabase.playerTable; - $GroupTableTable get groupTable => attachedDatabase.groupTable; + $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 5b2a095..fe067ae 100644 --- a/lib/data/dao/player_group_dao.dart +++ b/lib/data/dao/player_group_dao.dart @@ -16,7 +16,7 @@ class PlayerGroupDao extends DatabaseAccessor ..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(playerId: entry.playerId); @@ -38,13 +38,38 @@ class PlayerGroupDao extends DatabaseAccessor return rowsAffected > 0; } - /// Adds a player to a group with the given [playerId] and [groupId]. - Future addPlayerToGroup({ + /// 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(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 { - await into(playerGroupTable).insert( - PlayerGroupTableCompanion.insert(playerId: playerId, groupId: groupId), - ); + 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/tables/player_game_table.dart b/lib/data/db/tables/player_game_table.dart index 79b6df2..74c36fe 100644 --- a/lib/data/db/tables/player_game_table.dart +++ b/lib/data/db/tables/player_game_table.dart @@ -1,12 +1,12 @@ import 'package:drift/drift.dart'; -import 'package:game_tracker/data/db/tables/group_table.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(GroupTable, #id, onDelete: KeyAction.cascade)(); + text().references(GameTable, #id, onDelete: KeyAction.cascade)(); @override Set> get primaryKey => {playerId, gameId}; diff --git a/lib/main.dart b/lib/main.dart index 98c40f8..5aa9cfc 100644 --- a/lib/main.dart +++ b/lib/main.dart @@ -1,6 +1,9 @@ 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/game.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/custom_navigation_bar.dart'; import 'package:provider/provider.dart'; @@ -19,6 +22,8 @@ class GameTracker extends StatelessWidget { @override Widget build(BuildContext context) { + dbCheck(context); + return MaterialApp( debugShowCheckedModeBanner: false, title: 'Game Tracker', @@ -39,4 +44,29 @@ class GameTracker extends StatelessWidget { home: const CustomNavigationBar(), ); } + + Future dbCheck(BuildContext context) async { + Player player1 = Player(id: 'p1', name: 'Alice'); + Player player2 = Player(id: 'p2', name: 'Bob'); + Player player3 = Player(id: 'p3', name: 'Charlie'); + Player player4 = Player(id: 'p4', name: 'Diana'); + Group testgroup = Group( + id: 'gr1', + name: 'Test Group', + members: [player1, player2, player3], + ); + Game testgame = Game( + id: 'ga1', + name: 'Test Game', + winner: player1.id, + players: [player4], + group: testgroup, + ); + + final db = Provider.of(context, listen: false); + //await db.gameDao.addGame(game: testgame); + print('Game added: ${testgame.name}'); + final game = await db.gameDao.getGameById(gameId: testgame.id); + print(game.toString()); + } } diff --git a/test/db_tests/game_test.dart b/test/db_tests/game_test.dart new file mode 100644 index 0000000..fae8fc5 --- /dev/null +++ b/test/db_tests/game_test.dart @@ -0,0 +1,111 @@ +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 testPlayer; + late Player player1; + late Player player2; + late Player player3; + late Player player4; + late Group testgroup; + late Game testgame; + + setUp(() { + database = AppDatabase( + DatabaseConnection( + NativeDatabase.memory(), + // Recommended for widget tests to avoid test errors. + closeStreamsSynchronously: true, + ), + ); + + testPlayer = Player(id: 'test_id', name: 'Test Player'); + player1 = Player(id: 'p1', name: 'Alice'); + player2 = Player(id: 'p2', name: 'Bob'); + player3 = Player(id: 'p3', name: 'Charlie'); + player4 = Player(id: 'p4', name: 'Diana'); + testgroup = Group( + id: 'gr1', + name: 'Test Group', + members: [player1, player2, player3], + ); + testgame = Game( + id: 'ga1', + name: 'Test Game', + group: testgroup, + players: [player4], + ); + }); + 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); + + 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); + } + } 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..cdf514f --- /dev/null +++ b/test/db_tests/group_test.dart @@ -0,0 +1,130 @@ +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; + + setUp(() { + database = AppDatabase( + DatabaseConnection( + NativeDatabase.memory(), + // Recommended for widget tests to avoid test errors. + closeStreamsSynchronously: true, + ), + ); + + player1 = Player(id: 'p1', name: 'Alice'); + player2 = Player(id: 'p2', name: 'Bob'); + player3 = Player(id: 'p3', name: 'Charlie'); + player4 = Player(id: 'p4', name: 'Diana'); + testgroup = Group( + id: 'gr1', + name: 'Test Group', + members: [player1, player2, player3], + ); + }); + tearDown(() async { + await database.close(); + }); + + 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.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); + } + }); + + 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 playerAdded2 = await database.playerGroupDao.isPlayerInGroup( + playerId: 'a', + groupId: testgroup.id, + ); + + expect(playerAdded2, false); + + expect(playerAdded, 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); + }); + + 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); + }); +} diff --git a/test/db_tests/player_test.dart b/test/db_tests/player_test.dart new file mode 100644 index 0000000..a53f2cc --- /dev/null +++ b/test/db_tests/player_test.dart @@ -0,0 +1,66 @@ +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; + + setUp(() { + database = AppDatabase( + DatabaseConnection( + NativeDatabase.memory(), + // Recommended for widget tests to avoid test errors. + closeStreamsSynchronously: true, + ), + ); + + testPlayer = Player(id: 'test_id', name: 'Test Player'); + }); + tearDown(() async { + await database.close(); + }); + + group('player tests', () { + 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); + }); + + 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); + }); + }); +} diff --git a/test/widget_test.dart b/test/widget_test.dart deleted file mode 100644 index cb44eec..0000000 --- a/test/widget_test.dart +++ /dev/null @@ -1,29 +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 GameTracker()); - - // 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); - }); -} From 39b20681216ac3224795395c35cabce0f91d0040 Mon Sep 17 00:00:00 2001 From: Felix Kirchner Date: Wed, 12 Nov 2025 20:02:18 +0100 Subject: [PATCH 016/141] Removed unused var --- test/db_tests/game_test.dart | 2 -- 1 file changed, 2 deletions(-) diff --git a/test/db_tests/game_test.dart b/test/db_tests/game_test.dart index fae8fc5..bee3ff8 100644 --- a/test/db_tests/game_test.dart +++ b/test/db_tests/game_test.dart @@ -8,7 +8,6 @@ import 'package:game_tracker/data/dto/player.dart'; void main() { late AppDatabase database; - late Player testPlayer; late Player player1; late Player player2; late Player player3; @@ -25,7 +24,6 @@ void main() { ), ); - testPlayer = Player(id: 'test_id', name: 'Test Player'); player1 = Player(id: 'p1', name: 'Alice'); player2 = Player(id: 'p2', name: 'Bob'); player3 = Player(id: 'p3', name: 'Charlie'); From 9229f1f0a5b2a86772c4a8d1734c1695b1a23601 Mon Sep 17 00:00:00 2001 From: Felix Kirchner Date: Wed, 12 Nov 2025 20:09:17 +0100 Subject: [PATCH 017/141] Added counting methods + testing those --- lib/data/dao/player_dao.dart | 9 +++++++++ test/db_tests/group_test.dart | 18 ++++++++++++++++++ test/db_tests/player_test.dart | 18 ++++++++++++++++++ 3 files changed, 45 insertions(+) diff --git a/lib/data/dao/player_dao.dart b/lib/data/dao/player_dao.dart index 01e7163..976d4b0 100644 --- a/lib/data/dao/player_dao.dart +++ b/lib/data/dao/player_dao.dart @@ -61,4 +61,13 @@ class PlayerDao extends DatabaseAccessor with _$PlayerDaoMixin { 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/test/db_tests/group_test.dart b/test/db_tests/group_test.dart index cdf514f..a8fbcd5 100644 --- a/test/db_tests/group_test.dart +++ b/test/db_tests/group_test.dart @@ -127,4 +127,22 @@ void main() { 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 index a53f2cc..7fb9152 100644 --- a/test/db_tests/player_test.dart +++ b/test/db_tests/player_test.dart @@ -62,5 +62,23 @@ void main() { ); 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); + }); }); } From 2179331455c2b08b4b451d016cac61fec06bba68 Mon Sep 17 00:00:00 2001 From: Felix Kirchner Date: Fri, 14 Nov 2025 09:01:19 +0100 Subject: [PATCH 018/141] Removed test code --- lib/main.dart | 30 ------------------------------ 1 file changed, 30 deletions(-) diff --git a/lib/main.dart b/lib/main.dart index 5aa9cfc..98c40f8 100644 --- a/lib/main.dart +++ b/lib/main.dart @@ -1,9 +1,6 @@ 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/game.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/custom_navigation_bar.dart'; import 'package:provider/provider.dart'; @@ -22,8 +19,6 @@ class GameTracker extends StatelessWidget { @override Widget build(BuildContext context) { - dbCheck(context); - return MaterialApp( debugShowCheckedModeBanner: false, title: 'Game Tracker', @@ -44,29 +39,4 @@ class GameTracker extends StatelessWidget { home: const CustomNavigationBar(), ); } - - Future dbCheck(BuildContext context) async { - Player player1 = Player(id: 'p1', name: 'Alice'); - Player player2 = Player(id: 'p2', name: 'Bob'); - Player player3 = Player(id: 'p3', name: 'Charlie'); - Player player4 = Player(id: 'p4', name: 'Diana'); - Group testgroup = Group( - id: 'gr1', - name: 'Test Group', - members: [player1, player2, player3], - ); - Game testgame = Game( - id: 'ga1', - name: 'Test Game', - winner: player1.id, - players: [player4], - group: testgroup, - ); - - final db = Provider.of(context, listen: false); - //await db.gameDao.addGame(game: testgame); - print('Game added: ${testgame.name}'); - final game = await db.gameDao.getGameById(gameId: testgame.id); - print(game.toString()); - } } From 2ee4d8e6fa3dd36de8810703c6d09c44d0fdf427 Mon Sep 17 00:00:00 2001 From: mathiskirchner Date: Fri, 14 Nov 2025 20:58:01 +0100 Subject: [PATCH 019/141] implemented basic layout & functionality for add group button & group tiles --- .../views/main_menu/groups_view.dart | 82 ++++++++++++++++++- .../widgets/full_width_button.dart | 29 +++++++ lib/presentation/widgets/group_tile.dart | 56 +++++++++++++ .../widgets/top_centered_message.dart | 29 ++++--- 4 files changed, 182 insertions(+), 14 deletions(-) create mode 100644 lib/presentation/widgets/full_width_button.dart create mode 100644 lib/presentation/widgets/group_tile.dart diff --git a/lib/presentation/views/main_menu/groups_view.dart b/lib/presentation/views/main_menu/groups_view.dart index 485d516..a3e66d3 100644 --- a/lib/presentation/views/main_menu/groups_view.dart +++ b/lib/presentation/views/main_menu/groups_view.dart @@ -1,10 +1,86 @@ -import 'package:flutter/cupertino.dart'; +import 'package:flutter/material.dart'; +//import 'package:game_tracker/data/dto/group.dart'; +//import 'package:game_tracker/data/dto/player.dart'; +import 'package:game_tracker/presentation/widgets/full_width_button.dart'; +import 'package:game_tracker/presentation/widgets/group_tile.dart'; +import 'package:game_tracker/presentation/widgets/top_centered_message.dart'; -class GroupsView extends StatelessWidget { +class Group { + final String id; + final String name; + final List members; + + Group({required this.id, required this.name, required this.members}); +} + +class Player { + final String id; + final String name; + + Player({required this.id, required this.name}); +} + +class GroupsView extends StatefulWidget { const GroupsView({super.key}); + @override + State createState() => _GroupsViewState(); +} + +class _GroupsViewState extends State { + Future> _getMockGroups() async { + await Future.delayed(const Duration(seconds: 1)); + final player1 = Player(id: 'p1', name: 'Felix'); + final player2 = Player(id: 'p2', name: 'Yannick'); + final player3 = Player(id: 'p3', name: 'Mathis'); + final player4 = Player(id: 'p4', name: 'Petrus'); + + return [ + Group( + id: 'g1', + name: 'Weekend Warriors', + members: [player1, player2, player4], + ), + Group(id: 'g2', name: 'Strategy Masters', members: [player3, player4]), + Group( + id: 'g3', + name: 'The Cardboard Crew', + members: [player1, player2, player3, player4], + ), + Group(id: 'g4', name: 'The Group', members: [player1, player3, player4]), + ]; + } + @override Widget build(BuildContext context) { - return const Center(child: Text('Groups View')); + return Column( + children: [ + FutureBuilder( + future: _getMockGroups(), + builder: (BuildContext context, AsyncSnapshot> snapshot) { + if (snapshot.connectionState == ConnectionState.waiting) { + return Center( + child: TopCenteredMessage( + message: "Data not yet available, show sceleton", + ), + ); + } else if (snapshot.hasError) { + return Center( + child: TopCenteredMessage( + message: "Error while loading group data.", + ), + ); + } else if (!snapshot.hasData || snapshot.data!.isEmpty) { + return Center( + child: TopCenteredMessage(message: "No groups created yet."), + ); + } + return GroupTile(group: snapshot.data![0]); + //return ListView.builder() + }, + ), + FullWidthButton(text: "Create Group", onPressed: () {}), + ], + ); } } diff --git a/lib/presentation/widgets/full_width_button.dart b/lib/presentation/widgets/full_width_button.dart new file mode 100644 index 0000000..6df700b --- /dev/null +++ b/lib/presentation/widgets/full_width_button.dart @@ -0,0 +1,29 @@ +import 'package:flutter/material.dart'; +import 'package:game_tracker/core/custom_theme.dart'; + +class FullWidthButton extends StatelessWidget { + const FullWidthButton({super.key, required this.text, this.onPressed}); + + final String text; + final VoidCallback? onPressed; + + @override + Widget build(BuildContext context) { + return ElevatedButton( + onPressed: onPressed, + style: ElevatedButton.styleFrom( + minimumSize: Size(MediaQuery.of(context).size.width * 0.8, 60), + backgroundColor: CustomTheme.primaryColor, + shape: RoundedRectangleBorder(borderRadius: BorderRadius.circular(12)), + ), + child: Text( + text, + style: const TextStyle( + fontWeight: FontWeight.w500, + fontSize: 22, + color: Colors.white, + ), + ), + ); + } +} diff --git a/lib/presentation/widgets/group_tile.dart b/lib/presentation/widgets/group_tile.dart new file mode 100644 index 0000000..5959f04 --- /dev/null +++ b/lib/presentation/widgets/group_tile.dart @@ -0,0 +1,56 @@ +import 'package:flutter/material.dart'; +//import 'package:game_tracker/data/dto/group.dart'; + +class Group { + final String id; + final String name; + final List members; + + Group({required this.id, required this.name, required this.members}); +} + +class Player { + final String id; + final String name; + + Player({required this.id, required this.name}); +} + +class GroupTile extends StatelessWidget { + const GroupTile({super.key, required this.group}); + + final Group group; + + @override + Widget build(BuildContext context) { + return Container( + child: Column( + children: [ + Row( + mainAxisAlignment: MainAxisAlignment.spaceBetween, + children: [ + Text("${group.name}", overflow: TextOverflow.ellipsis), + Text("${group.members.length}"), + Icon(Icons.group), + ], + ), + Wrap( + spacing: 8.0, + runSpacing: -4.0, + children: [ + for (var member in group.members) + Container( + color: Colors.grey, + padding: const EdgeInsets.all(4.0), + decoration: BoxDecoration( + borderRadius: BorderRadius.circular(12), + ), + child: Text(member.name), + ), + ], + ), + ], + ), + ); + } +} diff --git a/lib/presentation/widgets/top_centered_message.dart b/lib/presentation/widgets/top_centered_message.dart index 6fe34ff..df8dcb1 100644 --- a/lib/presentation/widgets/top_centered_message.dart +++ b/lib/presentation/widgets/top_centered_message.dart @@ -1,14 +1,21 @@ 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.message}); + + final String message; + + @override + Widget build(BuildContext context) { + return Container( + padding: const EdgeInsets.only(top: 100), + margin: const EdgeInsets.symmetric(horizontal: 10), + alignment: Alignment.topCenter, + child: Text( + message, + style: const TextStyle(fontSize: 20), + textAlign: TextAlign.center, + ), + ); + } } From cbd5e1d0ba0a7a3b9fce2691e558ba974f706b53 Mon Sep 17 00:00:00 2001 From: Felix Kirchner Date: Fri, 14 Nov 2025 22:30:56 +0100 Subject: [PATCH 020/141] Added documentation --- lib/data/dao/group_game_dao.dart | 1 + 1 file changed, 1 insertion(+) diff --git a/lib/data/dao/group_game_dao.dart b/lib/data/dao/group_game_dao.dart index 88b8fad..d3b30ca 100644 --- a/lib/data/dao/group_game_dao.dart +++ b/lib/data/dao/group_game_dao.dart @@ -22,6 +22,7 @@ class GroupGameDao extends DatabaseAccessor return (count ?? 0) > 0; } + /// Retrieves the [Group] associated with the given [gameId]. Future getGroupByGameId({required String gameId}) async { final result = await (select( groupGameTable, From 7be86b3d9e77b1b3f1cbfb570ff0db33d99553e0 Mon Sep 17 00:00:00 2001 From: Felix Kirchner Date: Fri, 14 Nov 2025 22:31:30 +0100 Subject: [PATCH 021/141] Changed method name --- lib/data/dao/game_dao.dart | 2 +- lib/data/dao/player_game_dao.dart | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/lib/data/dao/game_dao.dart b/lib/data/dao/game_dao.dart index 9379623..fc931ad 100644 --- a/lib/data/dao/game_dao.dart +++ b/lib/data/dao/game_dao.dart @@ -24,7 +24,7 @@ class GameDao extends DatabaseAccessor with _$GameDaoMixin { final result = await query.getSingle(); List? players; - if (await db.playerGameDao.hasGamePlayers(gameId: gameId)) { + if (await db.playerGameDao.gameHasPlayers(gameId: gameId)) { players = await db.playerGameDao.getPlayersByGameId(gameId: gameId); } Group? group; diff --git a/lib/data/dao/player_game_dao.dart b/lib/data/dao/player_game_dao.dart index 333dc28..8f367f8 100644 --- a/lib/data/dao/player_game_dao.dart +++ b/lib/data/dao/player_game_dao.dart @@ -12,7 +12,7 @@ class PlayerGameDao extends DatabaseAccessor /// Checks if there are any players associated with the given [gameId]. /// Returns `true` if there are players, otherwise `false`. - Future hasGamePlayers({required String gameId}) async { + Future gameHasPlayers({required String gameId}) async { final count = await (selectOnly(playerGameTable) ..where(playerGameTable.gameId.equals(gameId)) From 34bf6740adce09c4b8f7019193471f26555f3251 Mon Sep 17 00:00:00 2001 From: Felix Kirchner Date: Fri, 14 Nov 2025 22:33:22 +0100 Subject: [PATCH 022/141] Corrected GroupGameTable attributes --- lib/data/dao/group_game_dao.g.dart | 3 +- lib/data/db/database.g.dart | 401 ++++++++++++----------- lib/data/db/tables/group_game_table.dart | 6 +- 3 files changed, 210 insertions(+), 200 deletions(-) diff --git a/lib/data/dao/group_game_dao.g.dart b/lib/data/dao/group_game_dao.g.dart index f1aa46f..426f192 100644 --- a/lib/data/dao/group_game_dao.g.dart +++ b/lib/data/dao/group_game_dao.g.dart @@ -4,7 +4,8 @@ part of 'group_game_dao.dart'; // ignore_for_file: type=lint mixin _$GroupGameDaoMixin on DatabaseAccessor { - $PlayerTableTable get playerTable => attachedDatabase.playerTable; $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/db/database.g.dart b/lib/data/db/database.g.dart index 453fcb0..03b7a10 100644 --- a/lib/data/db/database.g.dart +++ b/lib/data/db/database.g.dart @@ -1140,7 +1140,7 @@ class $GroupGameTableTable extends GroupGameTable type: DriftSqlType.string, requiredDuringInsert: true, defaultConstraints: GeneratedColumn.constraintIsAlways( - 'REFERENCES player_table (id) ON DELETE CASCADE', + 'REFERENCES group_table (id) ON DELETE CASCADE', ), ); static const VerificationMeta _gameIdMeta = const VerificationMeta('gameId'); @@ -1152,7 +1152,7 @@ class $GroupGameTableTable extends GroupGameTable type: DriftSqlType.string, requiredDuringInsert: true, defaultConstraints: GeneratedColumn.constraintIsAlways( - 'REFERENCES group_table (id) ON DELETE CASCADE', + 'REFERENCES game_table (id) ON DELETE CASCADE', ), ); @override @@ -1359,8 +1359,8 @@ abstract class _$AppDatabase extends GeneratedDatabase { this, ); late final $GroupGameTableTable groupGameTable = $GroupGameTableTable(this); - late final GroupDao groupDao = GroupDao(this as AppDatabase); 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, @@ -1418,14 +1418,14 @@ abstract class _$AppDatabase extends GeneratedDatabase { ), WritePropagation( on: TableUpdateQuery.onTableName( - 'player_table', + 'group_table', limitUpdateKind: UpdateKind.delete, ), result: [TableUpdate('group_game_table', kind: UpdateKind.delete)], ), WritePropagation( on: TableUpdateQuery.onTableName( - 'group_table', + 'game_table', limitUpdateKind: UpdateKind.delete, ), result: [TableUpdate('group_game_table', kind: UpdateKind.delete)], @@ -1513,27 +1513,6 @@ final class $$PlayerTableTableReferences manager.$state.copyWith(prefetchedData: cache), ); } - - static MultiTypedResultKey<$GroupGameTableTable, List> - _groupGameTableRefsTable(_$AppDatabase db) => MultiTypedResultKey.fromTable( - db.groupGameTable, - aliasName: $_aliasNameGenerator( - db.playerTable.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 $$PlayerTableTableFilterComposer @@ -1629,31 +1608,6 @@ class $$PlayerTableTableFilterComposer ); 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 $$PlayerTableTableOrderingComposer @@ -1765,31 +1719,6 @@ class $$PlayerTableTableAnnotationComposer ); 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 $$PlayerTableTableTableManager @@ -1809,7 +1738,6 @@ class $$PlayerTableTableTableManager bool gameTableRefs, bool playerGroupTableRefs, bool playerGameTableRefs, - bool groupGameTableRefs, }) > { $$PlayerTableTableTableManager(_$AppDatabase db, $PlayerTableTable table) @@ -1849,7 +1777,6 @@ class $$PlayerTableTableTableManager gameTableRefs = false, playerGroupTableRefs = false, playerGameTableRefs = false, - groupGameTableRefs = false, }) { return PrefetchHooks( db: db, @@ -1857,7 +1784,6 @@ class $$PlayerTableTableTableManager if (gameTableRefs) db.gameTable, if (playerGroupTableRefs) db.playerGroupTable, if (playerGameTableRefs) db.playerGameTable, - if (groupGameTableRefs) db.groupGameTable, ], addJoins: null, getPrefetchedDataCallback: (items) async { @@ -1925,27 +1851,6 @@ class $$PlayerTableTableTableManager ), typedResults: items, ), - if (groupGameTableRefs) - await $_getPrefetchedData< - PlayerTableData, - $PlayerTableTable, - GroupGameTableData - >( - currentTable: table, - referencedTable: $$PlayerTableTableReferences - ._groupGameTableRefsTable(db), - managerFromTypedResult: (p0) => - $$PlayerTableTableReferences( - db, - table, - p0, - ).groupGameTableRefs, - referencedItemsForCurrentItem: - (item, referencedItems) => referencedItems.where( - (e) => e.groupId == item.id, - ), - typedResults: items, - ), ]; }, ); @@ -1970,7 +1875,6 @@ typedef $$PlayerTableTableProcessedTableManager = bool gameTableRefs, bool playerGroupTableRefs, bool playerGameTableRefs, - bool groupGameTableRefs, }) >; typedef $$GroupTableTableCreateCompanionBuilder = @@ -2016,14 +1920,17 @@ final class $$GroupTableTableReferences static MultiTypedResultKey<$GroupGameTableTable, List> _groupGameTableRefsTable(_$AppDatabase db) => MultiTypedResultKey.fromTable( db.groupGameTable, - aliasName: $_aliasNameGenerator(db.groupTable.id, db.groupGameTable.gameId), + aliasName: $_aliasNameGenerator( + db.groupTable.id, + db.groupGameTable.groupId, + ), ); $$GroupGameTableTableProcessedTableManager get groupGameTableRefs { final manager = $$GroupGameTableTableTableManager( $_db, $_db.groupGameTable, - ).filter((f) => f.gameId.id.sqlEquals($_itemColumn('id')!)); + ).filter((f) => f.groupId.id.sqlEquals($_itemColumn('id')!)); final cache = $_typedResult.readTableOrNull(_groupGameTableRefsTable($_db)); return ProcessedTableManager( @@ -2083,7 +1990,7 @@ class $$GroupTableTableFilterComposer composer: this, getCurrentColumn: (t) => t.id, referencedTable: $db.groupGameTable, - getReferencedColumn: (t) => t.gameId, + getReferencedColumn: (t) => t.groupId, builder: ( joinBuilder, { @@ -2169,7 +2076,7 @@ class $$GroupTableTableAnnotationComposer composer: this, getCurrentColumn: (t) => t.id, referencedTable: $db.groupGameTable, - getReferencedColumn: (t) => t.gameId, + getReferencedColumn: (t) => t.groupId, builder: ( joinBuilder, { @@ -2287,7 +2194,7 @@ class $$GroupTableTableTableManager ).groupGameTableRefs, referencedItemsForCurrentItem: (item, referencedItems) => referencedItems.where( - (e) => e.gameId == item.id, + (e) => e.groupId == item.id, ), typedResults: items, ), @@ -2373,6 +2280,24 @@ final class $$GameTableTableReferences 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 @@ -2441,6 +2366,31 @@ class $$GameTableTableFilterComposer ); 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 @@ -2548,6 +2498,31 @@ class $$GameTableTableAnnotationComposer ); 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 @@ -2563,7 +2538,11 @@ class $$GameTableTableTableManager $$GameTableTableUpdateCompanionBuilder, (GameTableData, $$GameTableTableReferences), GameTableData, - PrefetchHooks Function({bool winnerId, bool playerGameTableRefs}) + PrefetchHooks Function({ + bool winnerId, + bool playerGameTableRefs, + bool groupGameTableRefs, + }) > { $$GameTableTableTableManager(_$AppDatabase db, $GameTableTable table) : super( @@ -2609,11 +2588,16 @@ class $$GameTableTableTableManager ) .toList(), prefetchHooksCallback: - ({winnerId = false, playerGameTableRefs = false}) { + ({ + winnerId = false, + playerGameTableRefs = false, + groupGameTableRefs = false, + }) { return PrefetchHooks( db: db, explicitlyWatchedTables: [ if (playerGameTableRefs) db.playerGameTable, + if (groupGameTableRefs) db.groupGameTable, ], addJoins: < @@ -2670,6 +2654,27 @@ class $$GameTableTableTableManager ), 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, + ), ]; }, ); @@ -2690,7 +2695,11 @@ typedef $$GameTableTableProcessedTableManager = $$GameTableTableUpdateCompanionBuilder, (GameTableData, $$GameTableTableReferences), GameTableData, - PrefetchHooks Function({bool winnerId, bool playerGameTableRefs}) + PrefetchHooks Function({ + bool winnerId, + bool playerGameTableRefs, + bool groupGameTableRefs, + }) >; typedef $$PlayerGroupTableTableCreateCompanionBuilder = PlayerGroupTableCompanion Function({ @@ -3448,17 +3457,17 @@ final class $$GroupGameTableTableReferences super.$_typedResult, ); - static $PlayerTableTable _groupIdTable(_$AppDatabase db) => - db.playerTable.createAlias( - $_aliasNameGenerator(db.groupGameTable.groupId, db.playerTable.id), + static $GroupTableTable _groupIdTable(_$AppDatabase db) => + db.groupTable.createAlias( + $_aliasNameGenerator(db.groupGameTable.groupId, db.groupTable.id), ); - $$PlayerTableTableProcessedTableManager get groupId { + $$GroupTableTableProcessedTableManager get groupId { final $_column = $_itemColumn('group_id')!; - final manager = $$PlayerTableTableTableManager( + final manager = $$GroupTableTableTableManager( $_db, - $_db.playerTable, + $_db.groupTable, ).filter((f) => f.id.sqlEquals($_column)); final item = $_typedResult.readTableOrNull(_groupIdTable($_db)); if (item == null) return manager; @@ -3467,17 +3476,17 @@ final class $$GroupGameTableTableReferences ); } - static $GroupTableTable _gameIdTable(_$AppDatabase db) => - db.groupTable.createAlias( - $_aliasNameGenerator(db.groupGameTable.gameId, db.groupTable.id), + static $GameTableTable _gameIdTable(_$AppDatabase db) => + db.gameTable.createAlias( + $_aliasNameGenerator(db.groupGameTable.gameId, db.gameTable.id), ); - $$GroupTableTableProcessedTableManager get gameId { + $$GameTableTableProcessedTableManager get gameId { final $_column = $_itemColumn('game_id')!; - final manager = $$GroupTableTableTableManager( + final manager = $$GameTableTableTableManager( $_db, - $_db.groupTable, + $_db.gameTable, ).filter((f) => f.id.sqlEquals($_column)); final item = $_typedResult.readTableOrNull(_gameIdTable($_db)); if (item == null) return manager; @@ -3496,33 +3505,10 @@ class $$GroupGameTableTableFilterComposer super.$addJoinBuilderToRootComposer, super.$removeJoinBuilderFromRootComposer, }); - $$PlayerTableTableFilterComposer get groupId { - final $$PlayerTableTableFilterComposer composer = $composerBuilder( - composer: this, - getCurrentColumn: (t) => t.groupId, - 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; - } - - $$GroupTableTableFilterComposer get gameId { + $$GroupTableTableFilterComposer get groupId { final $$GroupTableTableFilterComposer composer = $composerBuilder( composer: this, - getCurrentColumn: (t) => t.gameId, + getCurrentColumn: (t) => t.groupId, referencedTable: $db.groupTable, getReferencedColumn: (t) => t.id, builder: @@ -3541,6 +3527,29 @@ class $$GroupGameTableTableFilterComposer ); 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 @@ -3552,33 +3561,10 @@ class $$GroupGameTableTableOrderingComposer super.$addJoinBuilderToRootComposer, super.$removeJoinBuilderFromRootComposer, }); - $$PlayerTableTableOrderingComposer get groupId { - final $$PlayerTableTableOrderingComposer composer = $composerBuilder( - composer: this, - getCurrentColumn: (t) => t.groupId, - 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; - } - - $$GroupTableTableOrderingComposer get gameId { + $$GroupTableTableOrderingComposer get groupId { final $$GroupTableTableOrderingComposer composer = $composerBuilder( composer: this, - getCurrentColumn: (t) => t.gameId, + getCurrentColumn: (t) => t.groupId, referencedTable: $db.groupTable, getReferencedColumn: (t) => t.id, builder: @@ -3597,6 +3583,29 @@ class $$GroupGameTableTableOrderingComposer ); 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 @@ -3608,33 +3617,10 @@ class $$GroupGameTableTableAnnotationComposer super.$addJoinBuilderToRootComposer, super.$removeJoinBuilderFromRootComposer, }); - $$PlayerTableTableAnnotationComposer get groupId { - final $$PlayerTableTableAnnotationComposer composer = $composerBuilder( - composer: this, - getCurrentColumn: (t) => t.groupId, - 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; - } - - $$GroupTableTableAnnotationComposer get gameId { + $$GroupTableTableAnnotationComposer get groupId { final $$GroupTableTableAnnotationComposer composer = $composerBuilder( composer: this, - getCurrentColumn: (t) => t.gameId, + getCurrentColumn: (t) => t.groupId, referencedTable: $db.groupTable, getReferencedColumn: (t) => t.id, builder: @@ -3653,6 +3639,29 @@ class $$GroupGameTableTableAnnotationComposer ); 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 diff --git a/lib/data/db/tables/group_game_table.dart b/lib/data/db/tables/group_game_table.dart index 6be12bc..a16672e 100644 --- a/lib/data/db/tables/group_game_table.dart +++ b/lib/data/db/tables/group_game_table.dart @@ -1,12 +1,12 @@ 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'; -import 'package:game_tracker/data/db/tables/player_table.dart'; class GroupGameTable extends Table { TextColumn get groupId => - text().references(PlayerTable, #id, onDelete: KeyAction.cascade)(); - TextColumn get gameId => text().references(GroupTable, #id, onDelete: KeyAction.cascade)(); + TextColumn get gameId => + text().references(GameTable, #id, onDelete: KeyAction.cascade)(); @override Set> get primaryKey => {groupId, gameId}; From 1081fb8be7d61395bf0b1fab8addff48612dcb72 Mon Sep 17 00:00:00 2001 From: mathiskirchner Date: Sat, 15 Nov 2025 16:08:47 +0100 Subject: [PATCH 023/141] rearrange imports and fix wrong syntax in widget call --- lib/presentation/views/main_menu/game_history_view.dart | 8 +++++--- lib/presentation/views/main_menu/groups_view.dart | 4 ++-- 2 files changed, 7 insertions(+), 5 deletions(-) diff --git a/lib/presentation/views/main_menu/game_history_view.dart b/lib/presentation/views/main_menu/game_history_view.dart index de75ae6..f620cd7 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/top_centered_message.dart'; import 'package:game_tracker/presentation/widgets/double_row_info_tile.dart'; +import 'package:game_tracker/presentation/widgets/top_centered_message.dart'; class GameHistoryView extends StatefulWidget { const GameHistoryView({super.key}); @@ -178,9 +178,11 @@ class _GameHistoryViewState extends State { Widget gameHistoryListView(allGameData, suggestedGameData) { if (suggestedGameData.isEmpty && allGameData.isEmpty) { - return TopCenteredMessage("Keine Spiele erstellt"); + return TopCenteredMessage(message: "Keine Spiele erstellt"); } else if (suggestedGameData.isEmpty) { - return TopCenteredMessage("Kein Spiel mit den Suchparametern gefunden."); + return TopCenteredMessage( + message: "Kein Spiel mit den Suchparametern gefunden.", + ); } return ListView.builder( itemCount: suggestedGameData.length, diff --git a/lib/presentation/views/main_menu/groups_view.dart b/lib/presentation/views/main_menu/groups_view.dart index a3e66d3..70f70dc 100644 --- a/lib/presentation/views/main_menu/groups_view.dart +++ b/lib/presentation/views/main_menu/groups_view.dart @@ -2,7 +2,6 @@ import 'package:flutter/material.dart'; //import 'package:game_tracker/data/dto/group.dart'; //import 'package:game_tracker/data/dto/player.dart'; import 'package:game_tracker/presentation/widgets/full_width_button.dart'; -import 'package:game_tracker/presentation/widgets/group_tile.dart'; import 'package:game_tracker/presentation/widgets/top_centered_message.dart'; class Group { @@ -75,7 +74,8 @@ class _GroupsViewState extends State { child: TopCenteredMessage(message: "No groups created yet."), ); } - return GroupTile(group: snapshot.data![0]); + return Center(child: Text("whatever")); + //return GroupTile(group: snapshot.data![0]); //return ListView.builder() }, ), From d08c79fc262b9298442962285072813a8d145a89 Mon Sep 17 00:00:00 2001 From: mathiskirchner Date: Sat, 15 Nov 2025 20:22:09 +0100 Subject: [PATCH 024/141] implemented groups view with create group button --- .../views/main_menu/groups_view.dart | 115 +++++++++++++----- .../widgets/full_width_button.dart | 2 +- lib/presentation/widgets/group_tile.dart | 73 +++++++---- 3 files changed, 134 insertions(+), 56 deletions(-) diff --git a/lib/presentation/views/main_menu/groups_view.dart b/lib/presentation/views/main_menu/groups_view.dart index 70f70dc..76034a6 100644 --- a/lib/presentation/views/main_menu/groups_view.dart +++ b/lib/presentation/views/main_menu/groups_view.dart @@ -2,6 +2,7 @@ import 'package:flutter/material.dart'; //import 'package:game_tracker/data/dto/group.dart'; //import 'package:game_tracker/data/dto/player.dart'; import 'package:game_tracker/presentation/widgets/full_width_button.dart'; +import 'package:game_tracker/presentation/widgets/group_tile.dart'; import 'package:game_tracker/presentation/widgets/top_centered_message.dart'; class Group { @@ -38,7 +39,15 @@ class _GroupsViewState extends State { Group( id: 'g1', name: 'Weekend Warriors', - members: [player1, player2, player4], + members: [ + player1, + player2, + player4, + player3, + player1, + player4, + player2, + ], ), Group(id: 'g2', name: 'Strategy Masters', members: [player3, player4]), Group( @@ -46,41 +55,85 @@ class _GroupsViewState extends State { name: 'The Cardboard Crew', members: [player1, player2, player3, player4], ), - Group(id: 'g4', name: 'The Group', members: [player1, player3, player4]), + Group( + id: 'g4', + name: 'Gamers', + members: [player1, player3, player1, player4], + ), + Group( + id: 'g4', + name: 'The Group', + members: [player4, player1, player3, player4, player3], + ), + Group( + id: 'g4', + name: 'Friends', + members: [player4, player1, player3, player4], + ), + Group( + id: 'g4', + name: 'Sample Group', + members: [player1, player1, player4, player3], + ), + Group( + id: 'g4', + name: 'The Group', + members: [player1, player1, player3, player4], + ), + Group( + id: 'g4', + name: 'The Best', + members: [player1, player3, player1, player4, player1], + ), ]; } @override Widget build(BuildContext context) { - return Column( - children: [ - FutureBuilder( - future: _getMockGroups(), - builder: (BuildContext context, AsyncSnapshot> snapshot) { - if (snapshot.connectionState == ConnectionState.waiting) { - return Center( - child: TopCenteredMessage( - message: "Data not yet available, show sceleton", - ), - ); - } else if (snapshot.hasError) { - return Center( - child: TopCenteredMessage( - message: "Error while loading group data.", - ), - ); - } else if (!snapshot.hasData || snapshot.data!.isEmpty) { - return Center( - child: TopCenteredMessage(message: "No groups created yet."), - ); - } - return Center(child: Text("whatever")); - //return GroupTile(group: snapshot.data![0]); - //return ListView.builder() - }, - ), - FullWidthButton(text: "Create Group", onPressed: () {}), - ], + return SafeArea( + child: Stack( + children: [ + FutureBuilder( + future: _getMockGroups(), + builder: + (BuildContext context, AsyncSnapshot> snapshot) { + if (snapshot.connectionState == ConnectionState.waiting) { + return const Center( + child: TopCenteredMessage( + message: 'Data not yet available, show sceleton', + ), + ); + } else if (snapshot.hasError) { + return const Center( + child: TopCenteredMessage( + message: 'Error while loading group data.', + ), + ); + } else if (!snapshot.hasData || snapshot.data!.isEmpty) { + return const Center( + child: TopCenteredMessage( + message: 'No groups created yet.', + ), + ); + } + //return Center(child: Text('whatever')); + //return GroupTile(group: snapshot.data![0]); + return ListView.builder( + padding: const EdgeInsets.only(bottom: 85), + itemCount: snapshot.data!.length, + itemBuilder: (BuildContext context, int index) { + return GroupTile(group: snapshot.data![index]); + }, + ); + }, + ), + Positioned( + bottom: 16, + right: 16, + child: FullWidthButton(text: 'Create Group', onPressed: () {}), + ), + ], + ), ); } } diff --git a/lib/presentation/widgets/full_width_button.dart b/lib/presentation/widgets/full_width_button.dart index 6df700b..2af6abe 100644 --- a/lib/presentation/widgets/full_width_button.dart +++ b/lib/presentation/widgets/full_width_button.dart @@ -12,7 +12,7 @@ class FullWidthButton extends StatelessWidget { return ElevatedButton( onPressed: onPressed, style: ElevatedButton.styleFrom( - minimumSize: Size(MediaQuery.of(context).size.width * 0.8, 60), + minimumSize: Size(MediaQuery.of(context).size.width * 0.90, 60), backgroundColor: CustomTheme.primaryColor, shape: RoundedRectangleBorder(borderRadius: BorderRadius.circular(12)), ), diff --git a/lib/presentation/widgets/group_tile.dart b/lib/presentation/widgets/group_tile.dart index 5959f04..783abcd 100644 --- a/lib/presentation/widgets/group_tile.dart +++ b/lib/presentation/widgets/group_tile.dart @@ -1,20 +1,6 @@ import 'package:flutter/material.dart'; -//import 'package:game_tracker/data/dto/group.dart'; - -class Group { - final String id; - final String name; - final List members; - - Group({required this.id, required this.name, required this.members}); -} - -class Player { - final String id; - final String name; - - Player({required this.id, required this.name}); -} +import 'package:game_tracker/core/custom_theme.dart'; +import 'package:game_tracker/presentation/views/main_menu/groups_view.dart'; class GroupTile extends StatelessWidget { const GroupTile({super.key, required this.group}); @@ -24,31 +10,70 @@ class GroupTile extends StatelessWidget { @override Widget build(BuildContext context) { return Container( + width: MediaQuery.of(context).size.width * 0.90, + margin: const EdgeInsets.symmetric(horizontal: 20, vertical: 10), + padding: const EdgeInsets.symmetric(vertical: 5, horizontal: 10), + decoration: BoxDecoration( + color: CustomTheme.secondaryColor, + borderRadius: BorderRadius.circular(12), + ), child: Column( + crossAxisAlignment: CrossAxisAlignment.start, children: [ Row( mainAxisAlignment: MainAxisAlignment.spaceBetween, children: [ - Text("${group.name}", overflow: TextOverflow.ellipsis), - Text("${group.members.length}"), - Icon(Icons.group), + Text( + group.name, + overflow: TextOverflow.ellipsis, + style: const TextStyle( + fontWeight: FontWeight.bold, + fontSize: 20, + color: Colors.white, + ), + ), + const Spacer(), + Text( + '${group.members.length}', + style: const TextStyle( + fontWeight: FontWeight.w900, + fontSize: 20, + color: Colors.white, + ), + ), + SizedBox(width: 3), + const Icon(Icons.group), ], ), + SizedBox(height: 5), Wrap( - spacing: 8.0, - runSpacing: -4.0, + alignment: WrapAlignment.start, + crossAxisAlignment: WrapCrossAlignment.start, + spacing: 12.0, + runSpacing: 8.0, children: [ for (var member in group.members) Container( - color: Colors.grey, - padding: const EdgeInsets.all(4.0), + padding: const EdgeInsets.symmetric( + vertical: 5, + horizontal: 10, + ), decoration: BoxDecoration( + color: Colors.black26, borderRadius: BorderRadius.circular(12), ), - child: Text(member.name), + child: Text( + member.name, + style: TextStyle( + fontSize: 17, + fontWeight: FontWeight.bold, + color: Colors.white, + ), + ), ), ], ), + SizedBox(height: 2.5), ], ), ); From d36348c59c1b87afbdf4f1e7f065dff86aa0a301 Mon Sep 17 00:00:00 2001 From: mathiskirchner Date: Sat, 15 Nov 2025 21:24:52 +0100 Subject: [PATCH 025/141] added skeleton loading --- .../views/main_menu/groups_view.dart | 65 ++++++++++++++----- lib/presentation/widgets/group_tile.dart | 2 +- 2 files changed, 48 insertions(+), 19 deletions(-) diff --git a/lib/presentation/views/main_menu/groups_view.dart b/lib/presentation/views/main_menu/groups_view.dart index 76034a6..e52cf58 100644 --- a/lib/presentation/views/main_menu/groups_view.dart +++ b/lib/presentation/views/main_menu/groups_view.dart @@ -4,6 +4,7 @@ import 'package:flutter/material.dart'; import 'package:game_tracker/presentation/widgets/full_width_button.dart'; import 'package:game_tracker/presentation/widgets/group_tile.dart'; import 'package:game_tracker/presentation/widgets/top_centered_message.dart'; +import 'package:skeletonizer/skeletonizer.dart'; class Group { final String id; @@ -29,7 +30,7 @@ class GroupsView extends StatefulWidget { class _GroupsViewState extends State { Future> _getMockGroups() async { - await Future.delayed(const Duration(seconds: 1)); + await Future.delayed(const Duration(seconds: 4)); final player1 = Player(id: 'p1', name: 'Felix'); final player2 = Player(id: 'p2', name: 'Yannick'); final player3 = Player(id: 'p3', name: 'Mathis'); @@ -88,45 +89,73 @@ class _GroupsViewState extends State { ]; } + final player = Player(id: 'p1', name: 'Felix'); + late final List skeletonData = List.filled( + 7, + Group( + id: 'g1', + name: 'Weekend Warriors', + members: [player, player, player, player], + ), + ); + @override Widget build(BuildContext context) { return SafeArea( child: Stack( children: [ - FutureBuilder( + FutureBuilder>( future: _getMockGroups(), builder: (BuildContext context, AsyncSnapshot> snapshot) { - if (snapshot.connectionState == ConnectionState.waiting) { - return const Center( - child: TopCenteredMessage( - message: 'Data not yet available, show sceleton', - ), - ); - } else if (snapshot.hasError) { + if (snapshot.hasError) { return const Center( child: TopCenteredMessage( message: 'Error while loading group data.', ), ); - } else if (!snapshot.hasData || snapshot.data!.isEmpty) { + } + if (snapshot.connectionState == ConnectionState.done && + (!snapshot.hasData || snapshot.data!.isEmpty)) { return const Center( child: TopCenteredMessage( message: 'No groups created yet.', ), ); } - //return Center(child: Text('whatever')); - //return GroupTile(group: snapshot.data![0]); - return ListView.builder( - padding: const EdgeInsets.only(bottom: 85), - itemCount: snapshot.data!.length, - itemBuilder: (BuildContext context, int index) { - return GroupTile(group: snapshot.data![index]); - }, + final bool isLoading = + snapshot.connectionState == ConnectionState.waiting; + final List groups = isLoading + ? skeletonData + : (snapshot.data ?? []); + return Skeletonizer( + effect: PulseEffect( + from: Colors.grey[100]!, + to: Colors.grey[400]!, + 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, + itemBuilder: (BuildContext context, int index) { + return GroupTile(group: groups[index]); + }, + ), ); }, ), + + // Dein Button bleibt wie gehabt Positioned( bottom: 16, right: 16, diff --git a/lib/presentation/widgets/group_tile.dart b/lib/presentation/widgets/group_tile.dart index 783abcd..87d997b 100644 --- a/lib/presentation/widgets/group_tile.dart +++ b/lib/presentation/widgets/group_tile.dart @@ -59,7 +59,7 @@ class GroupTile extends StatelessWidget { horizontal: 10, ), decoration: BoxDecoration( - color: Colors.black26, + color: Colors.black38, borderRadius: BorderRadius.circular(12), ), child: Text( From 352fdc13f1698eb26d5f37f5b001b1a6dca80c1b Mon Sep 17 00:00:00 2001 From: mathiskirchner Date: Sat, 15 Nov 2025 21:25:12 +0100 Subject: [PATCH 026/141] added skeletonizer package requirement --- pubspec.yaml | 1 + 1 file changed, 1 insertion(+) diff --git a/pubspec.yaml b/pubspec.yaml index 5fa8019..ab6e30b 100644 --- a/pubspec.yaml +++ b/pubspec.yaml @@ -18,6 +18,7 @@ dependencies: drift_flutter: ^0.2.4 path_provider: ^2.1.5 provider: ^6.1.5 + skeletonizer: ^2.1.0+1 dev_dependencies: flutter_test: From d07bc6e8bbbb5eb3494e7359daa237933eaa8a6e Mon Sep 17 00:00:00 2001 From: mathiskirchner Date: Sat, 15 Nov 2025 21:43:03 +0100 Subject: [PATCH 027/141] increased skeleton item count & added daos as import --- .../views/main_menu/groups_view.dart | 22 +++---------------- lib/presentation/widgets/group_tile.dart | 2 +- 2 files changed, 4 insertions(+), 20 deletions(-) diff --git a/lib/presentation/views/main_menu/groups_view.dart b/lib/presentation/views/main_menu/groups_view.dart index e52cf58..623f7df 100644 --- a/lib/presentation/views/main_menu/groups_view.dart +++ b/lib/presentation/views/main_menu/groups_view.dart @@ -1,26 +1,11 @@ import 'package:flutter/material.dart'; -//import 'package:game_tracker/data/dto/group.dart'; -//import 'package:game_tracker/data/dto/player.dart'; +import 'package:game_tracker/data/dto/group.dart'; +import 'package:game_tracker/data/dto/player.dart'; import 'package:game_tracker/presentation/widgets/full_width_button.dart'; import 'package:game_tracker/presentation/widgets/group_tile.dart'; import 'package:game_tracker/presentation/widgets/top_centered_message.dart'; import 'package:skeletonizer/skeletonizer.dart'; -class Group { - final String id; - final String name; - final List members; - - Group({required this.id, required this.name, required this.members}); -} - -class Player { - final String id; - final String name; - - Player({required this.id, required this.name}); -} - class GroupsView extends StatefulWidget { const GroupsView({super.key}); @@ -91,7 +76,7 @@ class _GroupsViewState extends State { final player = Player(id: 'p1', name: 'Felix'); late final List skeletonData = List.filled( - 7, + 8, Group( id: 'g1', name: 'Weekend Warriors', @@ -155,7 +140,6 @@ class _GroupsViewState extends State { }, ), - // Dein Button bleibt wie gehabt Positioned( bottom: 16, right: 16, diff --git a/lib/presentation/widgets/group_tile.dart b/lib/presentation/widgets/group_tile.dart index 87d997b..bb96493 100644 --- a/lib/presentation/widgets/group_tile.dart +++ b/lib/presentation/widgets/group_tile.dart @@ -1,6 +1,6 @@ import 'package:flutter/material.dart'; import 'package:game_tracker/core/custom_theme.dart'; -import 'package:game_tracker/presentation/views/main_menu/groups_view.dart'; +import 'package:game_tracker/data/dto/group.dart'; class GroupTile extends StatelessWidget { const GroupTile({super.key, required this.group}); From 511124e323b48d9d52469289acdca6f1bfa82d13 Mon Sep 17 00:00:00 2001 From: mathiskirchner Date: Sat, 15 Nov 2025 21:57:31 +0100 Subject: [PATCH 028/141] reduced mock data loading time --- lib/presentation/views/main_menu/groups_view.dart | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/lib/presentation/views/main_menu/groups_view.dart b/lib/presentation/views/main_menu/groups_view.dart index 623f7df..4865d0a 100644 --- a/lib/presentation/views/main_menu/groups_view.dart +++ b/lib/presentation/views/main_menu/groups_view.dart @@ -15,7 +15,7 @@ class GroupsView extends StatefulWidget { class _GroupsViewState extends State { Future> _getMockGroups() async { - await Future.delayed(const Duration(seconds: 4)); + await Future.delayed(const Duration(seconds: 2)); final player1 = Player(id: 'p1', name: 'Felix'); final player2 = Player(id: 'p2', name: 'Yannick'); final player3 = Player(id: 'p3', name: 'Mathis'); From ac6f3d0f929a0f34afaa23bc737ca4feec0ec791 Mon Sep 17 00:00:00 2001 From: mathiskirchner Date: Sat, 15 Nov 2025 22:10:51 +0100 Subject: [PATCH 029/141] added missing const's --- lib/presentation/widgets/group_tile.dart | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/lib/presentation/widgets/group_tile.dart b/lib/presentation/widgets/group_tile.dart index bb96493..a874bc7 100644 --- a/lib/presentation/widgets/group_tile.dart +++ b/lib/presentation/widgets/group_tile.dart @@ -41,11 +41,11 @@ class GroupTile extends StatelessWidget { color: Colors.white, ), ), - SizedBox(width: 3), + const SizedBox(width: 3), const Icon(Icons.group), ], ), - SizedBox(height: 5), + const SizedBox(height: 5), Wrap( alignment: WrapAlignment.start, crossAxisAlignment: WrapCrossAlignment.start, @@ -64,7 +64,7 @@ class GroupTile extends StatelessWidget { ), child: Text( member.name, - style: TextStyle( + style: const TextStyle( fontSize: 17, fontWeight: FontWeight.bold, color: Colors.white, @@ -73,7 +73,7 @@ class GroupTile extends StatelessWidget { ), ], ), - SizedBox(height: 2.5), + const SizedBox(height: 2.5), ], ), ); From 7c34e517794c3679dc166a2381ef1757e6516684 Mon Sep 17 00:00:00 2001 From: mathiskirchner Date: Sat, 15 Nov 2025 22:33:00 +0100 Subject: [PATCH 030/141] fixed black bar behind nav bar by removing safearea --- lib/presentation/views/main_menu/groups_view.dart | 10 ++++++---- 1 file changed, 6 insertions(+), 4 deletions(-) diff --git a/lib/presentation/views/main_menu/groups_view.dart b/lib/presentation/views/main_menu/groups_view.dart index 4865d0a..0d5b993 100644 --- a/lib/presentation/views/main_menu/groups_view.dart +++ b/lib/presentation/views/main_menu/groups_view.dart @@ -1,4 +1,5 @@ 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/data/dto/player.dart'; import 'package:game_tracker/presentation/widgets/full_width_button.dart'; @@ -86,8 +87,10 @@ class _GroupsViewState extends State { @override Widget build(BuildContext context) { - return SafeArea( - child: Stack( + return Scaffold( + backgroundColor: CustomTheme.backgroundColor, + body: Stack( + alignment: Alignment.center, children: [ FutureBuilder>( future: _getMockGroups(), @@ -141,8 +144,7 @@ class _GroupsViewState extends State { ), Positioned( - bottom: 16, - right: 16, + bottom: 80, child: FullWidthButton(text: 'Create Group', onPressed: () {}), ), ], From b475237b9ea59a38f0ce906d53e7e5a47632b82e Mon Sep 17 00:00:00 2001 From: mathiskirchner Date: Sun, 16 Nov 2025 16:25:50 +0100 Subject: [PATCH 031/141] ignored text for players in skeleton loading --- lib/presentation/widgets/group_tile.dart | 15 +++++++++------ 1 file changed, 9 insertions(+), 6 deletions(-) diff --git a/lib/presentation/widgets/group_tile.dart b/lib/presentation/widgets/group_tile.dart index a874bc7..a317248 100644 --- a/lib/presentation/widgets/group_tile.dart +++ b/lib/presentation/widgets/group_tile.dart @@ -1,6 +1,7 @@ import 'package:flutter/material.dart'; import 'package:game_tracker/core/custom_theme.dart'; import 'package:game_tracker/data/dto/group.dart'; +import 'package:skeletonizer/skeletonizer.dart'; class GroupTile extends StatelessWidget { const GroupTile({super.key, required this.group}); @@ -62,12 +63,14 @@ class GroupTile extends StatelessWidget { color: Colors.black38, borderRadius: BorderRadius.circular(12), ), - child: Text( - member.name, - style: const TextStyle( - fontSize: 17, - fontWeight: FontWeight.bold, - color: Colors.white, + child: Skeleton.ignore( + child: Text( + member.name, + style: const TextStyle( + fontSize: 17, + fontWeight: FontWeight.bold, + color: Colors.white, + ), ), ), ), From 168d7748a98e2864b1b518a4d2617b867638bc19 Mon Sep 17 00:00:00 2001 From: mathiskirchner Date: Sun, 16 Nov 2025 16:26:08 +0100 Subject: [PATCH 032/141] added todo for getAllGroups tests --- test/db_tests/group_test.dart | 1 + 1 file changed, 1 insertion(+) diff --git a/test/db_tests/group_test.dart b/test/db_tests/group_test.dart index a8fbcd5..d9e2c32 100644 --- a/test/db_tests/group_test.dart +++ b/test/db_tests/group_test.dart @@ -36,6 +36,7 @@ void main() { await database.close(); }); + //TODO: test getAllGroups method test('group and group members gets added correctly', () async { await database.groupDao.addGroup(group: testgroup); From 640830d8ab39e07339bf6a966d620f67f205fde9 Mon Sep 17 00:00:00 2001 From: mathiskirchner Date: Sun, 16 Nov 2025 16:26:28 +0100 Subject: [PATCH 033/141] fixed getAllGroups not returning members --- lib/data/dao/group_dao.dart | 11 ++++++++--- 1 file changed, 8 insertions(+), 3 deletions(-) diff --git a/lib/data/dao/group_dao.dart b/lib/data/dao/group_dao.dart index 1f0e2c8..ffcb84a 100644 --- a/lib/data/dao/group_dao.dart +++ b/lib/data/dao/group_dao.dart @@ -14,9 +14,14 @@ 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); + }), + ); } /// Retrieves a [Group] by its [groupId], including its members. From 2dad822d79582686d82548a3af0e77d12ec0e2ad Mon Sep 17 00:00:00 2001 From: mathiskirchner Date: Sun, 16 Nov 2025 16:34:51 +0100 Subject: [PATCH 034/141] add sample groups with sample members at app startup --- lib/main.dart | 73 +++++++++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 73 insertions(+) diff --git a/lib/main.dart b/lib/main.dart index 98c40f8..b19eb45 100644 --- a/lib/main.dart +++ b/lib/main.dart @@ -1,6 +1,8 @@ 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/custom_navigation_bar.dart'; import 'package:provider/provider.dart'; @@ -19,6 +21,7 @@ class GameTracker extends StatelessWidget { @override Widget build(BuildContext context) { + addSampleGroupData(context); return MaterialApp( debugShowCheckedModeBanner: false, title: 'Game Tracker', @@ -39,4 +42,74 @@ class GameTracker extends StatelessWidget { home: const CustomNavigationBar(), ); } + + Future addSampleGroupData(BuildContext context) async { + final db = Provider.of(context, listen: false); + if (await db.groupDao.getGroupCount() == 0) { + final List allPlayers = [ + Player(id: '1', name: 'Alex'), + Player(id: '2', name: 'Ben'), + Player(id: '3', name: 'Chris'), + Player(id: '4', name: 'Daniel'), + Player(id: '5', name: 'Max Mustermann'), + Player(id: '6', name: 'Sebastian'), + Player(id: '7', name: 'Jonathan'), + Player(id: '8', name: 'Alexander'), + ]; + + // 2. Erstelle und füge 8 Gruppen mit unterschiedlicher Spieleranzahl hinzu + await db.groupDao.addGroup( + group: Group( + id: '1', + name: 'Anfänger', + members: allPlayers.sublist(0, 3), + ), + ); // 3 Spieler + await db.groupDao.addGroup( + group: Group( + id: '2', + name: 'Die glorreichen Sieben', + members: allPlayers.sublist(0, 7), + ), + ); // 7 Spieler + await db.groupDao.addGroup( + group: Group( + id: '3', + name: 'Profis', + members: allPlayers.sublist(4, 8), + ), + ); // 4 Spieler + await db.groupDao.addGroup( + group: Group( + id: '4', + name: 'Duo Infernale', + members: [allPlayers[0], allPlayers[7]], + ), + ); // 2 Spieler + await db.groupDao.addGroup( + group: Group( + id: '5', + name: 'Die fantastischen Fünf', + members: allPlayers.sublist(1, 6), + ), + ); // 5 Spieler + await db.groupDao.addGroup( + group: Group( + id: '6', + name: 'Feierabend-Zocker', + members: allPlayers.sublist(0, 6), + ), + ); // 6 Spieler + await db.groupDao.addGroup( + group: Group(id: '7', name: 'Alle Mann an Bord!', members: allPlayers), + ); // 8 Spieler + await db.groupDao.addGroup( + group: Group( + id: '8', + name: 'Testgruppe Alpha', + members: [allPlayers[1], allPlayers[3]], + ), + ); + } + } } From 2dd4f52336dfab9db96fda0de03bb80ad107fa28 Mon Sep 17 00:00:00 2001 From: mathiskirchner Date: Sun, 16 Nov 2025 16:42:18 +0100 Subject: [PATCH 035/141] removed sample groups from groups view --- .../views/main_menu/groups_view.dart | 82 ++++--------------- 1 file changed, 18 insertions(+), 64 deletions(-) diff --git a/lib/presentation/views/main_menu/groups_view.dart b/lib/presentation/views/main_menu/groups_view.dart index 0d5b993..c5f8def 100644 --- a/lib/presentation/views/main_menu/groups_view.dart +++ b/lib/presentation/views/main_menu/groups_view.dart @@ -1,10 +1,12 @@ 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/widgets/full_width_button.dart'; import 'package:game_tracker/presentation/widgets/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 StatefulWidget { @@ -15,76 +17,25 @@ class GroupsView extends StatefulWidget { } class _GroupsViewState extends State { - Future> _getMockGroups() async { - await Future.delayed(const Duration(seconds: 2)); - final player1 = Player(id: 'p1', name: 'Felix'); - final player2 = Player(id: 'p2', name: 'Yannick'); - final player3 = Player(id: 'p3', name: 'Mathis'); - final player4 = Player(id: 'p4', name: 'Petrus'); + late Future> _allGroupsFuture; - return [ - Group( - id: 'g1', - name: 'Weekend Warriors', - members: [ - player1, - player2, - player4, - player3, - player1, - player4, - player2, - ], - ), - Group(id: 'g2', name: 'Strategy Masters', members: [player3, player4]), - Group( - id: 'g3', - name: 'The Cardboard Crew', - members: [player1, player2, player3, player4], - ), - Group( - id: 'g4', - name: 'Gamers', - members: [player1, player3, player1, player4], - ), - Group( - id: 'g4', - name: 'The Group', - members: [player4, player1, player3, player4, player3], - ), - Group( - id: 'g4', - name: 'Friends', - members: [player4, player1, player3, player4], - ), - Group( - id: 'g4', - name: 'Sample Group', - members: [player1, player1, player4, player3], - ), - Group( - id: 'g4', - name: 'The Group', - members: [player1, player1, player3, player4], - ), - Group( - id: 'g4', - name: 'The Best', - members: [player1, player3, player1, player4, player1], - ), - ]; - } - - final player = Player(id: 'p1', name: 'Felix'); + final player = Player(id: 'p1', name: 'Sample'); late final List skeletonData = List.filled( 8, Group( - id: 'g1', - name: 'Weekend Warriors', + id: '0', + name: 'Sample Game', members: [player, player, player, player], ), ); + @override + void initState() { + super.initState(); + final db = Provider.of(context, listen: false); + _allGroupsFuture = db.groupDao.getAllGroups(); + } + @override Widget build(BuildContext context) { return Scaffold( @@ -93,7 +44,7 @@ class _GroupsViewState extends State { alignment: Alignment.center, children: [ FutureBuilder>( - future: _getMockGroups(), + future: _allGroupsFuture, builder: (BuildContext context, AsyncSnapshot> snapshot) { if (snapshot.hasError) { @@ -134,8 +85,11 @@ class _GroupsViewState extends State { ), child: ListView.builder( padding: const EdgeInsets.only(bottom: 85), - itemCount: groups.length, + itemCount: groups.length + 1, itemBuilder: (BuildContext context, int index) { + if (index == groups.length) { + return const SizedBox(height: 60); + } return GroupTile(group: groups[index]); }, ), From 3bd522df6e3b355f81af29e5b9464fef68e13afa Mon Sep 17 00:00:00 2001 From: mathiskirchner Date: Sun, 16 Nov 2025 18:29:27 +0100 Subject: [PATCH 036/141] change colors to fit home page --- lib/presentation/views/main_menu/groups_view.dart | 4 ++-- lib/presentation/widgets/group_tile.dart | 8 +++----- 2 files changed, 5 insertions(+), 7 deletions(-) diff --git a/lib/presentation/views/main_menu/groups_view.dart b/lib/presentation/views/main_menu/groups_view.dart index c5f8def..6a3f404 100644 --- a/lib/presentation/views/main_menu/groups_view.dart +++ b/lib/presentation/views/main_menu/groups_view.dart @@ -69,8 +69,8 @@ class _GroupsViewState extends State { : (snapshot.data ?? []); return Skeletonizer( effect: PulseEffect( - from: Colors.grey[100]!, - to: Colors.grey[400]!, + from: Colors.grey[800]!, + to: Colors.grey[600]!, duration: const Duration(milliseconds: 800), ), enabled: isLoading, diff --git a/lib/presentation/widgets/group_tile.dart b/lib/presentation/widgets/group_tile.dart index a317248..f61d3ce 100644 --- a/lib/presentation/widgets/group_tile.dart +++ b/lib/presentation/widgets/group_tile.dart @@ -15,7 +15,8 @@ class GroupTile extends StatelessWidget { margin: const EdgeInsets.symmetric(horizontal: 20, vertical: 10), padding: const EdgeInsets.symmetric(vertical: 5, horizontal: 10), decoration: BoxDecoration( - color: CustomTheme.secondaryColor, + color: CustomTheme.boxColor, + border: Border.all(color: CustomTheme.boxBorder), borderRadius: BorderRadius.circular(12), ), child: Column( @@ -30,7 +31,6 @@ class GroupTile extends StatelessWidget { style: const TextStyle( fontWeight: FontWeight.bold, fontSize: 20, - color: Colors.white, ), ), const Spacer(), @@ -39,11 +39,10 @@ class GroupTile extends StatelessWidget { style: const TextStyle( fontWeight: FontWeight.w900, fontSize: 20, - color: Colors.white, ), ), const SizedBox(width: 3), - const Icon(Icons.group), + Icon(Icons.group), ], ), const SizedBox(height: 5), @@ -69,7 +68,6 @@ class GroupTile extends StatelessWidget { style: const TextStyle( fontSize: 17, fontWeight: FontWeight.bold, - color: Colors.white, ), ), ), From a707990356ef3d9292b6ce43e3a95b4f381c9061 Mon Sep 17 00:00:00 2001 From: mathiskirchner Date: Sun, 16 Nov 2025 18:36:38 +0100 Subject: [PATCH 037/141] added new color: onBoxColor --- lib/core/custom_theme.dart | 1 + 1 file changed, 1 insertion(+) 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( From d931e85e9f1eca94a9f64f97863520b8a88142b6 Mon Sep 17 00:00:00 2001 From: mathiskirchner Date: Sun, 16 Nov 2025 18:36:54 +0100 Subject: [PATCH 038/141] changed member tile color --- lib/presentation/widgets/group_tile.dart | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/lib/presentation/widgets/group_tile.dart b/lib/presentation/widgets/group_tile.dart index f61d3ce..11d3e47 100644 --- a/lib/presentation/widgets/group_tile.dart +++ b/lib/presentation/widgets/group_tile.dart @@ -59,7 +59,7 @@ class GroupTile extends StatelessWidget { horizontal: 10, ), decoration: BoxDecoration( - color: Colors.black38, + color: CustomTheme.onBoxColor, borderRadius: BorderRadius.circular(12), ), child: Skeleton.ignore( From a6f40456d8fe0297bdd7ef697a0715d0dc2bd851 Mon Sep 17 00:00:00 2001 From: mathiskirchner Date: Sun, 16 Nov 2025 18:44:56 +0100 Subject: [PATCH 039/141] added missing const --- lib/presentation/widgets/group_tile.dart | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/lib/presentation/widgets/group_tile.dart b/lib/presentation/widgets/group_tile.dart index 11d3e47..ce6ba34 100644 --- a/lib/presentation/widgets/group_tile.dart +++ b/lib/presentation/widgets/group_tile.dart @@ -42,7 +42,7 @@ class GroupTile extends StatelessWidget { ), ), const SizedBox(width: 3), - Icon(Icons.group), + const Icon(Icons.group), ], ), const SizedBox(height: 5), From 02735b5b1dfd27daa9d349244dbd437a41b27751 Mon Sep 17 00:00:00 2001 From: Felix Kirchner Date: Sun, 16 Nov 2025 18:58:01 +0100 Subject: [PATCH 040/141] Added missing test --- test/db_tests/group_test.dart | 24 +++++++++++++++++++++++- 1 file changed, 23 insertions(+), 1 deletion(-) diff --git a/test/db_tests/group_test.dart b/test/db_tests/group_test.dart index d9e2c32..59ba686 100644 --- a/test/db_tests/group_test.dart +++ b/test/db_tests/group_test.dart @@ -36,7 +36,29 @@ void main() { await database.close(); }); - //TODO: test getAllGroups method + test('all groups get fetched correclty', () async { + final testgroup2 = Group( + id: 'gr2', + name: 'Second Group', + members: [player2, player3, player4], + ); + 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); + + 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); + }); + test('group and group members gets added correctly', () async { await database.groupDao.addGroup(group: testgroup); From 5c09dfb47dae81f736311908631e6cdff3f23e73 Mon Sep 17 00:00:00 2001 From: Felix Kirchner Date: Sun, 16 Nov 2025 19:01:58 +0100 Subject: [PATCH 041/141] Added fallbacks for groups when same group already exists --- lib/data/dao/group_dao.dart | 48 ++++++++++++++++++++----------------- 1 file changed, 26 insertions(+), 22 deletions(-) diff --git a/lib/data/dao/group_dao.dart b/lib/data/dao/group_dao.dart index ffcb84a..8eb3a1a 100644 --- a/lib/data/dao/group_dao.dart +++ b/lib/data/dao/group_dao.dart @@ -38,28 +38,32 @@ class GroupDao extends DatabaseAccessor with _$GroupDaoMixin { /// Adds a new group with the given [id] and [name] to the database. /// This method also adds the group's members to the [PlayerGroupTable]. - Future addGroup({required Group group}) async { - await db.transaction(() async { - await into( - groupTable, - ).insert(GroupTableCompanion.insert(id: group.id, name: group.name)); - 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)), - ); - }); + 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)); + 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. From 74402f2e04de52ef7e32d8ca6740b9cbefd2cd10 Mon Sep 17 00:00:00 2001 From: Felix Kirchner Date: Sun, 16 Nov 2025 19:02:20 +0100 Subject: [PATCH 042/141] Added fallbacks for players when same player already exists --- lib/data/dao/player_dao.dart | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/lib/data/dao/player_dao.dart b/lib/data/dao/player_dao.dart index 976d4b0..591634c 100644 --- a/lib/data/dao/player_dao.dart +++ b/lib/data/dao/player_dao.dart @@ -26,14 +26,14 @@ class PlayerDao extends DatabaseAccessor with _$PlayerDaoMixin { /// Adds a new [player] to the database. /// If a player with the same ID already exists, updates their name to /// the new one. - Future addPlayer({required Player player}) async { + Future addPlayer({required Player player}) async { if (!await playerExists(playerId: player.id)) { await into( playerTable, ).insert(PlayerTableCompanion.insert(id: player.id, name: player.name)); - } else { - await updatePlayername(playerId: player.id, newName: player.name); + return true; } + return false; } /// Deletes the player with the given [id] from the database. From e709edbf7a7406165ec8c72dc86f11e6538c77ae Mon Sep 17 00:00:00 2001 From: Felix Kirchner Date: Sun, 16 Nov 2025 19:12:38 +0100 Subject: [PATCH 043/141] Added getAllPlayers test --- test/db_tests/player_test.dart | 19 +++++++++++++++++++ 1 file changed, 19 insertions(+) diff --git a/test/db_tests/player_test.dart b/test/db_tests/player_test.dart index 7fb9152..9f12faa 100644 --- a/test/db_tests/player_test.dart +++ b/test/db_tests/player_test.dart @@ -24,6 +24,25 @@ void main() { }); group('player tests', () { + test('all players get fetched correclty', () async { + final testPlayer2 = Player(id: 'gr2', name: 'Second Group'); + 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); + + final fetchedPlayer2 = allPlayers.firstWhere( + (g) => g.id == testPlayer2.id, + ); + expect(fetchedPlayer2.name, testPlayer2.name); + }); + test('players get inserted correcly ', () async { await database.playerDao.addPlayer(player: testPlayer); final result = await database.playerDao.getPlayerById( From d3de0fda49c385eac8bb65a78e1d657c117daf4e Mon Sep 17 00:00:00 2001 From: Felix Kirchner Date: Sun, 16 Nov 2025 19:12:49 +0100 Subject: [PATCH 044/141] Updates getAllGroups test --- test/db_tests/group_test.dart | 207 ++++++++++++++++++---------------- 1 file changed, 108 insertions(+), 99 deletions(-) diff --git a/test/db_tests/group_test.dart b/test/db_tests/group_test.dart index 59ba686..e8e6316 100644 --- a/test/db_tests/group_test.dart +++ b/test/db_tests/group_test.dart @@ -35,137 +35,146 @@ void main() { tearDown(() async { await database.close(); }); + group('group tests', () { + test('all groups get fetched correclty', () async { + final testgroup2 = Group( + id: 'gr2', + name: 'Second Group', + members: [player2, player3, player4], + ); + await database.groupDao.addGroup(group: testgroup); + await database.groupDao.addGroup(group: testgroup2); - test('all groups get fetched correclty', () async { - final testgroup2 = Group( - id: 'gr2', - name: 'Second Group', - members: [player2, player3, player4], - ); - await database.groupDao.addGroup(group: testgroup); - await database.groupDao.addGroup(group: testgroup2); + final allGroups = await database.groupDao.getAllGroups(); + expect(allGroups.length, 2); - 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); - 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); + 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); + }); - 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); - }); + test('group and group members gets added correctly', () async { + await database.groupDao.addGroup(group: testgroup); - test('group and group members gets added correctly', () async { - await database.groupDao.addGroup(group: testgroup); + final result = await database.groupDao.getGroupById( + groupId: testgroup.id, + ); - final result = await database.groupDao.getGroupById(groupId: testgroup.id); + expect(result.id, testgroup.id); + expect(result.name, testgroup.name); - expect(result.id, testgroup.id); - expect(result.name, testgroup.name); + 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.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); - } - }); + test('group gets deleted correctly', () async { + await database.groupDao.addGroup(group: testgroup); - 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 groupDeleted = await database.groupDao.deleteGroup( - groupId: testgroup.id, - ); - expect(groupDeleted, true); + final groupExists = await database.groupDao.groupExists( + groupId: testgroup.id, + ); + expect(groupExists, false); + }); - 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); - test('group name gets updated correcly ', () async { - await database.groupDao.addGroup(group: testgroup); + const newGroupName = 'new group name'; - const newGroupName = 'new group name'; + await database.groupDao.updateGroupname( + groupId: testgroup.id, + newName: newGroupName, + ); - await database.groupDao.updateGroupname( - groupId: testgroup.id, - newName: newGroupName, - ); + final result = await database.groupDao.getGroupById( + groupId: testgroup.id, + ); + expect(result.name, 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); - test('Adding player to group works correctly', () async { - await database.groupDao.addGroup(group: testgroup); + await database.playerGroupDao.addPlayerToGroup( + player: player4, + groupId: testgroup.id, + ); - await database.playerGroupDao.addPlayerToGroup( - player: player4, - groupId: testgroup.id, - ); + final playerAdded = await database.playerGroupDao.isPlayerInGroup( + playerId: player4.id, + groupId: testgroup.id, + ); - final playerAdded = await database.playerGroupDao.isPlayerInGroup( - playerId: player4.id, - groupId: testgroup.id, - ); + expect(playerAdded, true); - expect(playerAdded, true); + final playerAdded2 = await database.playerGroupDao.isPlayerInGroup( + playerId: 'a', + groupId: testgroup.id, + ); - final playerAdded2 = await database.playerGroupDao.isPlayerInGroup( - playerId: 'a', - groupId: testgroup.id, - ); + expect(playerAdded2, false); - expect(playerAdded2, false); + expect(playerAdded, true); - expect(playerAdded, true); + final result = await database.groupDao.getGroupById( + groupId: testgroup.id, + ); + expect(result.members.length, testgroup.members.length + 1); - 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); + }); - final addedPlayer = result.members.firstWhere((p) => p.id == player4.id); - expect(addedPlayer.name, player4.name); - }); + test('Removing player from group works correctly', () async { + await database.groupDao.addGroup(group: testgroup); - test('Removing player from group works correctly', () async { - await database.groupDao.addGroup(group: testgroup); + final playerToRemove = testgroup.members[0]; - final playerToRemove = testgroup.members[0]; + final removed = await database.playerGroupDao.removePlayerFromGroup( + playerId: playerToRemove.id, + groupId: testgroup.id, + ); + expect(removed, true); - 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 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); + }); - 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); - test('get group count works correctly', () async { - final initialCount = await database.groupDao.getGroupCount(); - expect(initialCount, 0); + await database.groupDao.addGroup(group: testgroup); - await database.groupDao.addGroup(group: testgroup); + final groupAdded = await database.groupDao.getGroupCount(); + expect(groupAdded, 1); - final groupAdded = await database.groupDao.getGroupCount(); - expect(groupAdded, 1); + final groupRemoved = await database.groupDao.deleteGroup( + groupId: testgroup.id, + ); + expect(groupRemoved, true); - final groupRemoved = await database.groupDao.deleteGroup( - groupId: testgroup.id, - ); - expect(groupRemoved, true); - - final finalCount = await database.groupDao.getGroupCount(); - expect(finalCount, 0); + final finalCount = await database.groupDao.getGroupCount(); + expect(finalCount, 0); + }); }); } From 8d8d4319d248ec6a7934bdc126df419ed4923e3a Mon Sep 17 00:00:00 2001 From: mathiskirchner Date: Sun, 16 Nov 2025 19:37:51 +0100 Subject: [PATCH 045/141] change Mediaquery.of to .sizeOf --- lib/presentation/widgets/full_width_button.dart | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/lib/presentation/widgets/full_width_button.dart b/lib/presentation/widgets/full_width_button.dart index 2af6abe..bd18c64 100644 --- a/lib/presentation/widgets/full_width_button.dart +++ b/lib/presentation/widgets/full_width_button.dart @@ -12,7 +12,7 @@ class FullWidthButton extends StatelessWidget { return ElevatedButton( onPressed: onPressed, style: ElevatedButton.styleFrom( - minimumSize: Size(MediaQuery.of(context).size.width * 0.90, 60), + minimumSize: Size(MediaQuery.sizeOf(context).width * 0.9, 60), backgroundColor: CustomTheme.primaryColor, shape: RoundedRectangleBorder(borderRadius: BorderRadius.circular(12)), ), From 38466c6056a8e05d6d8eded63dcc37ac68cdd691 Mon Sep 17 00:00:00 2001 From: mathiskirchner Date: Sun, 16 Nov 2025 19:38:08 +0100 Subject: [PATCH 046/141] added title and icon to gamehistoryview --- lib/presentation/views/main_menu/game_history_view.dart | 8 +++++++- 1 file changed, 7 insertions(+), 1 deletion(-) diff --git a/lib/presentation/views/main_menu/game_history_view.dart b/lib/presentation/views/main_menu/game_history_view.dart index f620cd7..3642a88 100644 --- a/lib/presentation/views/main_menu/game_history_view.dart +++ b/lib/presentation/views/main_menu/game_history_view.dart @@ -178,9 +178,15 @@ class _GameHistoryViewState extends State { Widget gameHistoryListView(allGameData, suggestedGameData) { if (suggestedGameData.isEmpty && allGameData.isEmpty) { - return TopCenteredMessage(message: "Keine Spiele erstellt"); + return TopCenteredMessage( + icon: Icons.info, + title: "Info", + message: "Keine Spiele erstellt", + ); } else if (suggestedGameData.isEmpty) { return TopCenteredMessage( + icon: Icons.search, + title: "Info", message: "Kein Spiel mit den Suchparametern gefunden.", ); } From deab074885001a0f4ef6451ebdaeaa1fdfff6294 Mon Sep 17 00:00:00 2001 From: mathiskirchner Date: Sun, 16 Nov 2025 19:38:26 +0100 Subject: [PATCH 047/141] changed font sizes & tile width --- lib/presentation/widgets/{ => tiles}/group_tile.dart | 11 +++++------ 1 file changed, 5 insertions(+), 6 deletions(-) rename lib/presentation/widgets/{ => tiles}/group_tile.dart (90%) diff --git a/lib/presentation/widgets/group_tile.dart b/lib/presentation/widgets/tiles/group_tile.dart similarity index 90% rename from lib/presentation/widgets/group_tile.dart rename to lib/presentation/widgets/tiles/group_tile.dart index ce6ba34..448c68c 100644 --- a/lib/presentation/widgets/group_tile.dart +++ b/lib/presentation/widgets/tiles/group_tile.dart @@ -11,8 +11,7 @@ class GroupTile extends StatelessWidget { @override Widget build(BuildContext context) { return Container( - width: MediaQuery.of(context).size.width * 0.90, - margin: const EdgeInsets.symmetric(horizontal: 20, vertical: 10), + margin: const EdgeInsets.symmetric(horizontal: 12, vertical: 10), padding: const EdgeInsets.symmetric(vertical: 5, horizontal: 10), decoration: BoxDecoration( color: CustomTheme.boxColor, @@ -30,7 +29,7 @@ class GroupTile extends StatelessWidget { overflow: TextOverflow.ellipsis, style: const TextStyle( fontWeight: FontWeight.bold, - fontSize: 20, + fontSize: 18, ), ), const Spacer(), @@ -38,11 +37,11 @@ class GroupTile extends StatelessWidget { '${group.members.length}', style: const TextStyle( fontWeight: FontWeight.w900, - fontSize: 20, + fontSize: 18, ), ), const SizedBox(width: 3), - const Icon(Icons.group), + const Icon(Icons.group, size: 22), ], ), const SizedBox(height: 5), @@ -66,7 +65,7 @@ class GroupTile extends StatelessWidget { child: Text( member.name, style: const TextStyle( - fontSize: 17, + fontSize: 14, fontWeight: FontWeight.bold, ), ), From 258f610e289b0c7bae92babbac77111d4bc11b85 Mon Sep 17 00:00:00 2001 From: mathiskirchner Date: Sun, 16 Nov 2025 19:39:34 +0100 Subject: [PATCH 048/141] added icons & titles to top contered messages --- lib/presentation/views/main_menu/groups_view.dart | 8 ++++++-- 1 file changed, 6 insertions(+), 2 deletions(-) diff --git a/lib/presentation/views/main_menu/groups_view.dart b/lib/presentation/views/main_menu/groups_view.dart index 6a3f404..7b79a53 100644 --- a/lib/presentation/views/main_menu/groups_view.dart +++ b/lib/presentation/views/main_menu/groups_view.dart @@ -4,7 +4,7 @@ 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/full_width_button.dart'; -import 'package:game_tracker/presentation/widgets/group_tile.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'; @@ -50,7 +50,9 @@ class _GroupsViewState extends State { if (snapshot.hasError) { return const Center( child: TopCenteredMessage( - message: 'Error while loading group data.', + icon: Icons.report, + title: "Error", + message: 'Group data couldn\'t\nbe loaded.', ), ); } @@ -58,6 +60,8 @@ class _GroupsViewState extends State { (!snapshot.hasData || snapshot.data!.isEmpty)) { return const Center( child: TopCenteredMessage( + icon: Icons.info, + title: "Info", message: 'No groups created yet.', ), ); From c1e032208cd79d6d28d01b2963ef8f70b89e786d Mon Sep 17 00:00:00 2001 From: mathiskirchner Date: Sun, 16 Nov 2025 19:39:48 +0100 Subject: [PATCH 049/141] added icons, titles and changed font size --- .../widgets/top_centered_message.dart | 28 +++++++++++++++---- 1 file changed, 23 insertions(+), 5 deletions(-) diff --git a/lib/presentation/widgets/top_centered_message.dart b/lib/presentation/widgets/top_centered_message.dart index df8dcb1..af317d8 100644 --- a/lib/presentation/widgets/top_centered_message.dart +++ b/lib/presentation/widgets/top_centered_message.dart @@ -1,9 +1,16 @@ import 'package:flutter/material.dart'; class TopCenteredMessage extends StatelessWidget { - const TopCenteredMessage({super.key, required this.message}); + 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) { @@ -11,10 +18,21 @@ class TopCenteredMessage extends StatelessWidget { padding: const EdgeInsets.only(top: 100), margin: const EdgeInsets.symmetric(horizontal: 10), alignment: Alignment.topCenter, - child: Text( - message, - style: const TextStyle(fontSize: 20), - textAlign: TextAlign.center, + child: Column( + children: [ + Icon(icon, size: 45), + 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, + ), + ], ), ); } From accc1899493beddb472312248e4c15227dc9f60f Mon Sep 17 00:00:00 2001 From: mathiskirchner Date: Sun, 16 Nov 2025 19:50:54 +0100 Subject: [PATCH 050/141] decreased number of tiles in skeleton --- lib/presentation/views/main_menu/groups_view.dart | 13 +++++++------ 1 file changed, 7 insertions(+), 6 deletions(-) diff --git a/lib/presentation/views/main_menu/groups_view.dart b/lib/presentation/views/main_menu/groups_view.dart index 7b79a53..11e2544 100644 --- a/lib/presentation/views/main_menu/groups_view.dart +++ b/lib/presentation/views/main_menu/groups_view.dart @@ -21,11 +21,11 @@ class _GroupsViewState extends State { final player = Player(id: 'p1', name: 'Sample'); late final List skeletonData = List.filled( - 8, + 7, Group( id: '0', name: 'Sample Game', - members: [player, player, player, player], + members: [player, player, player, player, player, player], ), ); @@ -68,16 +68,17 @@ class _GroupsViewState extends State { } final bool isLoading = snapshot.connectionState == ConnectionState.waiting; - final List groups = isLoading - ? skeletonData - : (snapshot.data ?? []); + final List groups = skeletonData; + //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, + enabled: true, enableSwitchAnimation: true, switchAnimationConfig: const SwitchAnimationConfig( duration: Duration(milliseconds: 200), From 4befc85c9f9492b6bb3ce0eaa412aba9cf7a1354 Mon Sep 17 00:00:00 2001 From: mathiskirchner Date: Sun, 16 Nov 2025 19:52:31 +0100 Subject: [PATCH 051/141] added missing const --- lib/presentation/widgets/top_centered_message.dart | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/lib/presentation/widgets/top_centered_message.dart b/lib/presentation/widgets/top_centered_message.dart index af317d8..a5deea2 100644 --- a/lib/presentation/widgets/top_centered_message.dart +++ b/lib/presentation/widgets/top_centered_message.dart @@ -21,7 +21,7 @@ class TopCenteredMessage extends StatelessWidget { child: Column( children: [ Icon(icon, size: 45), - SizedBox(height: 10), + const SizedBox(height: 10), Text( title, style: const TextStyle(fontSize: 18, fontWeight: FontWeight.bold), From 9ffb7d6ca3c684379eeb34d1e6893fe3a9cceac4 Mon Sep 17 00:00:00 2001 From: mathiskirchner Date: Sun, 16 Nov 2025 19:53:32 +0100 Subject: [PATCH 052/141] changed skeleton to only show when loading --- lib/presentation/views/main_menu/groups_view.dart | 9 ++++----- 1 file changed, 4 insertions(+), 5 deletions(-) diff --git a/lib/presentation/views/main_menu/groups_view.dart b/lib/presentation/views/main_menu/groups_view.dart index 11e2544..8b3bffe 100644 --- a/lib/presentation/views/main_menu/groups_view.dart +++ b/lib/presentation/views/main_menu/groups_view.dart @@ -68,17 +68,16 @@ class _GroupsViewState extends State { } final bool isLoading = snapshot.connectionState == ConnectionState.waiting; - final List groups = skeletonData; - //final List groups = isLoading - // ? skeletonData - // : (snapshot.data ?? []); + 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: true, + enabled: isLoading, enableSwitchAnimation: true, switchAnimationConfig: const SwitchAnimationConfig( duration: Duration(milliseconds: 200), From a1d57fc42424dd625e7f79b83de54c49c156a20f Mon Sep 17 00:00:00 2001 From: mathiskirchner Date: Sun, 16 Nov 2025 20:04:59 +0100 Subject: [PATCH 053/141] removed sample data for group view --- lib/main.dart | 73 --------------------------------------------------- 1 file changed, 73 deletions(-) diff --git a/lib/main.dart b/lib/main.dart index b19eb45..98c40f8 100644 --- a/lib/main.dart +++ b/lib/main.dart @@ -1,8 +1,6 @@ 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/custom_navigation_bar.dart'; import 'package:provider/provider.dart'; @@ -21,7 +19,6 @@ class GameTracker extends StatelessWidget { @override Widget build(BuildContext context) { - addSampleGroupData(context); return MaterialApp( debugShowCheckedModeBanner: false, title: 'Game Tracker', @@ -42,74 +39,4 @@ class GameTracker extends StatelessWidget { home: const CustomNavigationBar(), ); } - - Future addSampleGroupData(BuildContext context) async { - final db = Provider.of(context, listen: false); - if (await db.groupDao.getGroupCount() == 0) { - final List allPlayers = [ - Player(id: '1', name: 'Alex'), - Player(id: '2', name: 'Ben'), - Player(id: '3', name: 'Chris'), - Player(id: '4', name: 'Daniel'), - Player(id: '5', name: 'Max Mustermann'), - Player(id: '6', name: 'Sebastian'), - Player(id: '7', name: 'Jonathan'), - Player(id: '8', name: 'Alexander'), - ]; - - // 2. Erstelle und füge 8 Gruppen mit unterschiedlicher Spieleranzahl hinzu - await db.groupDao.addGroup( - group: Group( - id: '1', - name: 'Anfänger', - members: allPlayers.sublist(0, 3), - ), - ); // 3 Spieler - await db.groupDao.addGroup( - group: Group( - id: '2', - name: 'Die glorreichen Sieben', - members: allPlayers.sublist(0, 7), - ), - ); // 7 Spieler - await db.groupDao.addGroup( - group: Group( - id: '3', - name: 'Profis', - members: allPlayers.sublist(4, 8), - ), - ); // 4 Spieler - await db.groupDao.addGroup( - group: Group( - id: '4', - name: 'Duo Infernale', - members: [allPlayers[0], allPlayers[7]], - ), - ); // 2 Spieler - await db.groupDao.addGroup( - group: Group( - id: '5', - name: 'Die fantastischen Fünf', - members: allPlayers.sublist(1, 6), - ), - ); // 5 Spieler - await db.groupDao.addGroup( - group: Group( - id: '6', - name: 'Feierabend-Zocker', - members: allPlayers.sublist(0, 6), - ), - ); // 6 Spieler - await db.groupDao.addGroup( - group: Group(id: '7', name: 'Alle Mann an Bord!', members: allPlayers), - ); // 8 Spieler - await db.groupDao.addGroup( - group: Group( - id: '8', - name: 'Testgruppe Alpha', - members: [allPlayers[1], allPlayers[3]], - ), - ); - } - } } From 10a45ac1f0cae5c0b00a8476a0a9e21fd4831df4 Mon Sep 17 00:00:00 2001 From: mathiskirchner Date: Sun, 16 Nov 2025 20:11:10 +0100 Subject: [PATCH 054/141] removed unneccessary double quotes --- lib/presentation/views/main_menu/groups_view.dart | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/lib/presentation/views/main_menu/groups_view.dart b/lib/presentation/views/main_menu/groups_view.dart index 8b3bffe..7f1f32d 100644 --- a/lib/presentation/views/main_menu/groups_view.dart +++ b/lib/presentation/views/main_menu/groups_view.dart @@ -51,7 +51,7 @@ class _GroupsViewState extends State { return const Center( child: TopCenteredMessage( icon: Icons.report, - title: "Error", + title: 'Error', message: 'Group data couldn\'t\nbe loaded.', ), ); @@ -61,7 +61,7 @@ class _GroupsViewState extends State { return const Center( child: TopCenteredMessage( icon: Icons.info, - title: "Info", + title: 'Info', message: 'No groups created yet.', ), ); From a9dd3216cc18ecc8d7d842776c1cd3081f5c410b Mon Sep 17 00:00:00 2001 From: Felix Kirchner Date: Sun, 16 Nov 2025 20:51:28 +0100 Subject: [PATCH 055/141] Implemented skeleton --- .../views/main_menu/home_view.dart | 260 +++++++++++------- pubspec.yaml | 1 + 2 files changed, 158 insertions(+), 103 deletions(-) diff --git a/lib/presentation/views/main_menu/home_view.dart b/lib/presentation/views/main_menu/home_view.dart index 141af77..57c4f61 100644 --- a/lib/presentation/views/main_menu/home_view.dart +++ b/lib/presentation/views/main_menu/home_view.dart @@ -5,6 +5,7 @@ import 'package:game_tracker/presentation/widgets/quick_create_button.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,172 @@ class _HomeViewState extends State { final db = Provider.of(context, listen: false); _gameCountFuture = db.gameDao.getGameCount(); _groupCountFuture = db.groupDao.getGroupCount(); + + Future.wait([_gameCountFuture, _groupCountFuture]).then((_) { + 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: Padding( + padding: const EdgeInsets.symmetric(horizontal: 40.0), + child: Column( + mainAxisAlignment: MainAxisAlignment.start, + crossAxisAlignment: CrossAxisAlignment.start, + children: [ + Skeleton.unite( + unite: true, + borderRadius: BorderRadius.circular(8), + child: const GameTile( + gameTitle: 'Gamenight', + gameType: 'Cabo', + ruleset: 'Lowest Points', + players: '5 Players', + winner: 'Leonard', + ), + ), + const Padding( + padding: EdgeInsets.symmetric(vertical: 8.0), + child: Divider(), + ), + Skeleton.unite( + unite: true, + borderRadius: BorderRadius.circular(8), + child: const 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/pubspec.yaml b/pubspec.yaml index 5fa8019..ab6e30b 100644 --- a/pubspec.yaml +++ b/pubspec.yaml @@ -18,6 +18,7 @@ dependencies: drift_flutter: ^0.2.4 path_provider: ^2.1.5 provider: ^6.1.5 + skeletonizer: ^2.1.0+1 dev_dependencies: flutter_test: From 630836d40cd3d50104f54c0a786015028289e3ca Mon Sep 17 00:00:00 2001 From: Felix Kirchner Date: Sun, 16 Nov 2025 21:53:04 +0100 Subject: [PATCH 056/141] typo --- test/db_tests/group_test.dart | 2 +- test/db_tests/player_test.dart | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/test/db_tests/group_test.dart b/test/db_tests/group_test.dart index e8e6316..d8d6ce2 100644 --- a/test/db_tests/group_test.dart +++ b/test/db_tests/group_test.dart @@ -36,7 +36,7 @@ void main() { await database.close(); }); group('group tests', () { - test('all groups get fetched correclty', () async { + test('all groups get fetched correctly', () async { final testgroup2 = Group( id: 'gr2', name: 'Second Group', diff --git a/test/db_tests/player_test.dart b/test/db_tests/player_test.dart index 9f12faa..5258c66 100644 --- a/test/db_tests/player_test.dart +++ b/test/db_tests/player_test.dart @@ -24,7 +24,7 @@ void main() { }); group('player tests', () { - test('all players get fetched correclty', () async { + test('all players get fetched correctly', () async { final testPlayer2 = Player(id: 'gr2', name: 'Second Group'); await database.playerDao.addPlayer(player: testPlayer); await database.playerDao.addPlayer(player: testPlayer2); From b5e7fe23ab335388eb8ee28fe781dc77fab3b899 Mon Sep 17 00:00:00 2001 From: mathiskirchner Date: Mon, 17 Nov 2025 13:10:08 +0100 Subject: [PATCH 057/141] changed fullwidthbutton to include size, borderColor and infillColor attributes --- .../widgets/full_width_button.dart | 21 +++++++++++++++---- 1 file changed, 17 insertions(+), 4 deletions(-) diff --git a/lib/presentation/widgets/full_width_button.dart b/lib/presentation/widgets/full_width_button.dart index bd18c64..fc2ca78 100644 --- a/lib/presentation/widgets/full_width_button.dart +++ b/lib/presentation/widgets/full_width_button.dart @@ -1,10 +1,19 @@ import 'package:flutter/material.dart'; -import 'package:game_tracker/core/custom_theme.dart'; class FullWidthButton extends StatelessWidget { - const FullWidthButton({super.key, required this.text, this.onPressed}); + const FullWidthButton({ + super.key, + required this.text, + required this.borderColor, + required this.infillColor, + required this.sizeRelativeToWidth, + required this.onPressed, + }); final String text; + final Color borderColor; + final Color infillColor; + final double sizeRelativeToWidth; final VoidCallback? onPressed; @override @@ -12,8 +21,12 @@ class FullWidthButton extends StatelessWidget { return ElevatedButton( onPressed: onPressed, style: ElevatedButton.styleFrom( - minimumSize: Size(MediaQuery.sizeOf(context).width * 0.9, 60), - backgroundColor: CustomTheme.primaryColor, + minimumSize: Size( + MediaQuery.sizeOf(context).width * sizeRelativeToWidth, + 60, + ), + backgroundColor: infillColor, + side: BorderSide(color: borderColor, width: 2), shape: RoundedRectangleBorder(borderRadius: BorderRadius.circular(12)), ), child: Text( From a54495f915447d0b0b42cfa959b751dc77eb87da Mon Sep 17 00:00:00 2001 From: mathiskirchner Date: Mon, 17 Nov 2025 13:10:33 +0100 Subject: [PATCH 058/141] implemented basic CreateGroupView without functionality --- .../create_group/create_group_view.dart | 309 ++++++++++++++++++ 1 file changed, 309 insertions(+) create mode 100644 lib/presentation/views/main_menu/create_group/create_group_view.dart diff --git a/lib/presentation/views/main_menu/create_group/create_group_view.dart b/lib/presentation/views/main_menu/create_group/create_group_view.dart new file mode 100644 index 0000000..63daf62 --- /dev/null +++ b/lib/presentation/views/main_menu/create_group/create_group_view.dart @@ -0,0 +1,309 @@ +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/player.dart'; +import 'package:game_tracker/presentation/widgets/full_width_button.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 = [ + Player(id: '0', name: 'Player 0'), + Player(id: '0', name: 'Player 0'), + Player(id: '0', name: 'Player 0'), + Player(id: '0', name: 'Player 0'), + ]; + late Future> _allPlayersFuture; + late final List skeletonData = List.filled( + 7, + Player(id: '0', name: 'Player 0'), + ); + + @override + @override + void initState() { + super.initState(); + final db = Provider.of(context, listen: false); + _allPlayersFuture = db.playerDao.getAllPlayers(); + } + + @override + Widget build(BuildContext context) { + addSamplePlayers(context); + return SafeArea( + child: Scaffold( + backgroundColor: CustomTheme.backgroundColor, + appBar: AppBar( + backgroundColor: CustomTheme.backgroundColor, + title: const Text( + "Create new group", + style: const TextStyle(fontSize: 20, fontWeight: FontWeight.bold), + ), + centerTitle: true, + ), + body: Column( + mainAxisAlignment: MainAxisAlignment.start, + children: [ + Container( + margin: const EdgeInsets.symmetric(horizontal: 12, vertical: 10), + child: TextField( + decoration: InputDecoration( + filled: true, + fillColor: CustomTheme.boxColor, + hint: Text("Group name", style: TextStyle(fontSize: 18)), + enabledBorder: OutlineInputBorder( + borderRadius: BorderRadius.all(Radius.circular(12)), + borderSide: BorderSide(color: CustomTheme.boxBorder), + ), + focusedBorder: OutlineInputBorder( + borderRadius: BorderRadius.all(Radius.circular(12)), + borderSide: BorderSide(color: CustomTheme.boxBorder), + ), + floatingLabelBehavior: FloatingLabelBehavior.never, + ), + ), + ), + 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: [ + SearchBar( + constraints: BoxConstraints(maxHeight: 45, minHeight: 45), + hintText: "Search for players", + hintStyle: WidgetStateProperty.all( + TextStyle(fontSize: 16), + ), + leading: Icon(Icons.search), + backgroundColor: WidgetStateProperty.all( + CustomTheme.boxColor, + ), + side: WidgetStateProperty.all( + BorderSide(color: CustomTheme.boxBorder), + ), + shape: WidgetStateProperty.all( + RoundedRectangleBorder( + borderRadius: BorderRadius.circular(12), + ), + ), + ), + SizedBox(height: 10), + Text( + "Ausgewählte Spieler: (X)", + style: TextStyle( + fontSize: 16, + fontWeight: FontWeight.bold, + ), + ), + SizedBox(height: 10), + Wrap( + alignment: WrapAlignment.start, + crossAxisAlignment: WrapCrossAlignment.start, + spacing: 8.0, + runSpacing: 8.0, + children: [ + for (var player in selectedPlayers) + Container( + padding: EdgeInsets.all(5), + decoration: BoxDecoration( + color: CustomTheme.onBoxColor, + borderRadius: BorderRadius.circular(12), + ), + child: Row( + mainAxisAlignment: MainAxisAlignment.spaceBetween, + mainAxisSize: MainAxisSize.min, + children: [ + SizedBox(width: 12), + Text( + player.name, + style: const TextStyle( + fontSize: 14, + fontWeight: FontWeight.w500, + ), + ), + SizedBox(width: 3), + GestureDetector( + child: const Icon(Icons.close, size: 20), + onTap: () { + setState(() { + selectedPlayers.remove(player); + }); + }, + ), + ], + ), + ), + ], + ), + SizedBox(height: 10), + Text( + "Alle Spieler:", + style: TextStyle( + fontSize: 16, + fontWeight: FontWeight.bold, + ), + ), + 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)) { + return const Center( + child: TopCenteredMessage( + icon: Icons.info, + title: 'Info', + message: 'No players created yet.', + ), + ); + } + final bool isLoading = + snapshot.connectionState == + ConnectionState.waiting; + final List players = isLoading + ? skeletonData + : (snapshot.data ?? []); + 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: ListView.builder( + itemCount: players.length, + itemBuilder: + (BuildContext context, int index) { + return Container( + margin: const EdgeInsets.symmetric( + horizontal: 5, + vertical: 5, + ), + padding: const EdgeInsets.symmetric( + horizontal: 10, + ), + decoration: BoxDecoration( + color: CustomTheme.boxColor, + border: Border.all( + color: CustomTheme.boxBorder, + ), + borderRadius: BorderRadius.circular( + 12, + ), + ), + child: Row( + mainAxisAlignment: + MainAxisAlignment.spaceBetween, + mainAxisSize: MainAxisSize.max, + children: [ + Text( + players[index].name, + style: TextStyle( + fontSize: 16, + fontWeight: FontWeight.w500, + ), + ), + IconButton( + icon: Icon(Icons.add, size: 20), + onPressed: () {}, + ), + ], + ), + ); //GroupTile(group: groups[index]); + }, + ), + ), + ); + }, + ), + ], + ), + ), + ), + FullWidthButton( + text: "Create group", + infillColor: CustomTheme.primaryColor, + borderColor: CustomTheme.primaryColor, + sizeRelativeToWidth: 0.95, + onPressed: () {}, + ), + SizedBox(height: 10), + FullWidthButton( + text: "Cancel", + infillColor: CustomTheme.boxColor, + borderColor: CustomTheme.primaryColor, + sizeRelativeToWidth: 0.95, + onPressed: () { + Navigator.pop(context); + }, + ), + SizedBox(height: 20), + ], + ), + ), + ); + } + + Future addSamplePlayers(BuildContext context) async { + final db = Provider.of(context, listen: false); + final playerCount = await db.playerDao.getPlayerCount(); + if (playerCount == 0) { + for (int i = 1; i <= 10; i++) { + final player = Player(id: '$i', name: 'Spieler $i'); + await db.playerDao.addPlayer(player: player); + } + print("10 Beispiel-Spieler wurden zur Datenbank hinzugefügt."); + final players = await db.playerDao.getAllPlayers(); + for (int i = 0; i < players.length; i++) { + print(players[i]); + } + } + } +} From e4de8fdb253906e14723e955ec01aa9fd7df358c Mon Sep 17 00:00:00 2001 From: mathiskirchner Date: Mon, 17 Nov 2025 13:11:47 +0100 Subject: [PATCH 059/141] added missing attributes for FullWidthButton in groups view --- .../views/main_menu/groups_view.dart | 18 +++++++++++++++++- 1 file changed, 17 insertions(+), 1 deletion(-) diff --git a/lib/presentation/views/main_menu/groups_view.dart b/lib/presentation/views/main_menu/groups_view.dart index 7f1f32d..7c5e3d5 100644 --- a/lib/presentation/views/main_menu/groups_view.dart +++ b/lib/presentation/views/main_menu/groups_view.dart @@ -3,6 +3,7 @@ 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/create_group_view.dart'; import 'package:game_tracker/presentation/widgets/full_width_button.dart'; import 'package:game_tracker/presentation/widgets/tiles/group_tile.dart'; import 'package:game_tracker/presentation/widgets/top_centered_message.dart'; @@ -103,7 +104,22 @@ class _GroupsViewState extends State { Positioned( bottom: 80, - child: FullWidthButton(text: 'Create Group', onPressed: () {}), + child: FullWidthButton( + text: 'Create Group', + infillColor: CustomTheme.primaryColor, + borderColor: CustomTheme.primaryColor, + sizeRelativeToWidth: 0.90, + onPressed: () { + Navigator.push( + context, + MaterialPageRoute( + builder: (context) { + return const CreateGroupView(); + }, + ), + ); + }, + ), ), ], ), From 2fc7eab1ac465f53ff9e3f2e417f6a9609d8a8ed Mon Sep 17 00:00:00 2001 From: Felix Kirchner Date: Mon, 17 Nov 2025 13:19:05 +0100 Subject: [PATCH 060/141] Corrected game tile skeleton --- .../views/main_menu/home_view.dart | 41 ++++++++----------- lib/presentation/widgets/game_tile.dart | 35 +++++++++------- 2 files changed, 37 insertions(+), 39 deletions(-) diff --git a/lib/presentation/views/main_menu/home_view.dart b/lib/presentation/views/main_menu/home_view.dart index 57c4f61..cf6288a 100644 --- a/lib/presentation/views/main_menu/home_view.dart +++ b/lib/presentation/views/main_menu/home_view.dart @@ -26,7 +26,8 @@ class _HomeViewState extends State { _gameCountFuture = db.gameDao.getGameCount(); _groupCountFuture = db.groupDao.getGroupCount(); - Future.wait([_gameCountFuture, _groupCountFuture]).then((_) { + Future.wait([_gameCountFuture, _groupCountFuture]).then((_) async { + await Future.delayed(const Duration(milliseconds: 50)); if (mounted) { setState(() { isLoading = false; @@ -102,37 +103,29 @@ class _HomeViewState extends State { width: constraints.maxWidth * 0.95, title: 'Recent Games', icon: Icons.timer, - content: Padding( - padding: const EdgeInsets.symmetric(horizontal: 40.0), + content: const Padding( + padding: EdgeInsets.symmetric(horizontal: 40.0), child: Column( mainAxisAlignment: MainAxisAlignment.start, crossAxisAlignment: CrossAxisAlignment.start, children: [ - Skeleton.unite( - unite: true, - borderRadius: BorderRadius.circular(8), - child: const GameTile( - gameTitle: 'Gamenight', - gameType: 'Cabo', - ruleset: 'Lowest Points', - players: '5 Players', - winner: 'Leonard', - ), + GameTile( + gameTitle: 'Gamenight', + gameType: 'Cabo', + ruleset: 'Lowest Points', + players: '5 Players', + winner: 'Leonard', ), - const Padding( + Padding( padding: EdgeInsets.symmetric(vertical: 8.0), child: Divider(), ), - Skeleton.unite( - unite: true, - borderRadius: BorderRadius.circular(8), - child: const GameTile( - gameTitle: 'Schoolbreak', - gameType: 'Uno', - ruleset: 'Highest Points', - players: 'The Gang', - winner: 'Lina', - ), + GameTile( + gameTitle: 'Schoolbreak', + gameType: 'Uno', + ruleset: 'Highest Points', + players: 'The Gang', + winner: 'Lina', ), SizedBox(height: 8), ], diff --git a/lib/presentation/widgets/game_tile.dart b/lib/presentation/widgets/game_tile.dart index c79a6b7..fcd2f65 100644 --- a/lib/presentation/widgets/game_tile.dart +++ b/lib/presentation/widgets/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, + ), ), - ), - ], + ], + ), ), ), ), From 47bb090e725be017e0a8e252c35e25b26b6e9ef2 Mon Sep 17 00:00:00 2001 From: mathiskirchner Date: Mon, 17 Nov 2025 18:23:07 +0100 Subject: [PATCH 061/141] added option to choose disabledBackgroundColor in FullWidthButton --- lib/presentation/widgets/full_width_button.dart | 3 +++ 1 file changed, 3 insertions(+) diff --git a/lib/presentation/widgets/full_width_button.dart b/lib/presentation/widgets/full_width_button.dart index fc2ca78..fe9913c 100644 --- a/lib/presentation/widgets/full_width_button.dart +++ b/lib/presentation/widgets/full_width_button.dart @@ -6,6 +6,7 @@ class FullWidthButton extends StatelessWidget { required this.text, required this.borderColor, required this.infillColor, + this.disabledInfillColor, required this.sizeRelativeToWidth, required this.onPressed, }); @@ -13,6 +14,7 @@ class FullWidthButton extends StatelessWidget { final String text; final Color borderColor; final Color infillColor; + final Color? disabledInfillColor; final double sizeRelativeToWidth; final VoidCallback? onPressed; @@ -21,6 +23,7 @@ class FullWidthButton extends StatelessWidget { return ElevatedButton( onPressed: onPressed, style: ElevatedButton.styleFrom( + disabledBackgroundColor: disabledInfillColor, minimumSize: Size( MediaQuery.sizeOf(context).width * sizeRelativeToWidth, 60, From 35f2f8754ae7d2b4f6644e8cf0e34035fd8663e1 Mon Sep 17 00:00:00 2001 From: mathiskirchner Date: Mon, 17 Nov 2025 18:24:30 +0100 Subject: [PATCH 062/141] added functionality to create group --- .../create_group/create_group_view.dart | 197 +++++++++++++----- 1 file changed, 142 insertions(+), 55 deletions(-) diff --git a/lib/presentation/views/main_menu/create_group/create_group_view.dart b/lib/presentation/views/main_menu/create_group/create_group_view.dart index 63daf62..13f1b7c 100644 --- a/lib/presentation/views/main_menu/create_group/create_group_view.dart +++ b/lib/presentation/views/main_menu/create_group/create_group_view.dart @@ -1,6 +1,7 @@ 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/widgets/full_width_button.dart'; import 'package:game_tracker/presentation/widgets/top_centered_message.dart'; @@ -15,24 +16,30 @@ class CreateGroupView extends StatefulWidget { } class _CreateGroupViewState extends State { - List selectedPlayers = [ - Player(id: '0', name: 'Player 0'), - Player(id: '0', name: 'Player 0'), - Player(id: '0', name: 'Player 0'), - Player(id: '0', name: 'Player 0'), - ]; + List selectedPlayers = []; + List suggestedPlayers = []; + List allPlayers = []; + late final AppDatabase db; late Future> _allPlayersFuture; late final List skeletonData = List.filled( 7, Player(id: '0', name: 'Player 0'), ); + final _groupNameController = TextEditingController(); + final _searchBarController = TextEditingController(); @override @override void initState() { super.initState(); - final db = Provider.of(context, listen: false); + db = Provider.of(context, listen: false); _allPlayersFuture = db.playerDao.getAllPlayers(); + _allPlayersFuture.then((loadedPlayers) { + setState(() { + allPlayers = loadedPlayers; + suggestedPlayers = loadedPlayers; + }); + }); } @override @@ -55,6 +62,10 @@ class _CreateGroupViewState extends State { Container( margin: const EdgeInsets.symmetric(horizontal: 12, vertical: 10), child: TextField( + controller: _groupNameController, + onChanged: (value) { + setState(() {}); + }, decoration: InputDecoration( filled: true, fillColor: CustomTheme.boxColor, @@ -90,6 +101,7 @@ class _CreateGroupViewState extends State { crossAxisAlignment: CrossAxisAlignment.start, children: [ SearchBar( + controller: _searchBarController, constraints: BoxConstraints(maxHeight: 45, minHeight: 45), hintText: "Search for players", hintStyle: WidgetStateProperty.all( @@ -107,10 +119,23 @@ class _CreateGroupViewState extends State { borderRadius: BorderRadius.circular(12), ), ), + onChanged: (value) { + setState(() { + if (value.isEmpty) { + suggestedPlayers = allPlayers; + } else { + suggestedPlayers = allPlayers.where((player) { + return player.name.toLowerCase().contains( + value.toLowerCase(), + ); + }).toList(); + } + }); + }, ), SizedBox(height: 10), Text( - "Ausgewählte Spieler: (X)", + "Ausgewählte Spieler: (${selectedPlayers.length})", style: TextStyle( fontSize: 16, fontWeight: FontWeight.bold, @@ -123,7 +148,7 @@ class _CreateGroupViewState extends State { spacing: 8.0, runSpacing: 8.0, children: [ - for (var player in selectedPlayers) + for (var selectedPlayer in selectedPlayers) Container( padding: EdgeInsets.all(5), decoration: BoxDecoration( @@ -136,7 +161,7 @@ class _CreateGroupViewState extends State { children: [ SizedBox(width: 12), Text( - player.name, + selectedPlayer.name, style: const TextStyle( fontSize: 14, fontWeight: FontWeight.w500, @@ -147,7 +172,7 @@ class _CreateGroupViewState extends State { child: const Icon(Icons.close, size: 20), onTap: () { setState(() { - selectedPlayers.remove(player); + selectedPlayers.remove(selectedPlayer); }); }, ), @@ -183,7 +208,10 @@ class _CreateGroupViewState extends State { } if (snapshot.connectionState == ConnectionState.done && - (!snapshot.hasData || snapshot.data!.isEmpty)) { + (!snapshot.hasData || + snapshot.data!.isEmpty || + (suggestedPlayers.isEmpty && + allPlayers.isEmpty))) { return const Center( child: TopCenteredMessage( icon: Icons.info, @@ -195,9 +223,6 @@ class _CreateGroupViewState extends State { final bool isLoading = snapshot.connectionState == ConnectionState.waiting; - final List players = isLoading - ? skeletonData - : (snapshot.data ?? []); return Expanded( child: Skeletonizer( effect: PulseEffect( @@ -217,48 +242,69 @@ class _CreateGroupViewState extends State { layoutBuilder: AnimatedSwitcher.defaultLayoutBuilder, ), - child: ListView.builder( - itemCount: players.length, - itemBuilder: - (BuildContext context, int index) { - return Container( - margin: const EdgeInsets.symmetric( - horizontal: 5, - vertical: 5, - ), - padding: const EdgeInsets.symmetric( - horizontal: 10, - ), - decoration: BoxDecoration( - color: CustomTheme.boxColor, - border: Border.all( - color: CustomTheme.boxBorder, + child: + (suggestedPlayers.isEmpty && + !allPlayers.isEmpty) + ? TopCenteredMessage( + icon: Icons.info, + title: 'Info', + message: + 'No players found with that name.', + ) + : ListView.builder( + itemCount: suggestedPlayers.length, + itemBuilder: (BuildContext context, int index) { + return Container( + margin: const EdgeInsets.symmetric( + horizontal: 5, + vertical: 5, ), - borderRadius: BorderRadius.circular( - 12, + padding: const EdgeInsets.symmetric( + horizontal: 10, ), - ), - child: Row( - mainAxisAlignment: - MainAxisAlignment.spaceBetween, - mainAxisSize: MainAxisSize.max, - children: [ - Text( - players[index].name, - style: TextStyle( - fontSize: 16, - fontWeight: FontWeight.w500, + decoration: BoxDecoration( + color: CustomTheme.boxColor, + border: Border.all( + color: CustomTheme.boxBorder, + ), + borderRadius: + BorderRadius.circular(12), + ), + child: Row( + mainAxisAlignment: + MainAxisAlignment + .spaceBetween, + mainAxisSize: MainAxisSize.max, + children: [ + Text( + suggestedPlayers[index].name, + style: TextStyle( + fontSize: 16, + fontWeight: FontWeight.w500, + ), ), - ), - IconButton( - icon: Icon(Icons.add, size: 20), - onPressed: () {}, - ), - ], - ), - ); //GroupTile(group: groups[index]); - }, - ), + IconButton( + icon: Icon( + Icons.add, + size: 20, + ), + onPressed: () { + setState(() { + if (!selectedPlayers.contains( + suggestedPlayers[index], + )) { + selectedPlayers.add( + suggestedPlayers[index], + ); + } + }); + }, + ), + ], + ), + ); + }, + ), ), ); }, @@ -271,14 +317,39 @@ class _CreateGroupViewState extends State { text: "Create group", infillColor: CustomTheme.primaryColor, borderColor: CustomTheme.primaryColor, + disabledInfillColor: CustomTheme.boxColor, sizeRelativeToWidth: 0.95, - onPressed: () {}, + onPressed: + (_groupNameController.text.isEmpty || selectedPlayers.isEmpty) + ? null + : () { + String id = "ID_" + _groupNameController.text; + String name = _groupNameController.text; + List members = selectedPlayers; + db.groupDao.addGroup( + group: Group(id: id, name: name, members: members), + ); + print(name); + print(id); + for (int i = 0; i < members.length; i++) { + print(members[i].name); + print(members[i].id); + } + if (true) { + //eigentlich wenn create group erfolgreich + _groupNameController.clear(); + _searchBarController.clear(); + selectedPlayers.clear(); + } + setState(() {}); + }, ), SizedBox(height: 10), FullWidthButton( text: "Cancel", infillColor: CustomTheme.boxColor, borderColor: CustomTheme.primaryColor, + disabledInfillColor: CustomTheme.boxColor, sizeRelativeToWidth: 0.95, onPressed: () { Navigator.pop(context); @@ -293,6 +364,22 @@ class _CreateGroupViewState extends State { Future addSamplePlayers(BuildContext context) async { final db = Provider.of(context, listen: false); + /*await db.groupDao.addGroup( + group: Group( + id: "dg1", + name: "Debug Gruppe 1", + members: [ + Player(id: '1', name: 'Spieler 1'), + Player(id: '2', name: 'Spieler 2'), + Player(id: '3', name: 'Spieler 3'), + ], + ), + ); + final group = await db.groupDao.getGroupById(groupId: "dg1"); + print(group.name); + print(group.id); + print(group.members.length); + */ final playerCount = await db.playerDao.getPlayerCount(); if (playerCount == 0) { for (int i = 1; i <= 10; i++) { From a7f6a53b9ccc20a21b64414b3dd7ef707b085671 Mon Sep 17 00:00:00 2001 From: mathiskirchner Date: Mon, 17 Nov 2025 19:00:38 +0100 Subject: [PATCH 063/141] removed double @override --- .../views/main_menu/create_group/create_group_view.dart | 1 - 1 file changed, 1 deletion(-) diff --git a/lib/presentation/views/main_menu/create_group/create_group_view.dart b/lib/presentation/views/main_menu/create_group/create_group_view.dart index 13f1b7c..631f3ae 100644 --- a/lib/presentation/views/main_menu/create_group/create_group_view.dart +++ b/lib/presentation/views/main_menu/create_group/create_group_view.dart @@ -28,7 +28,6 @@ class _CreateGroupViewState extends State { final _groupNameController = TextEditingController(); final _searchBarController = TextEditingController(); - @override @override void initState() { super.initState(); From f8b6c00d5d8f1ceaa67f3862f1d379e2241a327b Mon Sep 17 00:00:00 2001 From: Felix Kirchner Date: Mon, 17 Nov 2025 19:26:36 +0100 Subject: [PATCH 064/141] Fixed return --- lib/data/dao/group_dao.dart | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/lib/data/dao/group_dao.dart b/lib/data/dao/group_dao.dart index 8eb3a1a..cc680a3 100644 --- a/lib/data/dao/group_dao.dart +++ b/lib/data/dao/group_dao.dart @@ -60,8 +60,8 @@ class GroupDao extends DatabaseAccessor with _$GroupDaoMixin { await Future.wait( group.members.map((player) => db.playerDao.addPlayer(player: player)), ); - return true; }); + return true; } return false; } From 6b2fb18ec095b3feeffe344f7ecdd9caabf4faa1 Mon Sep 17 00:00:00 2001 From: mathiskirchner Date: Mon, 17 Nov 2025 20:20:56 +0100 Subject: [PATCH 065/141] fixed groups not getting added & added feature to remove player from all players when selected --- .../create_group/create_group_view.dart | 67 +++++++++---------- 1 file changed, 30 insertions(+), 37 deletions(-) diff --git a/lib/presentation/views/main_menu/create_group/create_group_view.dart b/lib/presentation/views/main_menu/create_group/create_group_view.dart index 631f3ae..b27fb6a 100644 --- a/lib/presentation/views/main_menu/create_group/create_group_view.dart +++ b/lib/presentation/views/main_menu/create_group/create_group_view.dart @@ -35,6 +35,7 @@ class _CreateGroupViewState extends State { _allPlayersFuture = db.playerDao.getAllPlayers(); _allPlayersFuture.then((loadedPlayers) { setState(() { + loadedPlayers.sort((a, b) => a.name.compareTo(b.name)); allPlayers = loadedPlayers; suggestedPlayers = loadedPlayers; }); @@ -171,7 +172,11 @@ class _CreateGroupViewState extends State { child: const Icon(Icons.close, size: 20), onTap: () { setState(() { + suggestedPlayers.add(selectedPlayer); selectedPlayers.remove(selectedPlayer); + suggestedPlayers.sort( + (a, b) => a.name.compareTo(b.name), + ); }); }, ), @@ -295,6 +300,15 @@ class _CreateGroupViewState extends State { selectedPlayers.add( suggestedPlayers[index], ); + selectedPlayers.sort( + (a, b) => + a.name.compareTo( + b.name, + ), + ); + suggestedPlayers.remove( + suggestedPlayers[index], + ); } }); }, @@ -321,39 +335,34 @@ class _CreateGroupViewState extends State { onPressed: (_groupNameController.text.isEmpty || selectedPlayers.isEmpty) ? null - : () { + : () async { String id = "ID_" + _groupNameController.text; String name = _groupNameController.text; List members = selectedPlayers; - db.groupDao.addGroup( + bool success = await db.groupDao.addGroup( group: Group(id: id, name: name, members: members), ); - print(name); - print(id); - for (int i = 0; i < members.length; i++) { - print(members[i].name); - print(members[i].id); - } - if (true) { - //eigentlich wenn create group erfolgreich + if (success) { _groupNameController.clear(); _searchBarController.clear(); selectedPlayers.clear(); + Navigator.pop(context); + } else { + ScaffoldMessenger.of(context).showSnackBar( + SnackBar( + backgroundColor: CustomTheme.boxColor, + content: Center( + child: Text( + "Error while creating group, please try again", + style: TextStyle(color: Colors.white), + ), + ), + ), + ); } setState(() {}); }, ), - SizedBox(height: 10), - FullWidthButton( - text: "Cancel", - infillColor: CustomTheme.boxColor, - borderColor: CustomTheme.primaryColor, - disabledInfillColor: CustomTheme.boxColor, - sizeRelativeToWidth: 0.95, - onPressed: () { - Navigator.pop(context); - }, - ), SizedBox(height: 20), ], ), @@ -363,22 +372,6 @@ class _CreateGroupViewState extends State { Future addSamplePlayers(BuildContext context) async { final db = Provider.of(context, listen: false); - /*await db.groupDao.addGroup( - group: Group( - id: "dg1", - name: "Debug Gruppe 1", - members: [ - Player(id: '1', name: 'Spieler 1'), - Player(id: '2', name: 'Spieler 2'), - Player(id: '3', name: 'Spieler 3'), - ], - ), - ); - final group = await db.groupDao.getGroupById(groupId: "dg1"); - print(group.name); - print(group.id); - print(group.members.length); - */ final playerCount = await db.playerDao.getPlayerCount(); if (playerCount == 0) { for (int i = 1; i <= 10; i++) { From c3a2ac77b0de0918a3d38c6cc72ded946de6d08d Mon Sep 17 00:00:00 2001 From: mathiskirchner Date: Mon, 17 Nov 2025 21:19:17 +0100 Subject: [PATCH 066/141] fixed color change in appbar when scrolling --- .../views/main_menu/create_group/create_group_view.dart | 1 + 1 file changed, 1 insertion(+) diff --git a/lib/presentation/views/main_menu/create_group/create_group_view.dart b/lib/presentation/views/main_menu/create_group/create_group_view.dart index b27fb6a..316f2d3 100644 --- a/lib/presentation/views/main_menu/create_group/create_group_view.dart +++ b/lib/presentation/views/main_menu/create_group/create_group_view.dart @@ -50,6 +50,7 @@ class _CreateGroupViewState extends State { backgroundColor: CustomTheme.backgroundColor, appBar: AppBar( backgroundColor: CustomTheme.backgroundColor, + scrolledUnderElevation: 0, title: const Text( "Create new group", style: const TextStyle(fontSize: 20, fontWeight: FontWeight.bold), From 3e89bfd641e5245264a5250fa7b320cb5072b127 Mon Sep 17 00:00:00 2001 From: mathiskirchner Date: Mon, 17 Nov 2025 21:34:51 +0100 Subject: [PATCH 067/141] added info message for when all players are selected --- .../create_group/create_group_view.dart | 241 +++++++++--------- 1 file changed, 116 insertions(+), 125 deletions(-) diff --git a/lib/presentation/views/main_menu/create_group/create_group_view.dart b/lib/presentation/views/main_menu/create_group/create_group_view.dart index 316f2d3..907671b 100644 --- a/lib/presentation/views/main_menu/create_group/create_group_view.dart +++ b/lib/presentation/views/main_menu/create_group/create_group_view.dart @@ -36,8 +36,8 @@ class _CreateGroupViewState extends State { _allPlayersFuture.then((loadedPlayers) { setState(() { loadedPlayers.sort((a, b) => a.name.compareTo(b.name)); - allPlayers = loadedPlayers; - suggestedPlayers = loadedPlayers; + allPlayers = [...loadedPlayers]; + suggestedPlayers = [...loadedPlayers]; }); }); } @@ -123,7 +123,7 @@ class _CreateGroupViewState extends State { onChanged: (value) { setState(() { if (value.isEmpty) { - suggestedPlayers = allPlayers; + suggestedPlayers = [...allPlayers]; } else { suggestedPlayers = allPlayers.where((player) { return player.name.toLowerCase().contains( @@ -197,131 +197,122 @@ class _CreateGroupViewState extends State { 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 || - (suggestedPlayers.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.isEmpty) - ? TopCenteredMessage( - icon: Icons.info, - title: 'Info', - message: - 'No players found with that name.', - ) - : ListView.builder( - itemCount: suggestedPlayers.length, - itemBuilder: (BuildContext context, int index) { - return Container( - margin: const EdgeInsets.symmetric( - horizontal: 5, - vertical: 5, - ), - padding: const EdgeInsets.symmetric( - horizontal: 10, - ), - decoration: BoxDecoration( - color: CustomTheme.boxColor, - border: Border.all( - color: CustomTheme.boxBorder, + 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.isEmpty) + ? 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 Container( + margin: const EdgeInsets.symmetric( + horizontal: 5, + vertical: 5, + ), + padding: const EdgeInsets.symmetric( + horizontal: 10, + ), + decoration: BoxDecoration( + color: CustomTheme.boxColor, + border: Border.all( + color: CustomTheme.boxBorder, + ), + borderRadius: BorderRadius.circular( + 12, + ), + ), + child: Row( + mainAxisAlignment: + MainAxisAlignment.spaceBetween, + mainAxisSize: MainAxisSize.max, + children: [ + Text( + suggestedPlayers[index].name, + style: TextStyle( + fontSize: 16, + fontWeight: FontWeight.w500, ), - borderRadius: - BorderRadius.circular(12), ), - child: Row( - mainAxisAlignment: - MainAxisAlignment - .spaceBetween, - mainAxisSize: MainAxisSize.max, - children: [ - Text( - suggestedPlayers[index].name, - style: TextStyle( - fontSize: 16, - fontWeight: FontWeight.w500, - ), - ), - IconButton( - icon: Icon( - Icons.add, - size: 20, - ), - onPressed: () { - setState(() { - if (!selectedPlayers.contains( - suggestedPlayers[index], - )) { - selectedPlayers.add( - suggestedPlayers[index], - ); - selectedPlayers.sort( - (a, b) => - a.name.compareTo( - b.name, - ), - ); - suggestedPlayers.remove( - suggestedPlayers[index], - ); - } - }); - }, - ), - ], + IconButton( + icon: Icon(Icons.add, size: 20), + onPressed: () { + setState(() { + if (!selectedPlayers.contains( + suggestedPlayers[index], + )) { + selectedPlayers.add( + suggestedPlayers[index], + ); + selectedPlayers.sort( + (a, b) => a.name + .compareTo(b.name), + ); + suggestedPlayers.remove( + suggestedPlayers[index], + ); + } + }); + }, ), - ); - }, - ), - ), - ); - }, + ], + ), + ); + }, + ), + ), + ); + }, ), ], ), From c31d757615547a89344387c8eca2324898970b15 Mon Sep 17 00:00:00 2001 From: mathiskirchner Date: Tue, 18 Nov 2025 17:00:09 +0100 Subject: [PATCH 068/141] fixed renderoverflow for long player & group names in create group view and group view --- .../create_group/create_group_view.dart | 32 +++++++++++------ .../widgets/tiles/group_tile.dart | 36 +++++++++++-------- 2 files changed, 42 insertions(+), 26 deletions(-) diff --git a/lib/presentation/views/main_menu/create_group/create_group_view.dart b/lib/presentation/views/main_menu/create_group/create_group_view.dart index 907671b..823b6ff 100644 --- a/lib/presentation/views/main_menu/create_group/create_group_view.dart +++ b/lib/presentation/views/main_menu/create_group/create_group_view.dart @@ -70,7 +70,11 @@ class _CreateGroupViewState extends State { decoration: InputDecoration( filled: true, fillColor: CustomTheme.boxColor, - hint: Text("Group name", style: TextStyle(fontSize: 18)), + hint: Text( + "Group name", + overflow: TextOverflow.ellipsis, + style: TextStyle(fontSize: 18), + ), enabledBorder: OutlineInputBorder( borderRadius: BorderRadius.all(Radius.circular(12)), borderSide: BorderSide(color: CustomTheme.boxBorder), @@ -161,11 +165,14 @@ class _CreateGroupViewState extends State { mainAxisSize: MainAxisSize.min, children: [ SizedBox(width: 12), - Text( - selectedPlayer.name, - style: const TextStyle( - fontSize: 14, - fontWeight: FontWeight.w500, + Flexible( + child: Text( + selectedPlayer.name, + overflow: TextOverflow.ellipsis, + style: const TextStyle( + fontSize: 14, + fontWeight: FontWeight.w500, + ), ), ), SizedBox(width: 3), @@ -277,11 +284,14 @@ class _CreateGroupViewState extends State { MainAxisAlignment.spaceBetween, mainAxisSize: MainAxisSize.max, children: [ - Text( - suggestedPlayers[index].name, - style: TextStyle( - fontSize: 16, - fontWeight: FontWeight.w500, + Flexible( + child: Text( + suggestedPlayers[index].name, + overflow: TextOverflow.ellipsis, + style: TextStyle( + fontSize: 16, + fontWeight: FontWeight.w500, + ), ), ), IconButton( diff --git a/lib/presentation/widgets/tiles/group_tile.dart b/lib/presentation/widgets/tiles/group_tile.dart index 448c68c..12d016e 100644 --- a/lib/presentation/widgets/tiles/group_tile.dart +++ b/lib/presentation/widgets/tiles/group_tile.dart @@ -24,24 +24,29 @@ class GroupTile extends StatelessWidget { Row( mainAxisAlignment: MainAxisAlignment.spaceBetween, children: [ - Text( - group.name, - overflow: TextOverflow.ellipsis, - style: const TextStyle( - fontWeight: FontWeight.bold, - fontSize: 18, + Flexible( + child: Text( + group.name, + overflow: TextOverflow.ellipsis, + style: const TextStyle( + fontWeight: FontWeight.bold, + fontSize: 18, + ), ), ), - const Spacer(), - Text( - '${group.members.length}', - style: const TextStyle( - fontWeight: FontWeight.w900, - 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(width: 3), - const Icon(Icons.group, size: 22), ], ), const SizedBox(height: 5), @@ -64,6 +69,7 @@ class GroupTile extends StatelessWidget { child: Skeleton.ignore( child: Text( member.name, + overflow: TextOverflow.ellipsis, style: const TextStyle( fontSize: 14, fontWeight: FontWeight.bold, From 412d1fd334b5475f5f1fd4f02c9ab5c7c6d639f8 Mon Sep 17 00:00:00 2001 From: mathiskirchner Date: Tue, 18 Nov 2025 17:08:07 +0100 Subject: [PATCH 069/141] fixed search bugs where duplicates where created or search results were wrong --- .../create_group/create_group_view.dart | 25 +++++++++++++------ 1 file changed, 18 insertions(+), 7 deletions(-) diff --git a/lib/presentation/views/main_menu/create_group/create_group_view.dart b/lib/presentation/views/main_menu/create_group/create_group_view.dart index 823b6ff..87ef5bc 100644 --- a/lib/presentation/views/main_menu/create_group/create_group_view.dart +++ b/lib/presentation/views/main_menu/create_group/create_group_view.dart @@ -130,9 +130,12 @@ class _CreateGroupViewState extends State { suggestedPlayers = [...allPlayers]; } else { suggestedPlayers = allPlayers.where((player) { - return player.name.toLowerCase().contains( - value.toLowerCase(), - ); + final bool nameMatches = player.name + .toLowerCase() + .contains(value.toLowerCase()); + final bool isNotSelected = !selectedPlayers + .contains(player); + return nameMatches && isNotSelected; }).toList(); } }); @@ -180,11 +183,19 @@ class _CreateGroupViewState extends State { child: const Icon(Icons.close, size: 20), onTap: () { setState(() { - suggestedPlayers.add(selectedPlayer); + final currentSearch = _searchBarController + .text + .toLowerCase(); selectedPlayers.remove(selectedPlayer); - suggestedPlayers.sort( - (a, b) => a.name.compareTo(b.name), - ); + if (currentSearch.isEmpty || + selectedPlayer.name + .toLowerCase() + .contains(currentSearch)) { + suggestedPlayers.add(selectedPlayer); + suggestedPlayers.sort( + (a, b) => a.name.compareTo(b.name), + ); + } }); }, ), From a5e508dbdaedb2e22039f0015de786d2e85b5a84 Mon Sep 17 00:00:00 2001 From: mathiskirchner Date: Tue, 18 Nov 2025 17:29:24 +0100 Subject: [PATCH 070/141] Refresh group list after adding a new group --- lib/presentation/views/main_menu/groups_view.dart | 10 +++++++--- 1 file changed, 7 insertions(+), 3 deletions(-) diff --git a/lib/presentation/views/main_menu/groups_view.dart b/lib/presentation/views/main_menu/groups_view.dart index 7c5e3d5..bdb3d4a 100644 --- a/lib/presentation/views/main_menu/groups_view.dart +++ b/lib/presentation/views/main_menu/groups_view.dart @@ -19,6 +19,7 @@ class GroupsView extends StatefulWidget { class _GroupsViewState extends State { late Future> _allGroupsFuture; + late final AppDatabase db; final player = Player(id: 'p1', name: 'Sample'); late final List skeletonData = List.filled( @@ -33,7 +34,7 @@ class _GroupsViewState extends State { @override void initState() { super.initState(); - final db = Provider.of(context, listen: false); + db = Provider.of(context, listen: false); _allGroupsFuture = db.groupDao.getAllGroups(); } @@ -109,8 +110,8 @@ class _GroupsViewState extends State { infillColor: CustomTheme.primaryColor, borderColor: CustomTheme.primaryColor, sizeRelativeToWidth: 0.90, - onPressed: () { - Navigator.push( + onPressed: () async { + await Navigator.push( context, MaterialPageRoute( builder: (context) { @@ -118,6 +119,9 @@ class _GroupsViewState extends State { }, ), ); + setState(() { + _allGroupsFuture = db.groupDao.getAllGroups(); + }); }, ), ), From 05c41707ca96f997f3608fc1206fc8e22913abda Mon Sep 17 00:00:00 2001 From: mathiskirchner Date: Tue, 18 Nov 2025 17:34:09 +0100 Subject: [PATCH 071/141] Refactor: Remove sample player generation code --- .../create_group/create_group_view.dart | 17 ----------------- 1 file changed, 17 deletions(-) diff --git a/lib/presentation/views/main_menu/create_group/create_group_view.dart b/lib/presentation/views/main_menu/create_group/create_group_view.dart index 87ef5bc..1f616a2 100644 --- a/lib/presentation/views/main_menu/create_group/create_group_view.dart +++ b/lib/presentation/views/main_menu/create_group/create_group_view.dart @@ -44,7 +44,6 @@ class _CreateGroupViewState extends State { @override Widget build(BuildContext context) { - addSamplePlayers(context); return SafeArea( child: Scaffold( backgroundColor: CustomTheme.backgroundColor, @@ -382,20 +381,4 @@ class _CreateGroupViewState extends State { ), ); } - - Future addSamplePlayers(BuildContext context) async { - final db = Provider.of(context, listen: false); - final playerCount = await db.playerDao.getPlayerCount(); - if (playerCount == 0) { - for (int i = 1; i <= 10; i++) { - final player = Player(id: '$i', name: 'Spieler $i'); - await db.playerDao.addPlayer(player: player); - } - print("10 Beispiel-Spieler wurden zur Datenbank hinzugefügt."); - final players = await db.playerDao.getAllPlayers(); - for (int i = 0; i < players.length; i++) { - print(players[i]); - } - } - } } From 282841ecf16816f79d4af0c3de1aacfaff0f24b4 Mon Sep 17 00:00:00 2001 From: Felix Kirchner Date: Tue, 18 Nov 2025 20:07:53 +0100 Subject: [PATCH 072/141] Implemented uuid for all dtos --- lib/data/dto/game.dart | 7 ++++--- lib/data/dto/group.dart | 4 +++- lib/data/dto/player.dart | 4 +++- lib/presentation/views/main_menu/groups_view.dart | 6 +++--- pubspec.yaml | 1 + 5 files changed, 14 insertions(+), 8 deletions(-) diff --git a/lib/data/dto/game.dart b/lib/data/dto/game.dart index 125af48..c84779d 100644 --- a/lib/data/dto/game.dart +++ b/lib/data/dto/game.dart @@ -1,5 +1,6 @@ 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; @@ -9,12 +10,12 @@ class Game { final String winner; Game({ + String? id, + required this.name, this.players, this.group, this.winner = '', - required this.id, - required this.name, - }); + }) : id = id ?? const Uuid().v4(); @override String toString() { diff --git a/lib/data/dto/group.dart b/lib/data/dto/group.dart index 427a52b..0420477 100644 --- a/lib/data/dto/group.dart +++ b/lib/data/dto/group.dart @@ -1,11 +1,13 @@ import 'package:game_tracker/data/dto/player.dart'; +import 'package:uuid/uuid.dart'; class Group { final String id; final String name; final List members; - Group({required this.id, required this.name, required this.members}); + Group({String? id, required this.name, required this.members}) + : id = id ?? const Uuid().v4(); @override String toString() { diff --git a/lib/data/dto/player.dart b/lib/data/dto/player.dart index 631a51f..1b00c2c 100644 --- a/lib/data/dto/player.dart +++ b/lib/data/dto/player.dart @@ -1,8 +1,10 @@ +import 'package:uuid/uuid.dart'; + class Player { final String id; final String name; - Player({required this.id, required this.name}); + Player({String? id, required this.name}) : id = id ?? const Uuid().v4(); @override String toString() { diff --git a/lib/presentation/views/main_menu/groups_view.dart b/lib/presentation/views/main_menu/groups_view.dart index 7f1f32d..cfeb0c3 100644 --- a/lib/presentation/views/main_menu/groups_view.dart +++ b/lib/presentation/views/main_menu/groups_view.dart @@ -19,12 +19,11 @@ class GroupsView extends StatefulWidget { class _GroupsViewState extends State { late Future> _allGroupsFuture; - final player = Player(id: 'p1', name: 'Sample'); + final player = Player(name: 'Skeleton Player'); late final List skeletonData = List.filled( 7, Group( - id: '0', - name: 'Sample Game', + name: 'Skeleton Game', members: [player, player, player, player, player, player], ), ); @@ -34,6 +33,7 @@ class _GroupsViewState extends State { super.initState(); final db = Provider.of(context, listen: false); _allGroupsFuture = db.groupDao.getAllGroups(); + print('Skeleton Data: $skeletonData'); } @override diff --git a/pubspec.yaml b/pubspec.yaml index ab6e30b..fbbc01a 100644 --- a/pubspec.yaml +++ b/pubspec.yaml @@ -19,6 +19,7 @@ dependencies: path_provider: ^2.1.5 provider: ^6.1.5 skeletonizer: ^2.1.0+1 + uuid: ^4.5.2 dev_dependencies: flutter_test: From 1882d0007bd42daadec4f95bd749640203dcdf88 Mon Sep 17 00:00:00 2001 From: mathiskirchner Date: Tue, 18 Nov 2025 20:09:57 +0100 Subject: [PATCH 073/141] created widgets for search bar list tile, selected tile and text input field in create groups view --- .../widgets/custom_search_bar.dart | 36 +++++++++++++++ .../widgets/text_input_field.dart | 38 ++++++++++++++++ .../widgets/tiles/text_icon_list_tile.dart | 42 ++++++++++++++++++ .../widgets/tiles/text_icon_tile.dart | 44 +++++++++++++++++++ 4 files changed, 160 insertions(+) create mode 100644 lib/presentation/widgets/custom_search_bar.dart create mode 100644 lib/presentation/widgets/text_input_field.dart create mode 100644 lib/presentation/widgets/tiles/text_icon_list_tile.dart create mode 100644 lib/presentation/widgets/tiles/text_icon_tile.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..d0f66e8 --- /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: MaterialStateProperty.all(const TextStyle(fontSize: 16)), + leading: const Icon(Icons.search), + backgroundColor: MaterialStateProperty.all(CustomTheme.boxColor), + side: MaterialStateProperty.all(BorderSide(color: CustomTheme.boxBorder)), + shape: MaterialStateProperty.all( + RoundedRectangleBorder(borderRadius: BorderRadius.circular(12)), + ), + elevation: MaterialStateProperty.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/tiles/text_icon_list_tile.dart b/lib/presentation/widgets/tiles/text_icon_list_tile.dart new file mode 100644 index 0000000..b32504f --- /dev/null +++ b/lib/presentation/widgets/tiles/text_icon_list_tile.dart @@ -0,0 +1,42 @@ +import 'package:flutter/material.dart'; +import 'package:game_tracker/core/custom_theme.dart'; + +class IconListTile extends StatelessWidget { + final String text; + final IconData icon; + final VoidCallback onPressed; + + const IconListTile({ + super.key, + required this.text, + required this.icon, + required this.onPressed, + }); + + @override + Widget build(BuildContext context) { + return Container( + margin: const EdgeInsets.symmetric(horizontal: 5, vertical: 5), + padding: const EdgeInsets.symmetric(horizontal: 10), + 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: Text( + text, + overflow: TextOverflow.ellipsis, + style: const TextStyle(fontSize: 16, fontWeight: FontWeight.w500), + ), + ), + IconButton(icon: Icon(icon, size: 20), onPressed: onPressed), + ], + ), + ); + } +} 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..52174bd --- /dev/null +++ b/lib/presentation/widgets/tiles/text_icon_tile.dart @@ -0,0 +1,44 @@ +import 'package:flutter/material.dart'; +import 'package:game_tracker/core/custom_theme.dart'; + +class TextIconTile extends StatelessWidget { + final String text; + final IconData? icon; + final VoidCallback? onIconTap; + + const TextIconTile({ + super.key, + required this.text, + this.icon, + this.onIconTap, + }); + + @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 (icon != null) const SizedBox(width: 3), + Flexible( + child: Text( + text, + overflow: TextOverflow.ellipsis, + style: const TextStyle(fontSize: 14, fontWeight: FontWeight.w500), + ), + ), + if (icon != null) ...[ + const SizedBox(width: 3), + GestureDetector(onTap: onIconTap, child: Icon(icon, size: 20)), + ], + ], + ), + ); + } +} From 8f9289617f63b4f66d5131a4f9e8e61df8f2c0ac Mon Sep 17 00:00:00 2001 From: mathiskirchner Date: Tue, 18 Nov 2025 20:10:26 +0100 Subject: [PATCH 074/141] changed group tile to use standardized text icon tile --- .../widgets/tiles/group_tile.dart | 24 ++----------------- 1 file changed, 2 insertions(+), 22 deletions(-) diff --git a/lib/presentation/widgets/tiles/group_tile.dart b/lib/presentation/widgets/tiles/group_tile.dart index 12d016e..d87cc12 100644 --- a/lib/presentation/widgets/tiles/group_tile.dart +++ b/lib/presentation/widgets/tiles/group_tile.dart @@ -1,7 +1,7 @@ import 'package:flutter/material.dart'; import 'package:game_tracker/core/custom_theme.dart'; import 'package:game_tracker/data/dto/group.dart'; -import 'package:skeletonizer/skeletonizer.dart'; +import 'package:game_tracker/presentation/widgets/tiles/text_icon_tile.dart'; class GroupTile extends StatelessWidget { const GroupTile({super.key, required this.group}); @@ -56,27 +56,7 @@ class GroupTile extends StatelessWidget { spacing: 12.0, runSpacing: 8.0, children: [ - for (var member in group.members) - Container( - padding: const EdgeInsets.symmetric( - vertical: 5, - horizontal: 10, - ), - decoration: BoxDecoration( - color: CustomTheme.onBoxColor, - borderRadius: BorderRadius.circular(12), - ), - child: Skeleton.ignore( - child: Text( - member.name, - overflow: TextOverflow.ellipsis, - style: const TextStyle( - fontSize: 14, - fontWeight: FontWeight.bold, - ), - ), - ), - ), + for (var member in group.members) TextIconTile(text: member.name), ], ), const SizedBox(height: 2.5), From c0ff2bf6777d90393ae8941dbd2291c4cf5aae4d Mon Sep 17 00:00:00 2001 From: Felix Kirchner Date: Tue, 18 Nov 2025 20:10:29 +0100 Subject: [PATCH 075/141] Removed unnecessary id declarations in tests --- test/db_tests/game_test.dart | 21 ++++++--------------- test/db_tests/group_test.dart | 20 ++++++++------------ test/db_tests/player_test.dart | 4 ++-- 3 files changed, 16 insertions(+), 29 deletions(-) diff --git a/test/db_tests/game_test.dart b/test/db_tests/game_test.dart index bee3ff8..29b0233 100644 --- a/test/db_tests/game_test.dart +++ b/test/db_tests/game_test.dart @@ -24,21 +24,12 @@ void main() { ), ); - player1 = Player(id: 'p1', name: 'Alice'); - player2 = Player(id: 'p2', name: 'Bob'); - player3 = Player(id: 'p3', name: 'Charlie'); - player4 = Player(id: 'p4', name: 'Diana'); - testgroup = Group( - id: 'gr1', - name: 'Test Group', - members: [player1, player2, player3], - ); - testgame = Game( - id: 'ga1', - name: 'Test Game', - group: testgroup, - players: [player4], - ); + 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]); + testgame = Game(name: 'Test Game', group: testgroup, players: [player4]); }); tearDown(() async { await database.close(); diff --git a/test/db_tests/group_test.dart b/test/db_tests/group_test.dart index d8d6ce2..3a9d8ca 100644 --- a/test/db_tests/group_test.dart +++ b/test/db_tests/group_test.dart @@ -22,15 +22,11 @@ void main() { ), ); - player1 = Player(id: 'p1', name: 'Alice'); - player2 = Player(id: 'p2', name: 'Bob'); - player3 = Player(id: 'p3', name: 'Charlie'); - player4 = Player(id: 'p4', name: 'Diana'); - testgroup = Group( - id: 'gr1', - name: 'Test Group', - members: [player1, player2, player3], - ); + 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]); }); tearDown(() async { await database.close(); @@ -121,12 +117,12 @@ void main() { expect(playerAdded, true); - final playerAdded2 = await database.playerGroupDao.isPlayerInGroup( - playerId: 'a', + final playerNotAdded = !await database.playerGroupDao.isPlayerInGroup( + playerId: '', groupId: testgroup.id, ); - expect(playerAdded2, false); + expect(playerNotAdded, true); expect(playerAdded, true); diff --git a/test/db_tests/player_test.dart b/test/db_tests/player_test.dart index 5258c66..91f4acb 100644 --- a/test/db_tests/player_test.dart +++ b/test/db_tests/player_test.dart @@ -17,7 +17,7 @@ void main() { ), ); - testPlayer = Player(id: 'test_id', name: 'Test Player'); + testPlayer = Player(name: 'Test Player'); }); tearDown(() async { await database.close(); @@ -25,7 +25,7 @@ void main() { group('player tests', () { test('all players get fetched correctly', () async { - final testPlayer2 = Player(id: 'gr2', name: 'Second Group'); + final testPlayer2 = Player(name: 'Second Group'); await database.playerDao.addPlayer(player: testPlayer); await database.playerDao.addPlayer(player: testPlayer2); From 77812842893db5d4c122761d5a74580331dc1639 Mon Sep 17 00:00:00 2001 From: mathiskirchner Date: Tue, 18 Nov 2025 20:10:48 +0100 Subject: [PATCH 076/141] changed to use standardized tiles and fixed search bug --- .../create_group/create_group_view.dart | 330 +++++++----------- 1 file changed, 128 insertions(+), 202 deletions(-) diff --git a/lib/presentation/views/main_menu/create_group/create_group_view.dart b/lib/presentation/views/main_menu/create_group/create_group_view.dart index 1f616a2..1a84956 100644 --- a/lib/presentation/views/main_menu/create_group/create_group_view.dart +++ b/lib/presentation/views/main_menu/create_group/create_group_view.dart @@ -3,10 +3,15 @@ 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/widgets/custom_search_bar.dart'; import 'package:game_tracker/presentation/widgets/full_width_button.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'; +import 'package:uuid/uuid.dart'; class CreateGroupView extends StatefulWidget { const CreateGroupView({super.key}); @@ -61,29 +66,12 @@ class _CreateGroupViewState extends State { children: [ Container( margin: const EdgeInsets.symmetric(horizontal: 12, vertical: 10), - child: TextField( + child: TextInputField( controller: _groupNameController, + hintText: 'Group name', onChanged: (value) { setState(() {}); }, - decoration: InputDecoration( - filled: true, - fillColor: CustomTheme.boxColor, - hint: Text( - "Group name", - overflow: TextOverflow.ellipsis, - style: TextStyle(fontSize: 18), - ), - enabledBorder: OutlineInputBorder( - borderRadius: BorderRadius.all(Radius.circular(12)), - borderSide: BorderSide(color: CustomTheme.boxBorder), - ), - focusedBorder: OutlineInputBorder( - borderRadius: BorderRadius.all(Radius.circular(12)), - borderSide: BorderSide(color: CustomTheme.boxBorder), - ), - floatingLabelBehavior: FloatingLabelBehavior.never, - ), ), ), Expanded( @@ -104,29 +92,16 @@ class _CreateGroupViewState extends State { child: Column( crossAxisAlignment: CrossAxisAlignment.start, children: [ - SearchBar( + CustomSearchBar( controller: _searchBarController, constraints: BoxConstraints(maxHeight: 45, minHeight: 45), hintText: "Search for players", - hintStyle: WidgetStateProperty.all( - TextStyle(fontSize: 16), - ), - leading: Icon(Icons.search), - backgroundColor: WidgetStateProperty.all( - CustomTheme.boxColor, - ), - side: WidgetStateProperty.all( - BorderSide(color: CustomTheme.boxBorder), - ), - shape: WidgetStateProperty.all( - RoundedRectangleBorder( - borderRadius: BorderRadius.circular(12), - ), - ), onChanged: (value) { setState(() { if (value.isEmpty) { - suggestedPlayers = [...allPlayers]; + suggestedPlayers = allPlayers.where((player) { + return !selectedPlayers.contains(player); + }).toList(); } else { suggestedPlayers = allPlayers.where((player) { final bool nameMatches = player.name @@ -156,50 +131,25 @@ class _CreateGroupViewState extends State { runSpacing: 8.0, children: [ for (var selectedPlayer in selectedPlayers) - Container( - padding: EdgeInsets.all(5), - decoration: BoxDecoration( - color: CustomTheme.onBoxColor, - borderRadius: BorderRadius.circular(12), - ), - child: Row( - mainAxisAlignment: MainAxisAlignment.spaceBetween, - mainAxisSize: MainAxisSize.min, - children: [ - SizedBox(width: 12), - Flexible( - child: Text( - selectedPlayer.name, - overflow: TextOverflow.ellipsis, - style: const TextStyle( - fontSize: 14, - fontWeight: FontWeight.w500, - ), - ), - ), - SizedBox(width: 3), - GestureDetector( - child: const Icon(Icons.close, size: 20), - onTap: () { - setState(() { - final currentSearch = _searchBarController - .text - .toLowerCase(); - selectedPlayers.remove(selectedPlayer); - if (currentSearch.isEmpty || - selectedPlayer.name - .toLowerCase() - .contains(currentSearch)) { - suggestedPlayers.add(selectedPlayer); - suggestedPlayers.sort( - (a, b) => a.name.compareTo(b.name), - ); - } - }); - }, - ), - ], - ), + TextIconTile( + text: selectedPlayer.name, + icon: Icons.close, + onIconTap: () { + setState(() { + final currentSearch = _searchBarController.text + .toLowerCase(); + selectedPlayers.remove(selectedPlayer); + if (currentSearch.isEmpty || + selectedPlayer.name.toLowerCase().contains( + currentSearch, + )) { + suggestedPlayers.add(selectedPlayer); + suggestedPlayers.sort( + (a, b) => a.name.compareTo(b.name), + ); + } + }); + }, ), ], ), @@ -214,125 +164,100 @@ class _CreateGroupViewState extends State { 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.isEmpty) - ? 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 Container( - margin: const EdgeInsets.symmetric( - horizontal: 5, - vertical: 5, - ), - padding: const EdgeInsets.symmetric( - horizontal: 10, - ), - 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: Text( - suggestedPlayers[index].name, - overflow: TextOverflow.ellipsis, - style: TextStyle( - fontSize: 16, - fontWeight: FontWeight.w500, - ), - ), - ), - IconButton( - icon: Icon(Icons.add, size: 20), - onPressed: () { - setState(() { - if (!selectedPlayers.contains( - suggestedPlayers[index], - )) { - selectedPlayers.add( + 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.isEmpty) + ? 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 IconListTile( + text: suggestedPlayers[index] + .name, + icon: Icons.add, + onPressed: () { + setState(() { + if (!selectedPlayers.contains( suggestedPlayers[index], - ); - selectedPlayers.sort( - (a, b) => a.name - .compareTo(b.name), - ); - suggestedPlayers.remove( - suggestedPlayers[index], - ); - } - }); - }, - ), - ], - ), - ); - }, - ), - ), - ); - }, + )) { + selectedPlayers.add( + suggestedPlayers[index], + ); + selectedPlayers.sort( + (a, b) => a.name + .compareTo(b.name), + ); + suggestedPlayers.remove( + suggestedPlayers[index], + ); + } + }); + }, + ); + }, + ), + ), + ); + }, ), ], ), @@ -348,11 +273,12 @@ class _CreateGroupViewState extends State { (_groupNameController.text.isEmpty || selectedPlayers.isEmpty) ? null : () async { - String id = "ID_" + _groupNameController.text; - String name = _groupNameController.text; - List members = selectedPlayers; bool success = await db.groupDao.addGroup( - group: Group(id: id, name: name, members: members), + group: Group( + id: Uuid().v4(), + name: _groupNameController.text, + members: selectedPlayers, + ), ); if (success) { _groupNameController.clear(); From 2f260d7cbcfd01be9ec595f3427088e120970c58 Mon Sep 17 00:00:00 2001 From: mathiskirchner Date: Tue, 18 Nov 2025 20:14:18 +0100 Subject: [PATCH 077/141] Add uuid dependency --- pubspec.yaml | 1 + 1 file changed, 1 insertion(+) diff --git a/pubspec.yaml b/pubspec.yaml index ab6e30b..fbbc01a 100644 --- a/pubspec.yaml +++ b/pubspec.yaml @@ -19,6 +19,7 @@ dependencies: path_provider: ^2.1.5 provider: ^6.1.5 skeletonizer: ^2.1.0+1 + uuid: ^4.5.2 dev_dependencies: flutter_test: From f4ed122220347dc4acfd55cac784a329aee30953 Mon Sep 17 00:00:00 2001 From: Felix Kirchner Date: Tue, 18 Nov 2025 20:15:10 +0100 Subject: [PATCH 078/141] Removed print --- lib/presentation/views/main_menu/groups_view.dart | 1 - 1 file changed, 1 deletion(-) diff --git a/lib/presentation/views/main_menu/groups_view.dart b/lib/presentation/views/main_menu/groups_view.dart index cfeb0c3..8edf20f 100644 --- a/lib/presentation/views/main_menu/groups_view.dart +++ b/lib/presentation/views/main_menu/groups_view.dart @@ -33,7 +33,6 @@ class _GroupsViewState extends State { super.initState(); final db = Provider.of(context, listen: false); _allGroupsFuture = db.groupDao.getAllGroups(); - print('Skeleton Data: $skeletonData'); } @override From 80290efa0b1d0046b0c18bea101dab4a82c05b83 Mon Sep 17 00:00:00 2001 From: mathiskirchner Date: Tue, 18 Nov 2025 20:37:41 +0100 Subject: [PATCH 079/141] rename FullWidthButton to CustomWidthButton --- .../views/main_menu/create_group/create_group_view.dart | 4 ++-- lib/presentation/views/main_menu/groups_view.dart | 4 ++-- .../{full_width_button.dart => custom_width_button.dart} | 4 ++-- 3 files changed, 6 insertions(+), 6 deletions(-) rename lib/presentation/widgets/{full_width_button.dart => custom_width_button.dart} (93%) diff --git a/lib/presentation/views/main_menu/create_group/create_group_view.dart b/lib/presentation/views/main_menu/create_group/create_group_view.dart index 1a84956..8a89501 100644 --- a/lib/presentation/views/main_menu/create_group/create_group_view.dart +++ b/lib/presentation/views/main_menu/create_group/create_group_view.dart @@ -4,7 +4,7 @@ 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/custom_search_bar.dart'; -import 'package:game_tracker/presentation/widgets/full_width_button.dart'; +import 'package:game_tracker/presentation/widgets/custom_width_button.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'; @@ -263,7 +263,7 @@ class _CreateGroupViewState extends State { ), ), ), - FullWidthButton( + CustomWidthButton( text: "Create group", infillColor: CustomTheme.primaryColor, borderColor: CustomTheme.primaryColor, diff --git a/lib/presentation/views/main_menu/groups_view.dart b/lib/presentation/views/main_menu/groups_view.dart index bdb3d4a..200f1d0 100644 --- a/lib/presentation/views/main_menu/groups_view.dart +++ b/lib/presentation/views/main_menu/groups_view.dart @@ -4,7 +4,7 @@ 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/create_group_view.dart'; -import 'package:game_tracker/presentation/widgets/full_width_button.dart'; +import 'package:game_tracker/presentation/widgets/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'; @@ -105,7 +105,7 @@ class _GroupsViewState extends State { Positioned( bottom: 80, - child: FullWidthButton( + child: CustomWidthButton( text: 'Create Group', infillColor: CustomTheme.primaryColor, borderColor: CustomTheme.primaryColor, diff --git a/lib/presentation/widgets/full_width_button.dart b/lib/presentation/widgets/custom_width_button.dart similarity index 93% rename from lib/presentation/widgets/full_width_button.dart rename to lib/presentation/widgets/custom_width_button.dart index fe9913c..b336a79 100644 --- a/lib/presentation/widgets/full_width_button.dart +++ b/lib/presentation/widgets/custom_width_button.dart @@ -1,7 +1,7 @@ import 'package:flutter/material.dart'; -class FullWidthButton extends StatelessWidget { - const FullWidthButton({ +class CustomWidthButton extends StatelessWidget { + const CustomWidthButton({ super.key, required this.text, required this.borderColor, From 73d8e7522cc2dbd72ded5a08a06fa63526648555 Mon Sep 17 00:00:00 2001 From: Felix Kirchner Date: Tue, 18 Nov 2025 20:44:55 +0100 Subject: [PATCH 080/141] Added fifth player --- test/db_tests/game_test.dart | 8 +++++++- 1 file changed, 7 insertions(+), 1 deletion(-) diff --git a/test/db_tests/game_test.dart b/test/db_tests/game_test.dart index 29b0233..4f4b23f 100644 --- a/test/db_tests/game_test.dart +++ b/test/db_tests/game_test.dart @@ -12,6 +12,7 @@ void main() { late Player player2; late Player player3; late Player player4; + late Player player5; late Group testgroup; late Game testgame; @@ -28,8 +29,13 @@ void main() { 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]); + testgame = Game( + name: 'Test Game', + group: testgroup, + players: [player4, player5], + ); }); tearDown(() async { await database.close(); From c67f688a7723c82c7026759472439f29bf65e98c Mon Sep 17 00:00:00 2001 From: mathiskirchner Date: Tue, 18 Nov 2025 21:42:03 +0100 Subject: [PATCH 081/141] Refactor CreateGroupView: remove UUID generation, update tiles & fix async gaps --- .../create_group/create_group_view.dart | 59 +++++++++---------- 1 file changed, 29 insertions(+), 30 deletions(-) diff --git a/lib/presentation/views/main_menu/create_group/create_group_view.dart b/lib/presentation/views/main_menu/create_group/create_group_view.dart index 8a89501..81d5e36 100644 --- a/lib/presentation/views/main_menu/create_group/create_group_view.dart +++ b/lib/presentation/views/main_menu/create_group/create_group_view.dart @@ -11,7 +11,6 @@ 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'; -import 'package:uuid/uuid.dart'; class CreateGroupView extends StatefulWidget { const CreateGroupView({super.key}); @@ -28,7 +27,7 @@ class _CreateGroupViewState extends State { late Future> _allPlayersFuture; late final List skeletonData = List.filled( 7, - Player(id: '0', name: 'Player 0'), + Player(name: 'Player 0'), ); final _groupNameController = TextEditingController(); final _searchBarController = TextEditingController(); @@ -56,8 +55,8 @@ class _CreateGroupViewState extends State { backgroundColor: CustomTheme.backgroundColor, scrolledUnderElevation: 0, title: const Text( - "Create new group", - style: const TextStyle(fontSize: 20, fontWeight: FontWeight.bold), + 'Create new group', + style: TextStyle(fontSize: 20, fontWeight: FontWeight.bold), ), centerTitle: true, ), @@ -94,8 +93,11 @@ class _CreateGroupViewState extends State { children: [ CustomSearchBar( controller: _searchBarController, - constraints: BoxConstraints(maxHeight: 45, minHeight: 45), - hintText: "Search for players", + constraints: const BoxConstraints( + maxHeight: 45, + minHeight: 45, + ), + hintText: 'Search for players', onChanged: (value) { setState(() { if (value.isEmpty) { @@ -115,35 +117,34 @@ class _CreateGroupViewState extends State { }); }, ), - SizedBox(height: 10), + const SizedBox(height: 10), Text( - "Ausgewählte Spieler: (${selectedPlayers.length})", - style: TextStyle( + 'Ausgewählte Spieler: (${selectedPlayers.length})', + style: const TextStyle( fontSize: 16, fontWeight: FontWeight.bold, ), ), - SizedBox(height: 10), + const SizedBox(height: 10), Wrap( alignment: WrapAlignment.start, crossAxisAlignment: WrapCrossAlignment.start, spacing: 8.0, runSpacing: 8.0, children: [ - for (var selectedPlayer in selectedPlayers) + for (var player in selectedPlayers) TextIconTile( - text: selectedPlayer.name, - icon: Icons.close, + text: player.name, onIconTap: () { setState(() { final currentSearch = _searchBarController.text .toLowerCase(); - selectedPlayers.remove(selectedPlayer); + selectedPlayers.remove(player); if (currentSearch.isEmpty || - selectedPlayer.name.toLowerCase().contains( + player.name.toLowerCase().contains( currentSearch, )) { - suggestedPlayers.add(selectedPlayer); + suggestedPlayers.add(player); suggestedPlayers.sort( (a, b) => a.name.compareTo(b.name), ); @@ -153,15 +154,15 @@ class _CreateGroupViewState extends State { ), ], ), - SizedBox(height: 10), - Text( - "Alle Spieler:", + const SizedBox(height: 10), + const Text( + 'Alle Spieler:', style: TextStyle( fontSize: 16, fontWeight: FontWeight.bold, ), ), - SizedBox(height: 10), + const SizedBox(height: 10), FutureBuilder( future: _allPlayersFuture, builder: @@ -216,7 +217,7 @@ class _CreateGroupViewState extends State { ), child: (suggestedPlayers.isEmpty && - !allPlayers.isEmpty) + allPlayers.isNotEmpty) ? TopCenteredMessage( icon: Icons.info, title: 'Info', @@ -230,10 +231,9 @@ class _CreateGroupViewState extends State { itemCount: suggestedPlayers.length, itemBuilder: (BuildContext context, int index) { - return IconListTile( + return TextIconListTile( text: suggestedPlayers[index] .name, - icon: Icons.add, onPressed: () { setState(() { if (!selectedPlayers.contains( @@ -264,9 +264,7 @@ class _CreateGroupViewState extends State { ), ), CustomWidthButton( - text: "Create group", - infillColor: CustomTheme.primaryColor, - borderColor: CustomTheme.primaryColor, + text: 'Create group', disabledInfillColor: CustomTheme.boxColor, sizeRelativeToWidth: 0.95, onPressed: @@ -275,7 +273,6 @@ class _CreateGroupViewState extends State { : () async { bool success = await db.groupDao.addGroup( group: Group( - id: Uuid().v4(), name: _groupNameController.text, members: selectedPlayers, ), @@ -284,14 +281,16 @@ class _CreateGroupViewState extends State { _groupNameController.clear(); _searchBarController.clear(); selectedPlayers.clear(); + if (!mounted) return; Navigator.pop(context); } else { + if (!mounted) return; ScaffoldMessenger.of(context).showSnackBar( SnackBar( backgroundColor: CustomTheme.boxColor, - content: Center( + content: const Center( child: Text( - "Error while creating group, please try again", + 'Error while creating group, please try again', style: TextStyle(color: Colors.white), ), ), @@ -301,7 +300,7 @@ class _CreateGroupViewState extends State { setState(() {}); }, ), - SizedBox(height: 20), + const SizedBox(height: 20), ], ), ), From 51a8c4ea58ab95ff732949868502acd66553537c Mon Sep 17 00:00:00 2001 From: mathiskirchner Date: Tue, 18 Nov 2025 21:42:17 +0100 Subject: [PATCH 082/141] Replace `MaterialStateProperty` with `WidgetStateProperty` in `CustomSearchBar` --- lib/presentation/widgets/custom_search_bar.dart | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) diff --git a/lib/presentation/widgets/custom_search_bar.dart b/lib/presentation/widgets/custom_search_bar.dart index d0f66e8..b482efb 100644 --- a/lib/presentation/widgets/custom_search_bar.dart +++ b/lib/presentation/widgets/custom_search_bar.dart @@ -23,14 +23,14 @@ class CustomSearchBar extends StatelessWidget { constraints ?? const BoxConstraints(maxHeight: 45, minHeight: 45), hintText: hintText, onChanged: onChanged, - hintStyle: MaterialStateProperty.all(const TextStyle(fontSize: 16)), + hintStyle: WidgetStateProperty.all(const TextStyle(fontSize: 16)), leading: const Icon(Icons.search), - backgroundColor: MaterialStateProperty.all(CustomTheme.boxColor), - side: MaterialStateProperty.all(BorderSide(color: CustomTheme.boxBorder)), - shape: MaterialStateProperty.all( + backgroundColor: WidgetStateProperty.all(CustomTheme.boxColor), + side: WidgetStateProperty.all(BorderSide(color: CustomTheme.boxBorder)), + shape: WidgetStateProperty.all( RoundedRectangleBorder(borderRadius: BorderRadius.circular(12)), ), - elevation: MaterialStateProperty.all(0), + elevation: WidgetStateProperty.all(0), ); } } From d65dd3d9838a9fa1075bcfd62460ec52ecb7f87e Mon Sep 17 00:00:00 2001 From: mathiskirchner Date: Tue, 18 Nov 2025 21:42:40 +0100 Subject: [PATCH 083/141] Refactor CustomWidthButton to use ButtonStyle enum and CustomTheme - Replaced `borderColor` and `infillColor` parameters with a `buttonStyle` parameter. - Introduced `ButtonStyle` enum (primary/secondary) to control styling. - Updated `CustomWidthButton` to derive colors from `CustomTheme` based on the selected `ButtonStyle`. --- .../widgets/custom_width_button.dart | 20 +++++++++++++------ 1 file changed, 14 insertions(+), 6 deletions(-) diff --git a/lib/presentation/widgets/custom_width_button.dart b/lib/presentation/widgets/custom_width_button.dart index b336a79..b0b9bd3 100644 --- a/lib/presentation/widgets/custom_width_button.dart +++ b/lib/presentation/widgets/custom_width_button.dart @@ -1,22 +1,23 @@ import 'package:flutter/material.dart'; +import 'package:game_tracker/core/custom_theme.dart'; + +enum ButtonStyle { primary, secondary } class CustomWidthButton extends StatelessWidget { const CustomWidthButton({ super.key, required this.text, - required this.borderColor, - required this.infillColor, this.disabledInfillColor, + this.buttonStyle = ButtonStyle.primary, required this.sizeRelativeToWidth, required this.onPressed, }); final String text; - final Color borderColor; - final Color infillColor; final Color? disabledInfillColor; final double sizeRelativeToWidth; final VoidCallback? onPressed; + final ButtonStyle buttonStyle; @override Widget build(BuildContext context) { @@ -28,8 +29,15 @@ class CustomWidthButton extends StatelessWidget { MediaQuery.sizeOf(context).width * sizeRelativeToWidth, 60, ), - backgroundColor: infillColor, - side: BorderSide(color: borderColor, width: 2), + backgroundColor: buttonStyle == ButtonStyle.primary + ? CustomTheme.primaryColor + : CustomTheme.secondaryColor, + side: BorderSide( + color: buttonStyle == ButtonStyle.primary + ? CustomTheme.primaryColor + : CustomTheme.secondaryColor, + width: 2, + ), shape: RoundedRectangleBorder(borderRadius: BorderRadius.circular(12)), ), child: Text( From e0c83988730735e444bd87ad0e631be605dc5799 Mon Sep 17 00:00:00 2001 From: mathiskirchner Date: Tue, 18 Nov 2025 21:43:38 +0100 Subject: [PATCH 084/141] remove custom colors from Create Group button in GroupsView --- lib/presentation/views/main_menu/groups_view.dart | 2 -- 1 file changed, 2 deletions(-) diff --git a/lib/presentation/views/main_menu/groups_view.dart b/lib/presentation/views/main_menu/groups_view.dart index 73f3509..7e6f59d 100644 --- a/lib/presentation/views/main_menu/groups_view.dart +++ b/lib/presentation/views/main_menu/groups_view.dart @@ -106,8 +106,6 @@ class _GroupsViewState extends State { bottom: 80, child: CustomWidthButton( text: 'Create Group', - infillColor: CustomTheme.primaryColor, - borderColor: CustomTheme.primaryColor, sizeRelativeToWidth: 0.90, onPressed: () async { await Navigator.push( From d3a63bd299e23cdfdf6470ff3793dce71076ad70 Mon Sep 17 00:00:00 2001 From: mathiskirchner Date: Tue, 18 Nov 2025 21:56:20 +0100 Subject: [PATCH 085/141] renamed IconListTile to TextIconListTile and replaced the icon parameter with iconEnabled in both TextIconListTile and TextIconTile --- .../widgets/tiles/text_icon_list_tile.dart | 28 +++++++++++++------ .../widgets/tiles/text_icon_tile.dart | 13 +++++---- 2 files changed, 27 insertions(+), 14 deletions(-) diff --git a/lib/presentation/widgets/tiles/text_icon_list_tile.dart b/lib/presentation/widgets/tiles/text_icon_list_tile.dart index b32504f..92d0251 100644 --- a/lib/presentation/widgets/tiles/text_icon_list_tile.dart +++ b/lib/presentation/widgets/tiles/text_icon_list_tile.dart @@ -1,16 +1,16 @@ import 'package:flutter/material.dart'; import 'package:game_tracker/core/custom_theme.dart'; -class IconListTile extends StatelessWidget { +class TextIconListTile extends StatelessWidget { final String text; - final IconData icon; final VoidCallback onPressed; + final bool iconEnabled; - const IconListTile({ + const TextIconListTile({ super.key, required this.text, - required this.icon, required this.onPressed, + this.iconEnabled = true, }); @override @@ -28,13 +28,23 @@ class IconListTile extends StatelessWidget { mainAxisSize: MainAxisSize.max, children: [ Flexible( - child: Text( - text, - overflow: TextOverflow.ellipsis, - style: const TextStyle(fontSize: 16, fontWeight: FontWeight.w500), + child: Container( + padding: const EdgeInsets.symmetric(vertical: 12.5), + child: Text( + text, + overflow: TextOverflow.ellipsis, + style: const TextStyle( + fontSize: 16, + fontWeight: FontWeight.w500, + ), + ), ), ), - IconButton(icon: Icon(icon, size: 20), onPressed: onPressed), + if (iconEnabled) + IconButton( + icon: const Icon(Icons.add, size: 20), + onPressed: onPressed, + ), ], ), ); diff --git a/lib/presentation/widgets/tiles/text_icon_tile.dart b/lib/presentation/widgets/tiles/text_icon_tile.dart index 52174bd..2544837 100644 --- a/lib/presentation/widgets/tiles/text_icon_tile.dart +++ b/lib/presentation/widgets/tiles/text_icon_tile.dart @@ -3,14 +3,14 @@ import 'package:game_tracker/core/custom_theme.dart'; class TextIconTile extends StatelessWidget { final String text; - final IconData? icon; + final bool iconEnabled; final VoidCallback? onIconTap; const TextIconTile({ super.key, required this.text, - this.icon, this.onIconTap, + this.iconEnabled = true, }); @override @@ -25,7 +25,7 @@ class TextIconTile extends StatelessWidget { mainAxisAlignment: MainAxisAlignment.spaceBetween, mainAxisSize: MainAxisSize.min, children: [ - if (icon != null) const SizedBox(width: 3), + if (iconEnabled) const SizedBox(width: 3), Flexible( child: Text( text, @@ -33,9 +33,12 @@ class TextIconTile extends StatelessWidget { style: const TextStyle(fontSize: 14, fontWeight: FontWeight.w500), ), ), - if (icon != null) ...[ + if (iconEnabled) ...[ const SizedBox(width: 3), - GestureDetector(onTap: onIconTap, child: Icon(icon, size: 20)), + GestureDetector( + onTap: onIconTap, + child: const Icon(Icons.close, size: 20), + ), ], ], ), From d34163488531a2cc37ac0f5c1577dca3c8df0f7b Mon Sep 17 00:00:00 2001 From: mathiskirchner Date: Tue, 18 Nov 2025 21:56:31 +0100 Subject: [PATCH 086/141] Disable icon for members in group tile --- lib/presentation/widgets/tiles/group_tile.dart | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/lib/presentation/widgets/tiles/group_tile.dart b/lib/presentation/widgets/tiles/group_tile.dart index d87cc12..fa91477 100644 --- a/lib/presentation/widgets/tiles/group_tile.dart +++ b/lib/presentation/widgets/tiles/group_tile.dart @@ -56,7 +56,8 @@ class GroupTile extends StatelessWidget { spacing: 12.0, runSpacing: 8.0, children: [ - for (var member in group.members) TextIconTile(text: member.name), + for (var member in group.members) + TextIconTile(text: member.name, iconEnabled: false), ], ), const SizedBox(height: 2.5), From 67c8a7e1811810a58e2344eade58703d096949a4 Mon Sep 17 00:00:00 2001 From: mathiskirchner Date: Tue, 18 Nov 2025 23:21:46 +0100 Subject: [PATCH 087/141] added createdAt timestamp to Group, Game, and Player DTOs --- lib/data/dto/game.dart | 5 ++++- lib/data/dto/group.dart | 10 ++++++++-- lib/data/dto/player.dart | 5 ++++- 3 files changed, 16 insertions(+), 4 deletions(-) diff --git a/lib/data/dto/game.dart b/lib/data/dto/game.dart index c84779d..b8ebf5c 100644 --- a/lib/data/dto/game.dart +++ b/lib/data/dto/game.dart @@ -8,14 +8,17 @@ class Game { final List? players; final Group? group; final String winner; + final DateTime createdAt; Game({ String? id, + DateTime? createdAt, required this.name, this.players, this.group, this.winner = '', - }) : id = id ?? const Uuid().v4(); + }) : id = id ?? const Uuid().v4(), + createdAt = createdAt ?? DateTime.now(); @override String toString() { diff --git a/lib/data/dto/group.dart b/lib/data/dto/group.dart index 0420477..6a27de1 100644 --- a/lib/data/dto/group.dart +++ b/lib/data/dto/group.dart @@ -5,9 +5,15 @@ class Group { final String id; final String name; final List members; + final DateTime createdAt; - Group({String? id, required this.name, required this.members}) - : id = id ?? const Uuid().v4(); + Group({ + String? id, + DateTime? createdAt, + required this.name, + required this.members, + }) : id = id ?? const Uuid().v4(), + createdAt = createdAt ?? DateTime.now(); @override String toString() { diff --git a/lib/data/dto/player.dart b/lib/data/dto/player.dart index 1b00c2c..5cbceef 100644 --- a/lib/data/dto/player.dart +++ b/lib/data/dto/player.dart @@ -3,8 +3,11 @@ import 'package:uuid/uuid.dart'; class Player { final String id; final String name; + final DateTime createdAt; - Player({String? id, required this.name}) : id = id ?? const Uuid().v4(); + Player({String? id, DateTime? createdAt, required this.name}) + : id = id ?? const Uuid().v4(), + createdAt = createdAt ?? DateTime.now(); @override String toString() { From 8cc898cad6b4b5e610dc9a38d0bdc1b15f631f9e Mon Sep 17 00:00:00 2001 From: mathiskirchner Date: Tue, 18 Nov 2025 23:38:43 +0100 Subject: [PATCH 088/141] regenerated database.g.dart --- lib/data/db/database.g.dart | 298 +++++++++++++++++++++++++++++++----- 1 file changed, 263 insertions(+), 35 deletions(-) diff --git a/lib/data/db/database.g.dart b/lib/data/db/database.g.dart index 03b7a10..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,6 +514,7 @@ class GroupTableCompanion extends UpdateCompanion { return (StringBuffer('GroupTableCompanion(') ..write('id: $id, ') ..write('name: $name, ') + ..write('createdAt: $createdAt, ') ..write('rowid: $rowid') ..write(')')) .toString(); @@ -451,8 +559,19 @@ class $GameTableTable extends GameTable 'REFERENCES player_table (id) ON DELETE CASCADE', ), ); + static const VerificationMeta _createdAtMeta = const VerificationMeta( + 'createdAt', + ); @override - List get $columns => [id, name, winnerId]; + 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 @@ -486,6 +605,14 @@ class $GameTableTable extends GameTable } 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; } @@ -507,6 +634,10 @@ class $GameTableTable extends GameTable DriftSqlType.string, data['${effectivePrefix}winner_id'], )!, + createdAt: attachedDatabase.typeMapping.read( + DriftSqlType.dateTime, + data['${effectivePrefix}created_at'], + )!, ); } @@ -520,10 +651,12 @@ class GameTableData extends DataClass implements Insertable { final String id; final String 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) { @@ -531,6 +664,7 @@ class GameTableData extends DataClass implements Insertable { map['id'] = Variable(id); map['name'] = Variable(name); map['winner_id'] = Variable(winnerId); + map['created_at'] = Variable(createdAt); return map; } @@ -539,6 +673,7 @@ class GameTableData extends DataClass implements Insertable { id: Value(id), name: Value(name), winnerId: Value(winnerId), + createdAt: Value(createdAt), ); } @@ -551,6 +686,7 @@ class GameTableData extends DataClass implements Insertable { id: serializer.fromJson(json['id']), name: serializer.fromJson(json['name']), winnerId: serializer.fromJson(json['winnerId']), + createdAt: serializer.fromJson(json['createdAt']), ); } @override @@ -560,20 +696,27 @@ class GameTableData extends DataClass implements Insertable { 'id': serializer.toJson(id), 'name': serializer.toJson(name), 'winnerId': serializer.toJson(winnerId), + 'createdAt': serializer.toJson(createdAt), }; } - GameTableData copyWith({String? id, String? name, String? winnerId}) => - GameTableData( - id: id ?? this.id, - name: name ?? this.name, - winnerId: winnerId ?? this.winnerId, - ); + 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, ); } @@ -582,51 +725,59 @@ class GameTableData extends DataClass implements Insertable { return (StringBuffer('GameTableData(') ..write('id: $id, ') ..write('name: $name, ') - ..write('winnerId: $winnerId') + ..write('winnerId: $winnerId, ') + ..write('createdAt: $createdAt') ..write(')')) .toString(); } @override - int get hashCode => Object.hash(id, name, winnerId); + 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.winnerId == this.winnerId); + 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), - winnerId = Value(winnerId); + 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, }); } @@ -635,12 +786,14 @@ class GameTableCompanion extends UpdateCompanion { 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, ); } @@ -657,6 +810,9 @@ class GameTableCompanion extends UpdateCompanion { 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); } @@ -669,6 +825,7 @@ class GameTableCompanion extends UpdateCompanion { ..write('id: $id, ') ..write('name: $name, ') ..write('winnerId: $winnerId, ') + ..write('createdAt: $createdAt, ') ..write('rowid: $rowid') ..write(')')) .toString(); @@ -1437,12 +1594,14 @@ 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, }); @@ -1534,6 +1693,11 @@ class $$PlayerTableTableFilterComposer builder: (column) => ColumnFilters(column), ); + ColumnFilters get createdAt => $composableBuilder( + column: $table.createdAt, + builder: (column) => ColumnFilters(column), + ); + Expression gameTableRefs( Expression Function($$GameTableTableFilterComposer f) f, ) { @@ -1628,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 @@ -1645,6 +1814,9 @@ 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, ) { @@ -1755,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) => ( @@ -1881,12 +2064,14 @@ 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, }); @@ -1958,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, ) { @@ -2027,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 @@ -2044,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, ) { @@ -2128,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) => ( @@ -2228,6 +2437,7 @@ typedef $$GameTableTableCreateCompanionBuilder = required String id, required String name, required String winnerId, + required DateTime createdAt, Value rowid, }); typedef $$GameTableTableUpdateCompanionBuilder = @@ -2235,6 +2445,7 @@ typedef $$GameTableTableUpdateCompanionBuilder = Value id, Value name, Value winnerId, + Value createdAt, Value rowid, }); @@ -2319,6 +2530,11 @@ class $$GameTableTableFilterComposer builder: (column) => ColumnFilters(column), ); + ColumnFilters get createdAt => $composableBuilder( + column: $table.createdAt, + builder: (column) => ColumnFilters(column), + ); + $$PlayerTableTableFilterComposer get winnerId { final $$PlayerTableTableFilterComposer composer = $composerBuilder( composer: this, @@ -2412,6 +2628,11 @@ class $$GameTableTableOrderingComposer builder: (column) => ColumnOrderings(column), ); + ColumnOrderings get createdAt => $composableBuilder( + column: $table.createdAt, + builder: (column) => ColumnOrderings(column), + ); + $$PlayerTableTableOrderingComposer get winnerId { final $$PlayerTableTableOrderingComposer composer = $composerBuilder( composer: this, @@ -2451,6 +2672,9 @@ class $$GameTableTableAnnotationComposer 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, @@ -2560,11 +2784,13 @@ class $$GameTableTableTableManager 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: @@ -2572,11 +2798,13 @@ class $$GameTableTableTableManager 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 From 2ee8edcf9b94a9cca5a57534656b76ecfbaca4d0 Mon Sep 17 00:00:00 2001 From: mathiskirchner Date: Tue, 18 Nov 2025 23:47:45 +0100 Subject: [PATCH 089/141] add createdAt column to game, group and player tables and DAOs --- lib/data/dao/game_dao.dart | 8 +++++++- lib/data/dao/group_dao.dart | 24 +++++++++++++++++++----- lib/data/dao/player_dao.dart | 22 +++++++++++++++++----- lib/data/db/tables/game_table.dart | 1 + lib/data/db/tables/group_table.dart | 1 + lib/data/db/tables/player_table.dart | 1 + 6 files changed, 46 insertions(+), 11 deletions(-) diff --git a/lib/data/dao/game_dao.dart b/lib/data/dao/game_dao.dart index fc931ad..94d010c 100644 --- a/lib/data/dao/game_dao.dart +++ b/lib/data/dao/game_dao.dart @@ -15,7 +15,11 @@ 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 [gameId]. @@ -38,6 +42,7 @@ class GameDao extends DatabaseAccessor with _$GameDaoMixin { players: players, group: group, winner: result.winnerId, + createdAt: result.createdAt, ); } @@ -58,6 +63,7 @@ class GameDao extends DatabaseAccessor with _$GameDaoMixin { id: game.id, name: game.name, winnerId: game.winner, + createdAt: game.createdAt, ), mode: InsertMode.insertOrReplace, ); diff --git a/lib/data/dao/group_dao.dart b/lib/data/dao/group_dao.dart index 8eb3a1a..1b0b09a 100644 --- a/lib/data/dao/group_dao.dart +++ b/lib/data/dao/group_dao.dart @@ -19,7 +19,12 @@ class GroupDao extends DatabaseAccessor with _$GroupDaoMixin { final members = await db.playerGroupDao.getPlayersOfGroupById( groupId: groupData.id, ); - return Group(id: groupData.id, name: groupData.name, members: members); + return Group( + id: groupData.id, + name: groupData.name, + members: members, + createdAt: groupData.createdAt, + ); }), ); } @@ -33,7 +38,12 @@ class GroupDao extends DatabaseAccessor with _$GroupDaoMixin { groupId: groupId, ); - 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. @@ -41,9 +51,13 @@ class GroupDao extends DatabaseAccessor with _$GroupDaoMixin { 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)); + await into(groupTable).insert( + GroupTableCompanion.insert( + id: group.id, + name: group.name, + createdAt: group.createdAt, + ), + ); await db.batch( (b) => b.insertAll( db.playerGroupTable, diff --git a/lib/data/dao/player_dao.dart b/lib/data/dao/player_dao.dart index 591634c..36f9305 100644 --- a/lib/data/dao/player_dao.dart +++ b/lib/data/dao/player_dao.dart @@ -13,14 +13,22 @@ 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({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. @@ -28,9 +36,13 @@ class PlayerDao extends DatabaseAccessor with _$PlayerDaoMixin { /// 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)); + await into(playerTable).insert( + PlayerTableCompanion.insert( + id: player.id, + name: player.name, + createdAt: player.createdAt, + ), + ); return true; } return false; diff --git a/lib/data/db/tables/game_table.dart b/lib/data/db/tables/game_table.dart index 9651a79..0fe5a3c 100644 --- a/lib/data/db/tables/game_table.dart +++ b/lib/data/db/tables/game_table.dart @@ -6,6 +6,7 @@ class GameTable extends Table { 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_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_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}; From 19c99eef9c5a2f581ab71d5d6bca8ee4120bd62c Mon Sep 17 00:00:00 2001 From: mathiskirchner Date: Wed, 19 Nov 2025 00:27:08 +0100 Subject: [PATCH 090/141] use clock.now() instead of DateTime.now() for DTO creation timestamps --- lib/data/dto/game.dart | 3 ++- lib/data/dto/group.dart | 3 ++- lib/data/dto/player.dart | 3 ++- 3 files changed, 6 insertions(+), 3 deletions(-) diff --git a/lib/data/dto/game.dart b/lib/data/dto/game.dart index b8ebf5c..96e9d73 100644 --- a/lib/data/dto/game.dart +++ b/lib/data/dto/game.dart @@ -1,3 +1,4 @@ +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'; @@ -18,7 +19,7 @@ class Game { this.group, this.winner = '', }) : id = id ?? const Uuid().v4(), - createdAt = createdAt ?? DateTime.now(); + createdAt = createdAt ?? clock.now(); @override String toString() { diff --git a/lib/data/dto/group.dart b/lib/data/dto/group.dart index 6a27de1..46c6f91 100644 --- a/lib/data/dto/group.dart +++ b/lib/data/dto/group.dart @@ -1,3 +1,4 @@ +import 'package:clock/clock.dart'; import 'package:game_tracker/data/dto/player.dart'; import 'package:uuid/uuid.dart'; @@ -13,7 +14,7 @@ class Group { required this.name, required this.members, }) : id = id ?? const Uuid().v4(), - createdAt = createdAt ?? DateTime.now(); + createdAt = createdAt ?? clock.now(); @override String toString() { diff --git a/lib/data/dto/player.dart b/lib/data/dto/player.dart index 5cbceef..4ef58b1 100644 --- a/lib/data/dto/player.dart +++ b/lib/data/dto/player.dart @@ -1,3 +1,4 @@ +import 'package:clock/clock.dart'; import 'package:uuid/uuid.dart'; class Player { @@ -7,7 +8,7 @@ class Player { Player({String? id, DateTime? createdAt, required this.name}) : id = id ?? const Uuid().v4(), - createdAt = createdAt ?? DateTime.now(); + createdAt = createdAt ?? clock.now(); @override String toString() { From 75c6f4e01c601cb8a084a25b33d7e3876cd29e88 Mon Sep 17 00:00:00 2001 From: mathiskirchner Date: Wed, 19 Nov 2025 00:27:40 +0100 Subject: [PATCH 091/141] verify createdAt timestamps in database tests using mocked clock --- test/db_tests/game_test.dart | 79 ++++++++++++-------- test/db_tests/group_test.dart | 133 +++++++++++++++++++-------------- test/db_tests/player_test.dart | 52 ++++++++----- 3 files changed, 156 insertions(+), 108 deletions(-) diff --git a/test/db_tests/game_test.dart b/test/db_tests/game_test.dart index 4f4b23f..0c86e45 100644 --- a/test/db_tests/game_test.dart +++ b/test/db_tests/game_test.dart @@ -1,3 +1,4 @@ +import 'package:clock/clock.dart'; import 'package:drift/drift.dart'; import 'package:drift/native.dart'; import 'package:flutter_test/flutter_test.dart'; @@ -15,6 +16,8 @@ void main() { 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( @@ -25,17 +28,22 @@ void main() { ), ); - 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], - ); + 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(); @@ -43,34 +51,41 @@ void main() { group('game tests', () { test('game is added correctly', () async { - await database.gameDao.addGame(game: testgame); + await withClock(fakeClock, () async { + await database.gameDao.addGame(game: testgame); - final result = await database.gameDao.getGameById(gameId: testgame.id); + 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.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); + 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); + 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'); } - } else { - fail('Group is null'); - } - if (result.players != null) { - expect(result.players!.length, testgame.players!.length); + 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); + 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'); } - } else { - fail('Players is null'); - } + }); }); test('game is deleted correctly', () async { diff --git a/test/db_tests/group_test.dart b/test/db_tests/group_test.dart index 3a9d8ca..5730617 100644 --- a/test/db_tests/group_test.dart +++ b/test/db_tests/group_test.dart @@ -1,3 +1,4 @@ +import 'package:clock/clock.dart'; import 'package:drift/drift.dart'; import 'package:drift/native.dart'; import 'package:flutter_test/flutter_test.dart'; @@ -12,6 +13,8 @@ void main() { late Player player3; late Player player4; late Group testgroup; + final fixedDate = DateTime(2025, 19, 11, 00, 11, 23); + final fakeClock = Clock(() => fixedDate); setUp(() { database = AppDatabase( @@ -22,54 +25,69 @@ void main() { ), ); - 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]); + 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], + ); + }); }); tearDown(() async { await database.close(); }); group('group tests', () { test('all groups get fetched correctly', () async { - final testgroup2 = Group( - id: 'gr2', - name: 'Second Group', - members: [player2, player3, player4], - ); - await database.groupDao.addGroup(group: testgroup); - await database.groupDao.addGroup(group: testgroup2); + await withClock(fakeClock, () async { + final testgroup2 = Group( + id: 'gr2', + name: 'Second Group', + members: [player2, player3, player4], + ); + await database.groupDao.addGroup(group: testgroup); + await database.groupDao.addGroup(group: testgroup2); - final allGroups = await database.groupDao.getAllGroups(); - expect(allGroups.length, 2); + 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); + 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); + 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); + await withClock(fakeClock, () async { + await database.groupDao.addGroup(group: testgroup); - final result = await database.groupDao.getGroupById( - groupId: testgroup.id, - ); + final result = await database.groupDao.getGroupById( + groupId: testgroup.id, + ); - expect(result.id, testgroup.id); - expect(result.name, testgroup.name); + 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.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 { @@ -103,36 +121,39 @@ void main() { }); test('Adding player to group works correctly', () async { - await database.groupDao.addGroup(group: testgroup); + await withClock(fakeClock, () async { + await database.groupDao.addGroup(group: testgroup); - await database.playerGroupDao.addPlayerToGroup( - player: player4, - groupId: testgroup.id, - ); + await database.playerGroupDao.addPlayerToGroup( + player: player4, + groupId: testgroup.id, + ); - final playerAdded = await database.playerGroupDao.isPlayerInGroup( - playerId: player4.id, - groupId: testgroup.id, - ); + final playerAdded = await database.playerGroupDao.isPlayerInGroup( + playerId: player4.id, + groupId: testgroup.id, + ); - expect(playerAdded, true); + expect(playerAdded, true); - final playerNotAdded = !await database.playerGroupDao.isPlayerInGroup( - playerId: '', - groupId: testgroup.id, - ); + final playerNotAdded = !await database.playerGroupDao.isPlayerInGroup( + playerId: '', + groupId: testgroup.id, + ); - expect(playerNotAdded, true); + expect(playerNotAdded, true); - expect(playerAdded, true); + final result = await database.groupDao.getGroupById( + groupId: testgroup.id, + ); + expect(result.members.length, testgroup.members.length + 1); - 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); + 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 { diff --git a/test/db_tests/player_test.dart b/test/db_tests/player_test.dart index 91f4acb..ce75297 100644 --- a/test/db_tests/player_test.dart +++ b/test/db_tests/player_test.dart @@ -1,3 +1,4 @@ +import 'package:clock/clock.dart'; import 'package:drift/drift.dart'; import 'package:drift/native.dart'; import 'package:flutter_test/flutter_test.dart'; @@ -7,6 +8,8 @@ import 'package:game_tracker/data/dto/player.dart'; void main() { late AppDatabase database; late Player testPlayer; + final fixedDate = DateTime(2025, 19, 11, 00, 11, 23); + final fakeClock = Clock(() => fixedDate); setUp(() { database = AppDatabase( @@ -17,7 +20,9 @@ void main() { ), ); - testPlayer = Player(name: 'Test Player'); + withClock(fakeClock, () { + testPlayer = Player(name: 'Test Player'); + }); }); tearDown(() async { await database.close(); @@ -25,32 +30,39 @@ void main() { group('player tests', () { test('all players get fetched correctly', () async { - final testPlayer2 = Player(name: 'Second Group'); - await database.playerDao.addPlayer(player: testPlayer); - await database.playerDao.addPlayer(player: testPlayer2); + await withClock(fakeClock, () async { + final testPlayer2 = Player(name: 'Second Group'); + await database.playerDao.addPlayer(player: testPlayer); + await database.playerDao.addPlayer(player: testPlayer2); - final allPlayers = await database.playerDao.getAllPlayers(); - expect(allPlayers.length, 2); + final allPlayers = await database.playerDao.getAllPlayers(); + expect(allPlayers.length, 2); - final fetchedPlayer1 = allPlayers.firstWhere( - (g) => g.id == testPlayer.id, - ); - expect(fetchedPlayer1.name, testPlayer.name); + 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); + 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, - ); + await withClock(fakeClock, () 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.id, testPlayer.id); + expect(result.name, testPlayer.name); + expect(result.createdAt, testPlayer.createdAt); + }); }); test('players get deleted correcly ', () async { From 8150b42dbad6a3ce79c46a53d3431b345a2ce3c9 Mon Sep 17 00:00:00 2001 From: mathiskirchner Date: Wed, 19 Nov 2025 00:27:47 +0100 Subject: [PATCH 092/141] add `clock` dependency to pubspec.yaml --- pubspec.yaml | 1 + 1 file changed, 1 insertion(+) diff --git a/pubspec.yaml b/pubspec.yaml index fbbc01a..b17f409 100644 --- a/pubspec.yaml +++ b/pubspec.yaml @@ -20,6 +20,7 @@ dependencies: provider: ^6.1.5 skeletonizer: ^2.1.0+1 uuid: ^4.5.2 + clock: ^1.1.2 dev_dependencies: flutter_test: From a8962e68b66bc42793b705557db1e3474ecab765 Mon Sep 17 00:00:00 2001 From: Felix Kirchner Date: Wed, 19 Nov 2025 09:51:37 +0100 Subject: [PATCH 093/141] Added first workflow --- .gitea/workflows/pull_request.yaml | 39 ++++++++++++++++++++++++++++++ 1 file changed, 39 insertions(+) create mode 100644 .gitea/workflows/pull_request.yaml diff --git a/.gitea/workflows/pull_request.yaml b/.gitea/workflows/pull_request.yaml new file mode 100644 index 0000000..8daedbc --- /dev/null +++ b/.gitea/workflows/pull_request.yaml @@ -0,0 +1,39 @@ +name: Pull Request Pipeline + +on: + pull_request: + +jobs: + lint: + runs-on: ubuntu-latest + steps: + - name: Checkout code + uses: actions/checkout@v4 + + - name: Set Up Flutter + uses: subosito/flutter-action@v2 + with: + flutter-version: 'stable' + channel: 'stable' + + - name: Check Formatting + run: flutter analyze + + test: + runs-on: ubuntu-latest + needs: lint + + steps: + - uses: actions/checkout@v4 + + - name: Set Up Flutter + uses: subosito/flutter-action@v2 + with: + flutter-version: 'stable' + channel: 'stable' + + - name: Get dependencies + run: flutter pub get + + - name: Run Tests + run: flutter test \ No newline at end of file From eeec92181a1f6e63350b77c4f1c936d202d4a4c8 Mon Sep 17 00:00:00 2001 From: Felix Kirchner Date: Wed, 19 Nov 2025 09:53:54 +0100 Subject: [PATCH 094/141] Added jq installation --- .gitea/workflows/pull_request.yaml | 3 +++ 1 file changed, 3 insertions(+) diff --git a/.gitea/workflows/pull_request.yaml b/.gitea/workflows/pull_request.yaml index 8daedbc..9985eb8 100644 --- a/.gitea/workflows/pull_request.yaml +++ b/.gitea/workflows/pull_request.yaml @@ -10,6 +10,9 @@ jobs: - name: Checkout code uses: actions/checkout@v4 + - name: Install jq + run: sudo apt-get install -y jq + - name: Set Up Flutter uses: subosito/flutter-action@v2 with: From ddc8d93592f715779499b7122c86e41324563022 Mon Sep 17 00:00:00 2001 From: Felix Kirchner Date: Wed, 19 Nov 2025 09:56:05 +0100 Subject: [PATCH 095/141] Removed sudo --- .gitea/workflows/pull_request.yaml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.gitea/workflows/pull_request.yaml b/.gitea/workflows/pull_request.yaml index 9985eb8..1593c18 100644 --- a/.gitea/workflows/pull_request.yaml +++ b/.gitea/workflows/pull_request.yaml @@ -11,7 +11,7 @@ jobs: uses: actions/checkout@v4 - name: Install jq - run: sudo apt-get install -y jq + run: apt-get install -y jq - name: Set Up Flutter uses: subosito/flutter-action@v2 From 8d91eb37808a41ea865716ab6f10e1a2d104b3c5 Mon Sep 17 00:00:00 2001 From: Felix Kirchner Date: Wed, 19 Nov 2025 09:58:03 +0100 Subject: [PATCH 096/141] Added update --- .gitea/workflows/pull_request.yaml | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/.gitea/workflows/pull_request.yaml b/.gitea/workflows/pull_request.yaml index 1593c18..25b7c7e 100644 --- a/.gitea/workflows/pull_request.yaml +++ b/.gitea/workflows/pull_request.yaml @@ -11,7 +11,9 @@ jobs: uses: actions/checkout@v4 - name: Install jq - run: apt-get install -y jq + run: | + apt-get update + apt-get install -y jq - name: Set Up Flutter uses: subosito/flutter-action@v2 From 003835472d107cd578dd4ff486a3767f038f0264 Mon Sep 17 00:00:00 2001 From: Felix Kirchner Date: Wed, 19 Nov 2025 10:00:09 +0100 Subject: [PATCH 097/141] Added flutter version again --- .gitea/workflows/pull_request.yaml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.gitea/workflows/pull_request.yaml b/.gitea/workflows/pull_request.yaml index 25b7c7e..22869cf 100644 --- a/.gitea/workflows/pull_request.yaml +++ b/.gitea/workflows/pull_request.yaml @@ -18,7 +18,7 @@ jobs: - name: Set Up Flutter uses: subosito/flutter-action@v2 with: - flutter-version: 'stable' + flutter-version: '3.38.2' channel: 'stable' - name: Check Formatting From 6ae39717fdfe4214bfe6383c22433dc46fbdc12c Mon Sep 17 00:00:00 2001 From: Felix Kirchner Date: Wed, 19 Nov 2025 10:02:39 +0100 Subject: [PATCH 098/141] Cleaned flutter cache --- .gitea/workflows/pull_request.yaml | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/.gitea/workflows/pull_request.yaml b/.gitea/workflows/pull_request.yaml index 22869cf..4ac911b 100644 --- a/.gitea/workflows/pull_request.yaml +++ b/.gitea/workflows/pull_request.yaml @@ -14,6 +14,12 @@ jobs: run: | apt-get update apt-get install -y jq + + + - name: Clean Flutter Cache + run: | + rm -rf /opt/hostedtoolcache/flutter + rm -rf ~/flutter - name: Set Up Flutter uses: subosito/flutter-action@v2 From 63d2117a6a40836642801180029aafd4571929b5 Mon Sep 17 00:00:00 2001 From: Felix Kirchner Date: Wed, 19 Nov 2025 10:05:55 +0100 Subject: [PATCH 099/141] Tried sth --- .gitea/workflows/pull_request.yaml | 9 +++------ 1 file changed, 3 insertions(+), 6 deletions(-) diff --git a/.gitea/workflows/pull_request.yaml b/.gitea/workflows/pull_request.yaml index 4ac911b..2550dcf 100644 --- a/.gitea/workflows/pull_request.yaml +++ b/.gitea/workflows/pull_request.yaml @@ -21,15 +21,12 @@ jobs: rm -rf /opt/hostedtoolcache/flutter rm -rf ~/flutter - - name: Set Up Flutter - uses: subosito/flutter-action@v2 - with: - flutter-version: '3.38.2' - channel: 'stable' - - name: Check Formatting run: flutter analyze + + + test: runs-on: ubuntu-latest needs: lint From 974f06b6b886ef23846ac890906c77264e6c7566 Mon Sep 17 00:00:00 2001 From: Felix Kirchner Date: Wed, 19 Nov 2025 10:06:46 +0100 Subject: [PATCH 100/141] Back again --- .gitea/workflows/pull_request.yaml | 7 ++++++- 1 file changed, 6 insertions(+), 1 deletion(-) diff --git a/.gitea/workflows/pull_request.yaml b/.gitea/workflows/pull_request.yaml index 2550dcf..8f8f0d1 100644 --- a/.gitea/workflows/pull_request.yaml +++ b/.gitea/workflows/pull_request.yaml @@ -21,12 +21,17 @@ jobs: rm -rf /opt/hostedtoolcache/flutter rm -rf ~/flutter + - name: Set Up Flutter + uses: subosito/flutter-action@v2 + with: + flutter-version: '3.38.2' + channel: 'stable' + - name: Check Formatting run: flutter analyze - test: runs-on: ubuntu-latest needs: lint From 6638c2deee81a4f67402e0b3de48fbc6467677f0 Mon Sep 17 00:00:00 2001 From: Felix Kirchner Date: Wed, 19 Nov 2025 10:08:04 +0100 Subject: [PATCH 101/141] Removed cache clearing --- .gitea/workflows/pull_request.yaml | 6 ------ 1 file changed, 6 deletions(-) diff --git a/.gitea/workflows/pull_request.yaml b/.gitea/workflows/pull_request.yaml index 8f8f0d1..b2027d6 100644 --- a/.gitea/workflows/pull_request.yaml +++ b/.gitea/workflows/pull_request.yaml @@ -14,12 +14,6 @@ jobs: run: | apt-get update apt-get install -y jq - - - - name: Clean Flutter Cache - run: | - rm -rf /opt/hostedtoolcache/flutter - rm -rf ~/flutter - name: Set Up Flutter uses: subosito/flutter-action@v2 From 10e56a7241928f2873e52d271b99d006fbe0362f Mon Sep 17 00:00:00 2001 From: Felix Kirchner Date: Wed, 19 Nov 2025 10:09:15 +0100 Subject: [PATCH 102/141] Downgraded flutter version --- .gitea/workflows/pull_request.yaml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.gitea/workflows/pull_request.yaml b/.gitea/workflows/pull_request.yaml index b2027d6..d209dd2 100644 --- a/.gitea/workflows/pull_request.yaml +++ b/.gitea/workflows/pull_request.yaml @@ -18,8 +18,8 @@ jobs: - name: Set Up Flutter uses: subosito/flutter-action@v2 with: - flutter-version: '3.38.2' channel: 'stable' + flutter-version: '3.22.0' - name: Check Formatting run: flutter analyze From 7cc72015d3705a7e75821fec31bf7c84d5049ae6 Mon Sep 17 00:00:00 2001 From: Felix Kirchner Date: Wed, 19 Nov 2025 10:11:22 +0100 Subject: [PATCH 103/141] Upgraded to flutter 3.35.6 --- .gitea/workflows/pull_request.yaml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.gitea/workflows/pull_request.yaml b/.gitea/workflows/pull_request.yaml index d209dd2..867f174 100644 --- a/.gitea/workflows/pull_request.yaml +++ b/.gitea/workflows/pull_request.yaml @@ -19,7 +19,7 @@ jobs: uses: subosito/flutter-action@v2 with: channel: 'stable' - flutter-version: '3.22.0' + flutter-version: '3.35.6' - name: Check Formatting run: flutter analyze From 7123d36cd811a6cabc45e36622c382faa7df6d63 Mon Sep 17 00:00:00 2001 From: Felix Kirchner Date: Wed, 19 Nov 2025 10:15:12 +0100 Subject: [PATCH 104/141] Updated flutter installation way --- .gitea/workflows/pull_request.yaml | 27 ++++++++++++++++++++------- 1 file changed, 20 insertions(+), 7 deletions(-) diff --git a/.gitea/workflows/pull_request.yaml b/.gitea/workflows/pull_request.yaml index 867f174..0b71231 100644 --- a/.gitea/workflows/pull_request.yaml +++ b/.gitea/workflows/pull_request.yaml @@ -15,11 +15,18 @@ jobs: apt-get update apt-get install -y jq - - name: Set Up Flutter - uses: subosito/flutter-action@v2 - with: - channel: 'stable' - flutter-version: '3.35.6' + - name: Install Flutter + run: | + # Flutter SDK herunterladen und entpacken + wget https://storage.googleapis.com/flutter_infra_release/releases/stable/linux/flutter_linux_3.35.6-stable.tar.xz + tar xf flutter_linux_3.35.6-stable.tar.xz + # Flutter zum PATH hinzufügen + echo "$(pwd)/flutter/bin" >> $GITHUB_PATH + # Flutter Doctor ausführen (optional) + flutter doctor -v + + - name: Get dependencies + run: flutter pub get - name: Check Formatting run: flutter analyze @@ -31,13 +38,19 @@ jobs: needs: lint steps: - - uses: actions/checkout@v4 + - name: Checkout code + uses: actions/checkout@v4 + + - name: Install jq + run: | + apt-get update + apt-get install -y jq - name: Set Up Flutter uses: subosito/flutter-action@v2 with: - flutter-version: 'stable' channel: 'stable' + flutter-version: '3.35.0' - name: Get dependencies run: flutter pub get From 17c14dd2302c32230667b30de1abd668a22c7c98 Mon Sep 17 00:00:00 2001 From: Felix Kirchner Date: Wed, 19 Nov 2025 10:19:45 +0100 Subject: [PATCH 105/141] Added container --- .gitea/workflows/pull_request.yaml | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/.gitea/workflows/pull_request.yaml b/.gitea/workflows/pull_request.yaml index 0b71231..a28864a 100644 --- a/.gitea/workflows/pull_request.yaml +++ b/.gitea/workflows/pull_request.yaml @@ -6,6 +6,7 @@ on: jobs: lint: runs-on: ubuntu-latest + container: node:18-bullseye steps: - name: Checkout code uses: actions/checkout@v4 @@ -21,7 +22,7 @@ jobs: wget https://storage.googleapis.com/flutter_infra_release/releases/stable/linux/flutter_linux_3.35.6-stable.tar.xz tar xf flutter_linux_3.35.6-stable.tar.xz # Flutter zum PATH hinzufügen - echo "$(pwd)/flutter/bin" >> $GITHUB_PATH + echo "$(pwd)/flutter/bin" >> /usr/local/bin # Flutter Doctor ausführen (optional) flutter doctor -v From e108bb41f6b8ffa464bce490c6ac440dcf76d4ba Mon Sep 17 00:00:00 2001 From: Felix Kirchner Date: Wed, 19 Nov 2025 10:22:55 +0100 Subject: [PATCH 106/141] Corrected installation --- .gitea/workflows/pull_request.yaml | 9 ++++----- 1 file changed, 4 insertions(+), 5 deletions(-) diff --git a/.gitea/workflows/pull_request.yaml b/.gitea/workflows/pull_request.yaml index a28864a..62aa58e 100644 --- a/.gitea/workflows/pull_request.yaml +++ b/.gitea/workflows/pull_request.yaml @@ -18,13 +18,12 @@ jobs: - name: Install Flutter run: | - # Flutter SDK herunterladen und entpacken wget https://storage.googleapis.com/flutter_infra_release/releases/stable/linux/flutter_linux_3.35.6-stable.tar.xz tar xf flutter_linux_3.35.6-stable.tar.xz - # Flutter zum PATH hinzufügen - echo "$(pwd)/flutter/bin" >> /usr/local/bin - # Flutter Doctor ausführen (optional) - flutter doctor -v + # Flutter-Pfad zur PATH-Variable hinzufügen + echo "$(pwd)/flutter/bin" >> $GITHUB_PATH + # Alternativ für Docker/act: + echo "PATH=$(pwd)/flutter/bin:$PATH" >> $GITHUB_ENV - name: Get dependencies run: flutter pub get From e852a4d53976fe0a6a051dfd03169ece057d9392 Mon Sep 17 00:00:00 2001 From: Felix Kirchner Date: Wed, 19 Nov 2025 10:26:34 +0100 Subject: [PATCH 107/141] Added git safe directory --- .gitea/workflows/pull_request.yaml | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/.gitea/workflows/pull_request.yaml b/.gitea/workflows/pull_request.yaml index 62aa58e..a222eff 100644 --- a/.gitea/workflows/pull_request.yaml +++ b/.gitea/workflows/pull_request.yaml @@ -25,6 +25,12 @@ jobs: # Alternativ für Docker/act: echo "PATH=$(pwd)/flutter/bin:$PATH" >> $GITHUB_ENV + - name: Configure Git Safe Directory + run: | + git config --global --add safe.directory /workspace/liquid-development/game-tracker + git config --global --add safe.directory /workspace/liquid-development/game-tracker/flutter + + - name: Get dependencies run: flutter pub get From 601b7d0a4f654bfc8bff848178560c3ddf169ee8 Mon Sep 17 00:00:00 2001 From: Felix Kirchner Date: Wed, 19 Nov 2025 10:36:48 +0100 Subject: [PATCH 108/141] Changed flutter installation --- .gitea/workflows/pull_request.yaml | 13 +++++-------- 1 file changed, 5 insertions(+), 8 deletions(-) diff --git a/.gitea/workflows/pull_request.yaml b/.gitea/workflows/pull_request.yaml index a222eff..c8b25e9 100644 --- a/.gitea/workflows/pull_request.yaml +++ b/.gitea/workflows/pull_request.yaml @@ -16,14 +16,11 @@ jobs: apt-get update apt-get install -y jq - - name: Install Flutter - run: | - wget https://storage.googleapis.com/flutter_infra_release/releases/stable/linux/flutter_linux_3.35.6-stable.tar.xz - tar xf flutter_linux_3.35.6-stable.tar.xz - # Flutter-Pfad zur PATH-Variable hinzufügen - echo "$(pwd)/flutter/bin" >> $GITHUB_PATH - # Alternativ für Docker/act: - echo "PATH=$(pwd)/flutter/bin:$PATH" >> $GITHUB_ENV + - name: Set Up Flutter + uses: flutter-actions/setup-flutter@v2 + with: + flutter-version: '3.35.6' + channel: 'stable' - name: Configure Git Safe Directory run: | From 7ac5986588749d2d55e6eca9225b95900135d088 Mon Sep 17 00:00:00 2001 From: Felix Kirchner Date: Wed, 19 Nov 2025 10:41:12 +0100 Subject: [PATCH 109/141] Updated whole workflow --- .gitea/workflows/pull_request.yaml | 27 ++++++++++++++------------- 1 file changed, 14 insertions(+), 13 deletions(-) diff --git a/.gitea/workflows/pull_request.yaml b/.gitea/workflows/pull_request.yaml index c8b25e9..5338cab 100644 --- a/.gitea/workflows/pull_request.yaml +++ b/.gitea/workflows/pull_request.yaml @@ -11,28 +11,29 @@ jobs: - name: Checkout code uses: actions/checkout@v4 - - name: Install jq + - name: Install dependencies run: | apt-get update - apt-get install -y jq + apt-get install -y jq git wget unzip xz-utils - - name: Set Up Flutter - uses: flutter-actions/setup-flutter@v2 - with: - flutter-version: '3.35.6' - channel: 'stable' - - - name: Configure Git Safe Directory + - name: Install Flutter (lokal) run: | - git config --global --add safe.directory /workspace/liquid-development/game-tracker - git config --global --add safe.directory /workspace/liquid-development/game-tracker/flutter + 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 + # Git-Safe-Directory für Flutter-Pfad setzen + git config --global --add safe.directory "$(pwd)/flutter" + # Flutter-Pfad setzen + echo "$(pwd)/flutter/bin" >> $GITHUB_PATH + - name: Configure Git Safe Directory (für Projekt) + run: | + git config --global --add safe.directory "$(pwd)" - name: Get dependencies - run: flutter pub get + run: ./flutter/bin/flutter pub get - name: Check Formatting - run: flutter analyze + run: ./flutter/bin/flutter analyze From 6ae1ce9bc71ea90cd231188d315adf2042612bef Mon Sep 17 00:00:00 2001 From: Felix Kirchner Date: Wed, 19 Nov 2025 10:47:14 +0100 Subject: [PATCH 110/141] Updated analyzing --- .gitea/workflows/pull_request.yaml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.gitea/workflows/pull_request.yaml b/.gitea/workflows/pull_request.yaml index 5338cab..f44a8f9 100644 --- a/.gitea/workflows/pull_request.yaml +++ b/.gitea/workflows/pull_request.yaml @@ -33,7 +33,7 @@ jobs: run: ./flutter/bin/flutter pub get - name: Check Formatting - run: ./flutter/bin/flutter analyze + run: ./flutter/bin/flutter analyze lib test From 91b68eac3edd02f30b3db38fbee01567b308837b Mon Sep 17 00:00:00 2001 From: Felix Kirchner Date: Wed, 19 Nov 2025 10:50:56 +0100 Subject: [PATCH 111/141] Implemented test workflow --- .gitea/workflows/pull_request.yaml | 30 ++++++++++++++++-------------- 1 file changed, 16 insertions(+), 14 deletions(-) diff --git a/.gitea/workflows/pull_request.yaml b/.gitea/workflows/pull_request.yaml index f44a8f9..2dbe146 100644 --- a/.gitea/workflows/pull_request.yaml +++ b/.gitea/workflows/pull_request.yaml @@ -25,9 +25,9 @@ jobs: # Flutter-Pfad setzen echo "$(pwd)/flutter/bin" >> $GITHUB_PATH - - name: Configure Git Safe Directory (für Projekt) - run: | - git config --global --add safe.directory "$(pwd)" + # - name: Configure Git Safe Directory (für Projekt) + # run: | + # git config --global --add safe.directory "$(pwd)" - name: Get dependencies run: ./flutter/bin/flutter pub get @@ -39,25 +39,27 @@ jobs: test: runs-on: ubuntu-latest - needs: lint steps: - name: Checkout code uses: actions/checkout@v4 - - name: Install jq + - name: Install dependencies run: | apt-get update - apt-get install -y jq + apt-get install -y jq git wget unzip xz-utils - - name: Set Up Flutter - uses: subosito/flutter-action@v2 - with: - channel: 'stable' - flutter-version: '3.35.0' + - name: Install Flutter (lokal) + 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 + # Git-Safe-Directory für Flutter-Pfad setzen + git config --global --add safe.directory "$(pwd)/flutter" + # Flutter-Pfad setzen + echo "$(pwd)/flutter/bin" >> $GITHUB_PATH - name: Get dependencies - run: flutter pub get + run: ./flutter/bin/flutter pub get - - name: Run Tests - run: flutter test \ No newline at end of file + - name: Check Formatting + run: ./flutter/bin/flutter test \ No newline at end of file From a3b45053e72108812beaee76feeb0df20eae6d63 Mon Sep 17 00:00:00 2001 From: Felix Kirchner Date: Wed, 19 Nov 2025 10:54:58 +0100 Subject: [PATCH 112/141] Finalized workflow --- .gitea/workflows/pull_request.yaml | 20 +++++++------------- 1 file changed, 7 insertions(+), 13 deletions(-) diff --git a/.gitea/workflows/pull_request.yaml b/.gitea/workflows/pull_request.yaml index 2dbe146..1122252 100644 --- a/.gitea/workflows/pull_request.yaml +++ b/.gitea/workflows/pull_request.yaml @@ -11,12 +11,12 @@ jobs: - name: Checkout code uses: actions/checkout@v4 - - name: Install dependencies + - name: Install jq run: | apt-get update - apt-get install -y jq git wget unzip xz-utils + apt-get install -y jq - - name: Install Flutter (lokal) + - 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 @@ -25,18 +25,12 @@ jobs: # Flutter-Pfad setzen echo "$(pwd)/flutter/bin" >> $GITHUB_PATH - # - name: Configure Git Safe Directory (für Projekt) - # run: | - # git config --global --add safe.directory "$(pwd)" - - name: Get dependencies run: ./flutter/bin/flutter pub get - - name: Check Formatting + - name: Analyze Formatting run: ./flutter/bin/flutter analyze lib test - - test: runs-on: ubuntu-latest @@ -47,9 +41,9 @@ jobs: - name: Install dependencies run: | apt-get update - apt-get install -y jq git wget unzip xz-utils + apt-get install -y jq - - name: Install Flutter (lokal) + - 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 @@ -61,5 +55,5 @@ jobs: - name: Get dependencies run: ./flutter/bin/flutter pub get - - name: Check Formatting + - name: Run tests run: ./flutter/bin/flutter test \ No newline at end of file From c89243f886d9241fdf26d13b49de2c443e2aafb1 Mon Sep 17 00:00:00 2001 From: Felix Kirchner Date: Wed, 19 Nov 2025 10:57:53 +0100 Subject: [PATCH 113/141] Tried sth --- .gitea/workflows/pull_request.yaml | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/.gitea/workflows/pull_request.yaml b/.gitea/workflows/pull_request.yaml index 1122252..187eef9 100644 --- a/.gitea/workflows/pull_request.yaml +++ b/.gitea/workflows/pull_request.yaml @@ -29,7 +29,7 @@ jobs: run: ./flutter/bin/flutter pub get - name: Analyze Formatting - run: ./flutter/bin/flutter analyze lib test + run: flutter analyze lib test test: runs-on: ubuntu-latest @@ -53,7 +53,7 @@ jobs: echo "$(pwd)/flutter/bin" >> $GITHUB_PATH - name: Get dependencies - run: ./flutter/bin/flutter pub get + run: flutter pub get - name: Run tests - run: ./flutter/bin/flutter test \ No newline at end of file + run: flutter test \ No newline at end of file From f136400c7e9bc5e0dde36e9de823a9e665ce6e97 Mon Sep 17 00:00:00 2001 From: Felix Kirchner Date: Wed, 19 Nov 2025 11:01:33 +0100 Subject: [PATCH 114/141] Final changes? --- .gitea/workflows/pull_request.yaml | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) diff --git a/.gitea/workflows/pull_request.yaml b/.gitea/workflows/pull_request.yaml index 187eef9..dcc95c1 100644 --- a/.gitea/workflows/pull_request.yaml +++ b/.gitea/workflows/pull_request.yaml @@ -20,13 +20,13 @@ jobs: 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 - # Git-Safe-Directory für Flutter-Pfad setzen + # Set Git safe directory for Flutter path git config --global --add safe.directory "$(pwd)/flutter" - # Flutter-Pfad setzen + # Set Flutter path echo "$(pwd)/flutter/bin" >> $GITHUB_PATH - name: Get dependencies - run: ./flutter/bin/flutter pub get + run: flutter pub get - name: Analyze Formatting run: flutter analyze lib test @@ -47,9 +47,9 @@ jobs: 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 - # Git-Safe-Directory für Flutter-Pfad setzen + # Set Git safe directory for Flutter path git config --global --add safe.directory "$(pwd)/flutter" - # Flutter-Pfad setzen + # Set Flutter path echo "$(pwd)/flutter/bin" >> $GITHUB_PATH - name: Get dependencies From 1732878c7fcb3d64f6ad4c840175ab1737c23bdc Mon Sep 17 00:00:00 2001 From: Felix Kirchner Date: Wed, 19 Nov 2025 11:03:10 +0100 Subject: [PATCH 115/141] Tested sth --- .gitea/workflows/pull_request.yaml | 42 +++++++++++++++++++++++++++++- 1 file changed, 41 insertions(+), 1 deletion(-) diff --git a/.gitea/workflows/pull_request.yaml b/.gitea/workflows/pull_request.yaml index dcc95c1..6299f66 100644 --- a/.gitea/workflows/pull_request.yaml +++ b/.gitea/workflows/pull_request.yaml @@ -56,4 +56,44 @@ jobs: run: flutter pub get - name: Run tests - run: flutter test \ No newline at end of file + run: flutter test + + format: + 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 & upgrade dependencies + run: | + flutter pub get + flutter pub upgrade --major-versions + + - name: Auto-format + run: | + dart format . + dart fix --apply + + - name: Commit Changes + if: steps.check_changes.outputs.changes_detected == 'true' + run: | + # git config --global user.name "GitHub Actions" + # git config --global user.email "actions@github.com" + git add . + git commit -m "Actions: Auto-formatting [skip ci]" + git push \ No newline at end of file From e5268ebc12d776aaa83f49a8921c86e2d920b388 Mon Sep 17 00:00:00 2001 From: Felix Kirchner Date: Wed, 19 Nov 2025 11:03:10 +0100 Subject: [PATCH 116/141] Tested sth --- .gitea/workflows/pull_request.yaml | 42 +++++++++++++++++++++++++++++- 1 file changed, 41 insertions(+), 1 deletion(-) diff --git a/.gitea/workflows/pull_request.yaml b/.gitea/workflows/pull_request.yaml index dcc95c1..6299f66 100644 --- a/.gitea/workflows/pull_request.yaml +++ b/.gitea/workflows/pull_request.yaml @@ -56,4 +56,44 @@ jobs: run: flutter pub get - name: Run tests - run: flutter test \ No newline at end of file + run: flutter test + + format: + 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 & upgrade dependencies + run: | + flutter pub get + flutter pub upgrade --major-versions + + - name: Auto-format + run: | + dart format . + dart fix --apply + + - name: Commit Changes + if: steps.check_changes.outputs.changes_detected == 'true' + run: | + # git config --global user.name "GitHub Actions" + # git config --global user.email "actions@github.com" + git add . + git commit -m "Actions: Auto-formatting [skip ci]" + git push \ No newline at end of file From 594ea947c2e074236935541e9d5aa67d8b9d11a5 Mon Sep 17 00:00:00 2001 From: Felix Kirchner Date: Wed, 19 Nov 2025 11:06:40 +0100 Subject: [PATCH 117/141] Tested sth --- .gitea/workflows/pull_request.yaml | 3 --- 1 file changed, 3 deletions(-) diff --git a/.gitea/workflows/pull_request.yaml b/.gitea/workflows/pull_request.yaml index 6299f66..01a3780 100644 --- a/.gitea/workflows/pull_request.yaml +++ b/.gitea/workflows/pull_request.yaml @@ -6,7 +6,6 @@ on: jobs: lint: runs-on: ubuntu-latest - container: node:18-bullseye steps: - name: Checkout code uses: actions/checkout@v4 @@ -33,7 +32,6 @@ jobs: test: runs-on: ubuntu-latest - steps: - name: Checkout code uses: actions/checkout@v4 @@ -60,7 +58,6 @@ jobs: format: runs-on: ubuntu-latest - steps: - name: Checkout code uses: actions/checkout@v4 From 346dddcf62ec7bdd82858ccb256bc6f20d2f3fed Mon Sep 17 00:00:00 2001 From: Felix Kirchner Date: Wed, 19 Nov 2025 11:08:01 +0100 Subject: [PATCH 118/141] testing formatting --- .gitea/workflows/pull_request.yaml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.gitea/workflows/pull_request.yaml b/.gitea/workflows/pull_request.yaml index 22e794d..0e075d5 100644 --- a/.gitea/workflows/pull_request.yaml +++ b/.gitea/workflows/pull_request.yaml @@ -86,7 +86,7 @@ jobs: - name: Auto-format run: | dart format . - dart fix --apply + dart fix --apply - name: Commit Changes if: steps.check_changes.outputs.changes_detected == 'true' From dd8af42a472568178efca2103d14ab5b5c20c7e9 Mon Sep 17 00:00:00 2001 From: Felix Kirchner Date: Wed, 19 Nov 2025 11:08:30 +0100 Subject: [PATCH 119/141] corrected workflow --- .gitea/workflows/pull_request.yaml | 4 +--- 1 file changed, 1 insertion(+), 3 deletions(-) diff --git a/.gitea/workflows/pull_request.yaml b/.gitea/workflows/pull_request.yaml index 0e075d5..d30f3fe 100644 --- a/.gitea/workflows/pull_request.yaml +++ b/.gitea/workflows/pull_request.yaml @@ -91,8 +91,6 @@ jobs: - name: Commit Changes if: steps.check_changes.outputs.changes_detected == 'true' run: | - # git config --global user.name "GitHub Actions" - # git config --global user.email "actions@github.com" git add . git commit -m "Actions: Auto-formatting [skip ci]" - git push \ No newline at end of file + git push From 5d8047b3ba4a59e1743e5d4ae5b9315dd792da2c Mon Sep 17 00:00:00 2001 From: Felix Kirchner Date: Wed, 19 Nov 2025 11:12:02 +0100 Subject: [PATCH 120/141] Updated directorys --- .gitea/workflows/pull_request.yaml | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/.gitea/workflows/pull_request.yaml b/.gitea/workflows/pull_request.yaml index d30f3fe..89bf9df 100644 --- a/.gitea/workflows/pull_request.yaml +++ b/.gitea/workflows/pull_request.yaml @@ -60,6 +60,7 @@ jobs: format: runs-on: ubuntu-latest + if: false # steps: - name: Checkout code uses: actions/checkout@v4 @@ -85,8 +86,8 @@ jobs: - name: Auto-format run: | - dart format . - dart fix --apply + dart format lib test + dart fix --apply lib test - name: Commit Changes if: steps.check_changes.outputs.changes_detected == 'true' From 89d7bb54a1bf16f5da98fe32ff0d0c8cd4d44c25 Mon Sep 17 00:00:00 2001 From: Felix Kirchner Date: Wed, 19 Nov 2025 11:12:46 +0100 Subject: [PATCH 121/141] Removed false --- .gitea/workflows/pull_request.yaml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.gitea/workflows/pull_request.yaml b/.gitea/workflows/pull_request.yaml index 89bf9df..c4504a6 100644 --- a/.gitea/workflows/pull_request.yaml +++ b/.gitea/workflows/pull_request.yaml @@ -60,7 +60,7 @@ jobs: format: runs-on: ubuntu-latest - if: false # + # if: false # Needs bot user steps: - name: Checkout code uses: actions/checkout@v4 From 81cdeb7ed6a29edda6bb1069d35646f150ccdf8e Mon Sep 17 00:00:00 2001 From: Felix Kirchner Date: Wed, 19 Nov 2025 11:15:30 +0100 Subject: [PATCH 122/141] Skipped other runs for testing --- .gitea/workflows/pull_request.yaml | 7 ++++--- 1 file changed, 4 insertions(+), 3 deletions(-) diff --git a/.gitea/workflows/pull_request.yaml b/.gitea/workflows/pull_request.yaml index c4504a6..1c8e4d3 100644 --- a/.gitea/workflows/pull_request.yaml +++ b/.gitea/workflows/pull_request.yaml @@ -5,6 +5,7 @@ on: jobs: lint: + if: false runs-on: ubuntu-latest container: node:18-bullseye steps: @@ -32,8 +33,8 @@ jobs: run: flutter analyze lib test test: + if: false runs-on: ubuntu-latest - steps: - name: Checkout code uses: actions/checkout@v4 @@ -86,8 +87,8 @@ jobs: - name: Auto-format run: | - dart format lib test - dart fix --apply lib test + dart format lib + dart fix --apply lib - name: Commit Changes if: steps.check_changes.outputs.changes_detected == 'true' From 0659d202b3d90c01c0d3ebe4a58e46b34615a3ac Mon Sep 17 00:00:00 2001 From: Felix Kirchner Date: Wed, 19 Nov 2025 11:18:23 +0100 Subject: [PATCH 123/141] Remove if clause --- .gitea/workflows/pull_request.yaml | 1 - 1 file changed, 1 deletion(-) diff --git a/.gitea/workflows/pull_request.yaml b/.gitea/workflows/pull_request.yaml index 1c8e4d3..7f85a05 100644 --- a/.gitea/workflows/pull_request.yaml +++ b/.gitea/workflows/pull_request.yaml @@ -91,7 +91,6 @@ jobs: dart fix --apply lib - name: Commit Changes - if: steps.check_changes.outputs.changes_detected == 'true' run: | git add . git commit -m "Actions: Auto-formatting [skip ci]" From aade42c0a600a63ac75cbaa548649dcc163d88ce Mon Sep 17 00:00:00 2001 From: Felix Kirchner Date: Wed, 19 Nov 2025 11:21:43 +0100 Subject: [PATCH 124/141] Tried sth --- .gitea/workflows/pull_request.yaml | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) diff --git a/.gitea/workflows/pull_request.yaml b/.gitea/workflows/pull_request.yaml index 7f85a05..58f29e5 100644 --- a/.gitea/workflows/pull_request.yaml +++ b/.gitea/workflows/pull_request.yaml @@ -87,11 +87,13 @@ jobs: - name: Auto-format run: | - dart format lib + dart format lib dart fix --apply lib - name: Commit Changes run: | - git add . + git status + git add lib/ + git status git commit -m "Actions: Auto-formatting [skip ci]" git push From ca4bf03bab19910730ad3bbddffb51fe13596e4c Mon Sep 17 00:00:00 2001 From: Felix Kirchner Date: Wed, 19 Nov 2025 11:27:48 +0100 Subject: [PATCH 125/141] Finalized pull request workflow --- .gitea/workflows/pull_request.yaml | 44 +----------------------------- 1 file changed, 1 insertion(+), 43 deletions(-) diff --git a/.gitea/workflows/pull_request.yaml b/.gitea/workflows/pull_request.yaml index 58f29e5..43d36d2 100644 --- a/.gitea/workflows/pull_request.yaml +++ b/.gitea/workflows/pull_request.yaml @@ -5,9 +5,7 @@ on: jobs: lint: - if: false runs-on: ubuntu-latest - container: node:18-bullseye steps: - name: Checkout code uses: actions/checkout@v4 @@ -33,7 +31,6 @@ jobs: run: flutter analyze lib test test: - if: false runs-on: ubuntu-latest steps: - name: Checkout code @@ -57,43 +54,4 @@ jobs: run: flutter pub get - name: Run tests - run: flutter test - - 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 - - - name: Commit Changes - run: | - git status - git add lib/ - git status - git commit -m "Actions: Auto-formatting [skip ci]" - git push + run: flutter test \ No newline at end of file From 74fffa95e287cc0b2df5e778fb461fb81ebfd54c Mon Sep 17 00:00:00 2001 From: Felix Kirchner Date: Wed, 19 Nov 2025 11:28:00 +0100 Subject: [PATCH 126/141] Added push workflow (not active) --- .gitea/workflows/push.yaml | 48 ++++++++++++++++++++++++++++++++++++++ 1 file changed, 48 insertions(+) create mode 100644 .gitea/workflows/push.yaml diff --git a/.gitea/workflows/push.yaml b/.gitea/workflows/push.yaml new file mode 100644 index 0000000..7a6bb0b --- /dev/null +++ b/.gitea/workflows/push.yaml @@ -0,0 +1,48 @@ +name: Pull Request 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 status + git add lib/ + git status + git commit -m "Actions: Auto-formatting [skip ci]" + git push From 0ac8c2105260328c506cdd39ee18d0301124d1cd Mon Sep 17 00:00:00 2001 From: Felix Kirchner Date: Wed, 19 Nov 2025 11:32:22 +0100 Subject: [PATCH 127/141] Formatted files so that pipeline doesnt fail --- .../views/main_menu/game_history_view.dart | 22 ++++++++--------- .../widgets/double_row_info_tile.dart | 24 +++++++++---------- 2 files changed, 23 insertions(+), 23 deletions(-) diff --git a/lib/presentation/views/main_menu/game_history_view.dart b/lib/presentation/views/main_menu/game_history_view.dart index 3642a88..90cc50a 100644 --- a/lib/presentation/views/main_menu/game_history_view.dart +++ b/lib/presentation/views/main_menu/game_history_view.dart @@ -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,16 +178,16 @@ class _GameHistoryViewState extends State { Widget gameHistoryListView(allGameData, suggestedGameData) { if (suggestedGameData.isEmpty && allGameData.isEmpty) { - return TopCenteredMessage( + return const TopCenteredMessage( icon: Icons.info, - title: "Info", - message: "Keine Spiele erstellt", + title: 'Info', + message: 'Keine Spiele erstellt', ); } else if (suggestedGameData.isEmpty) { - return TopCenteredMessage( + return const TopCenteredMessage( icon: Icons.search, - title: "Info", - message: "Kein Spiel mit den Suchparametern gefunden.", + title: 'Info', + message: 'Kein Spiel mit den Suchparametern gefunden.', ); } return ListView.builder( @@ -195,9 +195,9 @@ Widget gameHistoryListView(allGameData, suggestedGameData) { 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/widgets/double_row_info_tile.dart b/lib/presentation/widgets/double_row_info_tile.dart index 621cc74..57404ff 100644 --- a/lib/presentation/widgets/double_row_info_tile.dart +++ b/lib/presentation/widgets/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, From c76e193b4d63396877e2a1af8b4a57e0f31bb9f6 Mon Sep 17 00:00:00 2001 From: mathiskirchner Date: Wed, 19 Nov 2025 15:02:32 +0100 Subject: [PATCH 128/141] created all objects in setup() funktion to avoid redundant withClock --- test/db_tests/game_test.dart | 51 +++++++++++------------- test/db_tests/group_test.dart | 71 ++++++++++++++++------------------ test/db_tests/player_test.dart | 49 +++++++++++------------ 3 files changed, 79 insertions(+), 92 deletions(-) diff --git a/test/db_tests/game_test.dart b/test/db_tests/game_test.dart index 0c86e45..d726425 100644 --- a/test/db_tests/game_test.dart +++ b/test/db_tests/game_test.dart @@ -51,41 +51,36 @@ void main() { group('game tests', () { test('game is added correctly', () async { - await withClock(fakeClock, () async { - await database.gameDao.addGame(game: testgame); + await database.gameDao.addGame(game: testgame); - final result = await database.gameDao.getGameById(gameId: testgame.id); + 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); + 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); + 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'); + 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); } - if (result.players != null) { - expect(result.players!.length, testgame.players!.length); + } 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'); + 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 { diff --git a/test/db_tests/group_test.dart b/test/db_tests/group_test.dart index 5730617..1241419 100644 --- a/test/db_tests/group_test.dart +++ b/test/db_tests/group_test.dart @@ -13,6 +13,7 @@ void main() { 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); @@ -34,6 +35,11 @@ void main() { name: 'Test Group', members: [player1, player2, player3], ); + testgroup2 = Group( + id: 'gr2', + name: 'Second Group', + members: [player2, player3, player4], + ); }); }); tearDown(() async { @@ -41,53 +47,42 @@ void main() { }); group('group tests', () { test('all groups get fetched correctly', () async { - await withClock(fakeClock, () async { - final testgroup2 = Group( - id: 'gr2', - name: 'Second Group', - members: [player2, player3, player4], - ); - await database.groupDao.addGroup(group: testgroup); - await database.groupDao.addGroup(group: testgroup2); + await database.groupDao.addGroup(group: testgroup); + await database.groupDao.addGroup(group: testgroup2); - final allGroups = await database.groupDao.getAllGroups(); - expect(allGroups.length, 2); + 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 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); - }); + 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 withClock(fakeClock, () async { - await database.groupDao.addGroup(group: testgroup); + await database.groupDao.addGroup(group: testgroup); - final result = await database.groupDao.getGroupById( - groupId: testgroup.id, - ); + 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.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); - } - }); + 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 { diff --git a/test/db_tests/player_test.dart b/test/db_tests/player_test.dart index ce75297..fa65f67 100644 --- a/test/db_tests/player_test.dart +++ b/test/db_tests/player_test.dart @@ -8,6 +8,7 @@ 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); @@ -22,6 +23,7 @@ void main() { withClock(fakeClock, () { testPlayer = Player(name: 'Test Player'); + testPlayer2 = Player(name: 'Second Group'); }); }); tearDown(() async { @@ -30,39 +32,34 @@ void main() { group('player tests', () { test('all players get fetched correctly', () async { - await withClock(fakeClock, () async { - final testPlayer2 = Player(name: 'Second Group'); - await database.playerDao.addPlayer(player: testPlayer); - await database.playerDao.addPlayer(player: testPlayer2); + await database.playerDao.addPlayer(player: testPlayer); + await database.playerDao.addPlayer(player: testPlayer2); - final allPlayers = await database.playerDao.getAllPlayers(); - expect(allPlayers.length, 2); + 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 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); - }); + 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 withClock(fakeClock, () async { - await database.playerDao.addPlayer(player: testPlayer); - final result = await database.playerDao.getPlayerById( - playerId: testPlayer.id, - ); + 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); - }); + expect(result.id, testPlayer.id); + expect(result.name, testPlayer.name); + expect(result.createdAt, testPlayer.createdAt); }); test('players get deleted correcly ', () async { From b82261317c87c14b0001c8f3fd457373bc5cbd4f Mon Sep 17 00:00:00 2001 From: mathiskirchner Date: Wed, 19 Nov 2025 15:09:40 +0100 Subject: [PATCH 129/141] move CreateGroupView to main_menu directory --- .../views/main_menu/{create_group => }/create_group_view.dart | 0 1 file changed, 0 insertions(+), 0 deletions(-) rename lib/presentation/views/main_menu/{create_group => }/create_group_view.dart (100%) diff --git a/lib/presentation/views/main_menu/create_group/create_group_view.dart b/lib/presentation/views/main_menu/create_group_view.dart similarity index 100% rename from lib/presentation/views/main_menu/create_group/create_group_view.dart rename to lib/presentation/views/main_menu/create_group_view.dart From 98b02adc85a8d8958596ff28fa93934d843970e2 Mon Sep 17 00:00:00 2001 From: Felix Kirchner Date: Wed, 19 Nov 2025 15:43:49 +0100 Subject: [PATCH 130/141] Formatted files so that pipeline doesnt fail --- .gitea/workflows/push.yaml | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/.gitea/workflows/push.yaml b/.gitea/workflows/push.yaml index 7a6bb0b..c5afb83 100644 --- a/.gitea/workflows/push.yaml +++ b/.gitea/workflows/push.yaml @@ -41,7 +41,9 @@ jobs: # Needs credentials, push access and the right files need to be staged - name: Commit Changes run: | - git status + 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]" From 3b6a91402290ca5b51bb19728d19c4c462d963a3 Mon Sep 17 00:00:00 2001 From: mathiskirchner Date: Wed, 19 Nov 2025 15:52:04 +0100 Subject: [PATCH 131/141] removed uneccessary withClock --- test/db_tests/group_test.dart | 48 ++++++++++++++++------------------- 1 file changed, 22 insertions(+), 26 deletions(-) diff --git a/test/db_tests/group_test.dart b/test/db_tests/group_test.dart index 1241419..a076ab0 100644 --- a/test/db_tests/group_test.dart +++ b/test/db_tests/group_test.dart @@ -116,39 +116,35 @@ void main() { }); test('Adding player to group works correctly', () async { - await withClock(fakeClock, () async { - await database.groupDao.addGroup(group: testgroup); + await database.groupDao.addGroup(group: testgroup); - await database.playerGroupDao.addPlayerToGroup( - player: player4, - groupId: testgroup.id, - ); + await database.playerGroupDao.addPlayerToGroup( + player: player4, + groupId: testgroup.id, + ); - final playerAdded = await database.playerGroupDao.isPlayerInGroup( - playerId: player4.id, - groupId: testgroup.id, - ); + final playerAdded = await database.playerGroupDao.isPlayerInGroup( + playerId: player4.id, + groupId: testgroup.id, + ); - expect(playerAdded, true); + expect(playerAdded, true); - final playerNotAdded = !await database.playerGroupDao.isPlayerInGroup( - playerId: '', - groupId: testgroup.id, - ); + final playerNotAdded = !await database.playerGroupDao.isPlayerInGroup( + playerId: '', + groupId: testgroup.id, + ); - expect(playerNotAdded, true); + expect(playerNotAdded, true); - final result = await database.groupDao.getGroupById( - groupId: testgroup.id, - ); - expect(result.members.length, testgroup.members.length + 1); + 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); - }); + 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 { From 54e1756e79326324205acba4874fd0e12b14e88a Mon Sep 17 00:00:00 2001 From: mathiskirchner Date: Wed, 19 Nov 2025 16:39:05 +0100 Subject: [PATCH 132/141] moved create_group_view from subfolder to root --- lib/presentation/views/main_menu/groups_view.dart | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/lib/presentation/views/main_menu/groups_view.dart b/lib/presentation/views/main_menu/groups_view.dart index 7e6f59d..f74d20c 100644 --- a/lib/presentation/views/main_menu/groups_view.dart +++ b/lib/presentation/views/main_menu/groups_view.dart @@ -3,7 +3,7 @@ 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/create_group_view.dart'; +import 'package:game_tracker/presentation/views/main_menu/create_group_view.dart'; import 'package:game_tracker/presentation/widgets/custom_width_button.dart'; import 'package:game_tracker/presentation/widgets/tiles/group_tile.dart'; import 'package:game_tracker/presentation/widgets/top_centered_message.dart'; From 9365313c9215a5ad77f2a16b8c2c05f7dad03ad9 Mon Sep 17 00:00:00 2001 From: mathiskirchner Date: Wed, 19 Nov 2025 16:39:32 +0100 Subject: [PATCH 133/141] button not working --- .../views/main_menu/create_group_view.dart | 7 ++- .../widgets/custom_width_button.dart | 46 ++++++++++++++----- 2 files changed, 37 insertions(+), 16 deletions(-) diff --git a/lib/presentation/views/main_menu/create_group_view.dart b/lib/presentation/views/main_menu/create_group_view.dart index 81d5e36..f43fc8d 100644 --- a/lib/presentation/views/main_menu/create_group_view.dart +++ b/lib/presentation/views/main_menu/create_group_view.dart @@ -1,4 +1,4 @@ -import 'package:flutter/material.dart'; +import 'package:flutter/material.dart' hide ButtonStyle; import 'package:game_tracker/core/custom_theme.dart'; import 'package:game_tracker/data/db/database.dart'; import 'package:game_tracker/data/dto/group.dart'; @@ -265,8 +265,8 @@ class _CreateGroupViewState extends State { ), CustomWidthButton( text: 'Create group', - disabledInfillColor: CustomTheme.boxColor, sizeRelativeToWidth: 0.95, + buttonStyle: ButtonStyle.secondary, onPressed: (_groupNameController.text.isEmpty || selectedPlayers.isEmpty) ? null @@ -277,14 +277,13 @@ class _CreateGroupViewState extends State { members: selectedPlayers, ), ); + if (!context.mounted) return; if (success) { _groupNameController.clear(); _searchBarController.clear(); selectedPlayers.clear(); - if (!mounted) return; Navigator.pop(context); } else { - if (!mounted) return; ScaffoldMessenger.of(context).showSnackBar( SnackBar( backgroundColor: CustomTheme.boxColor, diff --git a/lib/presentation/widgets/custom_width_button.dart b/lib/presentation/widgets/custom_width_button.dart index b0b9bd3..2a79d1b 100644 --- a/lib/presentation/widgets/custom_width_button.dart +++ b/lib/presentation/widgets/custom_width_button.dart @@ -7,45 +7,67 @@ class CustomWidthButton extends StatelessWidget { const CustomWidthButton({ super.key, required this.text, - this.disabledInfillColor, this.buttonStyle = ButtonStyle.primary, required this.sizeRelativeToWidth, - required this.onPressed, + this.onPressed, }); final String text; - final Color? disabledInfillColor; final double sizeRelativeToWidth; final VoidCallback? onPressed; final ButtonStyle buttonStyle; @override Widget build(BuildContext context) { + + final Color buttonBackgroundColor; + final Color disabledBackgroundColor; + final Color borderSideColor; + final Color disabledBorderSideColor; + final Color textcolor; + final Color disabledTextColor; + + + if(buttonStyle == ButtonStyle.primary){ + buttonBackgroundColor = CustomTheme.primaryColor; + disabledBackgroundColor = CustomTheme.primaryColor.withValues(alpha: 0.24); + borderSideColor = Colors.transparent; + disabledBorderSideColor = Colors.transparent; + textcolor = Colors.white; + disabledTextColor = Colors.white.withValues(alpha: 0.24); + } else{ + buttonBackgroundColor = Colors.transparent; + disabledBackgroundColor = Colors.transparent; + borderSideColor = CustomTheme.primaryColor.withValues(alpha: 0.6 ); + disabledBorderSideColor = Colors.transparent; + textcolor = CustomTheme.primaryColor; + disabledTextColor = CustomTheme.primaryColor.withValues(alpha: 0.24); + } + + return ElevatedButton( onPressed: onPressed, style: ElevatedButton.styleFrom( - disabledBackgroundColor: disabledInfillColor, + disabledBackgroundColor: disabledBackgroundColor, minimumSize: Size( MediaQuery.sizeOf(context).width * sizeRelativeToWidth, 60, ), - backgroundColor: buttonStyle == ButtonStyle.primary - ? CustomTheme.primaryColor - : CustomTheme.secondaryColor, + backgroundColor: buttonBackgroundColor, side: BorderSide( - color: buttonStyle == ButtonStyle.primary - ? CustomTheme.primaryColor - : CustomTheme.secondaryColor, + color: borderSideColor, width: 2, ), shape: RoundedRectangleBorder(borderRadius: BorderRadius.circular(12)), ), child: Text( text, - style: const TextStyle( + style: TextStyle( fontWeight: FontWeight.w500, fontSize: 22, - color: Colors.white, + color: (onPressed == null) + ? disabledTextColor + : textcolor, ), ), ); From 201fd70685c2d7040db9c9d0533254db2bef0dd6 Mon Sep 17 00:00:00 2001 From: mathiskirchner Date: Wed, 19 Nov 2025 16:44:46 +0100 Subject: [PATCH 134/141] Update `TextIconListTile` padding and replace `IconButton` with `GestureDetector` --- lib/presentation/widgets/tiles/text_icon_list_tile.dart | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/lib/presentation/widgets/tiles/text_icon_list_tile.dart b/lib/presentation/widgets/tiles/text_icon_list_tile.dart index 92d0251..1907928 100644 --- a/lib/presentation/widgets/tiles/text_icon_list_tile.dart +++ b/lib/presentation/widgets/tiles/text_icon_list_tile.dart @@ -17,7 +17,7 @@ class TextIconListTile extends StatelessWidget { Widget build(BuildContext context) { return Container( margin: const EdgeInsets.symmetric(horizontal: 5, vertical: 5), - padding: const EdgeInsets.symmetric(horizontal: 10), + padding: const EdgeInsets.symmetric(horizontal: 15), decoration: BoxDecoration( color: CustomTheme.boxColor, border: Border.all(color: CustomTheme.boxBorder), @@ -41,9 +41,9 @@ class TextIconListTile extends StatelessWidget { ), ), if (iconEnabled) - IconButton( - icon: const Icon(Icons.add, size: 20), - onPressed: onPressed, + GestureDetector( + child: const Icon(Icons.add, size: 20), + onTap: onPressed, ), ], ), From 018332d8e603cabe5ab6ee6e46770fd1e16a595c Mon Sep 17 00:00:00 2001 From: mathiskirchner Date: Wed, 19 Nov 2025 16:48:43 +0100 Subject: [PATCH 135/141] Refactor widget directory structure by organizing tiles and buttons - Move `GameTile` and `DoubleRowInfoTile` to `presentation/widgets/tiles/` - Move `CustomWidthButton` and `QuickCreateButton` to `presentation/widgets/buttons/` - Update import paths in `HomeView`, `GroupsView`, `GameHistoryView`, and `CreateGroupView` --- lib/presentation/views/main_menu/create_group_view.dart | 2 +- lib/presentation/views/main_menu/game_history_view.dart | 2 +- lib/presentation/views/main_menu/groups_view.dart | 2 +- lib/presentation/views/main_menu/home_view.dart | 4 ++-- .../widgets/{ => buttons}/custom_width_button.dart | 0 .../widgets/{ => buttons}/quick_create_button.dart | 0 .../widgets/{ => tiles}/double_row_info_tile.dart | 0 lib/presentation/widgets/{ => tiles}/game_tile.dart | 0 8 files changed, 5 insertions(+), 5 deletions(-) rename lib/presentation/widgets/{ => buttons}/custom_width_button.dart (100%) rename lib/presentation/widgets/{ => buttons}/quick_create_button.dart (100%) rename lib/presentation/widgets/{ => tiles}/double_row_info_tile.dart (100%) rename lib/presentation/widgets/{ => tiles}/game_tile.dart (100%) diff --git a/lib/presentation/views/main_menu/create_group_view.dart b/lib/presentation/views/main_menu/create_group_view.dart index f43fc8d..365cf27 100644 --- a/lib/presentation/views/main_menu/create_group_view.dart +++ b/lib/presentation/views/main_menu/create_group_view.dart @@ -3,8 +3,8 @@ 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/widgets/buttons/custom_width_button.dart'; import 'package:game_tracker/presentation/widgets/custom_search_bar.dart'; -import 'package:game_tracker/presentation/widgets/custom_width_button.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'; diff --git a/lib/presentation/views/main_menu/game_history_view.dart b/lib/presentation/views/main_menu/game_history_view.dart index 3642a88..7c19bbf 100644 --- a/lib/presentation/views/main_menu/game_history_view.dart +++ b/lib/presentation/views/main_menu/game_history_view.dart @@ -1,6 +1,6 @@ import 'package:flutter/material.dart'; import 'package:game_tracker/core/custom_theme.dart'; -import 'package:game_tracker/presentation/widgets/double_row_info_tile.dart'; +import 'package:game_tracker/presentation/widgets/tiles/double_row_info_tile.dart'; import 'package:game_tracker/presentation/widgets/top_centered_message.dart'; class GameHistoryView extends StatefulWidget { diff --git a/lib/presentation/views/main_menu/groups_view.dart b/lib/presentation/views/main_menu/groups_view.dart index f74d20c..c45cf21 100644 --- a/lib/presentation/views/main_menu/groups_view.dart +++ b/lib/presentation/views/main_menu/groups_view.dart @@ -4,7 +4,7 @@ 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/custom_width_button.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'; diff --git a/lib/presentation/views/main_menu/home_view.dart b/lib/presentation/views/main_menu/home_view.dart index cf6288a..34e4be3 100644 --- a/lib/presentation/views/main_menu/home_view.dart +++ b/lib/presentation/views/main_menu/home_view.dart @@ -1,7 +1,7 @@ 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'; diff --git a/lib/presentation/widgets/custom_width_button.dart b/lib/presentation/widgets/buttons/custom_width_button.dart similarity index 100% rename from lib/presentation/widgets/custom_width_button.dart rename to lib/presentation/widgets/buttons/custom_width_button.dart 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/double_row_info_tile.dart b/lib/presentation/widgets/tiles/double_row_info_tile.dart similarity index 100% rename from lib/presentation/widgets/double_row_info_tile.dart rename to lib/presentation/widgets/tiles/double_row_info_tile.dart diff --git a/lib/presentation/widgets/game_tile.dart b/lib/presentation/widgets/tiles/game_tile.dart similarity index 100% rename from lib/presentation/widgets/game_tile.dart rename to lib/presentation/widgets/tiles/game_tile.dart From 1232cb8f0dc259c4c4105030fe25255c14683a06 Mon Sep 17 00:00:00 2001 From: mathiskirchner Date: Wed, 19 Nov 2025 16:50:02 +0100 Subject: [PATCH 136/141] Fix `GestureDetector` child ordering in `TextIconListTile` --- lib/presentation/widgets/tiles/text_icon_list_tile.dart | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/lib/presentation/widgets/tiles/text_icon_list_tile.dart b/lib/presentation/widgets/tiles/text_icon_list_tile.dart index 1907928..c0fe673 100644 --- a/lib/presentation/widgets/tiles/text_icon_list_tile.dart +++ b/lib/presentation/widgets/tiles/text_icon_list_tile.dart @@ -42,8 +42,8 @@ class TextIconListTile extends StatelessWidget { ), if (iconEnabled) GestureDetector( - child: const Icon(Icons.add, size: 20), onTap: onPressed, + child: const Icon(Icons.add, size: 20), ), ], ), From 3f79a7b89826b60fd33712cb016418507da1b292 Mon Sep 17 00:00:00 2001 From: Felix Kirchner Date: Wed, 19 Nov 2025 18:26:51 +0100 Subject: [PATCH 137/141] sourcing enums out to enums.dart --- lib/core/enums.dart | 2 ++ lib/presentation/views/main_menu/create_group_view.dart | 3 ++- 2 files changed, 4 insertions(+), 1 deletion(-) create mode 100644 lib/core/enums.dart 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/presentation/views/main_menu/create_group_view.dart b/lib/presentation/views/main_menu/create_group_view.dart index 365cf27..db8890f 100644 --- a/lib/presentation/views/main_menu/create_group_view.dart +++ b/lib/presentation/views/main_menu/create_group_view.dart @@ -1,5 +1,6 @@ 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'; @@ -266,7 +267,7 @@ class _CreateGroupViewState extends State { CustomWidthButton( text: 'Create group', sizeRelativeToWidth: 0.95, - buttonStyle: ButtonStyle.secondary, + buttonType: ButtonType.primary, onPressed: (_groupNameController.text.isEmpty || selectedPlayers.isEmpty) ? null From e71e65b197f1fa05bb82d977d8012e5a92dd73f2 Mon Sep 17 00:00:00 2001 From: Felix Kirchner Date: Wed, 19 Nov 2025 18:27:27 +0100 Subject: [PATCH 138/141] Corrected button color behaviour and added tertiary button --- .../widgets/buttons/custom_width_button.dart | 127 ++++++++++++------ 1 file changed, 83 insertions(+), 44 deletions(-) diff --git a/lib/presentation/widgets/buttons/custom_width_button.dart b/lib/presentation/widgets/buttons/custom_width_button.dart index 2a79d1b..bce78ed 100644 --- a/lib/presentation/widgets/buttons/custom_width_button.dart +++ b/lib/presentation/widgets/buttons/custom_width_button.dart @@ -1,13 +1,12 @@ import 'package:flutter/material.dart'; import 'package:game_tracker/core/custom_theme.dart'; - -enum ButtonStyle { primary, secondary } +import 'package:game_tracker/core/enums.dart'; class CustomWidthButton extends StatelessWidget { const CustomWidthButton({ super.key, required this.text, - this.buttonStyle = ButtonStyle.primary, + this.buttonType = ButtonType.primary, required this.sizeRelativeToWidth, this.onPressed, }); @@ -15,61 +14,101 @@ class CustomWidthButton extends StatelessWidget { final String text; final double sizeRelativeToWidth; final VoidCallback? onPressed; - final ButtonStyle buttonStyle; + final ButtonType buttonType; @override Widget build(BuildContext context) { - final Color buttonBackgroundColor; final Color disabledBackgroundColor; final Color borderSideColor; - final Color disabledBorderSideColor; final Color textcolor; final Color disabledTextColor; - - if(buttonStyle == ButtonStyle.primary){ - buttonBackgroundColor = CustomTheme.primaryColor; - disabledBackgroundColor = CustomTheme.primaryColor.withValues(alpha: 0.24); - borderSideColor = Colors.transparent; - disabledBorderSideColor = Colors.transparent; + if (buttonType == ButtonType.primary) { textcolor = Colors.white; disabledTextColor = Colors.white.withValues(alpha: 0.24); - } else{ + buttonBackgroundColor = CustomTheme.primaryColor; + disabledBackgroundColor = CustomTheme.primaryColor.withValues( + alpha: 0.24, + ); + + 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 = CustomTheme.primaryColor.withValues(alpha: 0.5); buttonBackgroundColor = Colors.transparent; disabledBackgroundColor = Colors.transparent; - borderSideColor = CustomTheme.primaryColor.withValues(alpha: 0.6 ); - disabledBorderSideColor = Colors.transparent; + borderSideColor = onPressed != null + ? CustomTheme.primaryColor + : CustomTheme.primaryColor.withValues(alpha: 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 = CustomTheme.primaryColor.withValues(alpha: 0.24); + disabledTextColor = CustomTheme.primaryColor.withValues(alpha: 0.3); + 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), + ), + ); } - - - return ElevatedButton( - onPressed: onPressed, - style: ElevatedButton.styleFrom( - disabledBackgroundColor: disabledBackgroundColor, - minimumSize: Size( - MediaQuery.sizeOf(context).width * sizeRelativeToWidth, - 60, - ), - backgroundColor: buttonBackgroundColor, - side: BorderSide( - color: borderSideColor, - width: 2, - ), - shape: RoundedRectangleBorder(borderRadius: BorderRadius.circular(12)), - ), - child: Text( - text, - style: TextStyle( - fontWeight: FontWeight.w500, - fontSize: 22, - color: (onPressed == null) - ? disabledTextColor - : textcolor, - ), - ), - ); } } From 248d652e0641cba2a45447a486b97b6b52c5a175 Mon Sep 17 00:00:00 2001 From: Felix Kirchner Date: Wed, 19 Nov 2025 18:32:25 +0100 Subject: [PATCH 139/141] Made onPressed not required --- lib/presentation/widgets/tiles/text_icon_list_tile.dart | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/lib/presentation/widgets/tiles/text_icon_list_tile.dart b/lib/presentation/widgets/tiles/text_icon_list_tile.dart index c0fe673..5e272c9 100644 --- a/lib/presentation/widgets/tiles/text_icon_list_tile.dart +++ b/lib/presentation/widgets/tiles/text_icon_list_tile.dart @@ -3,13 +3,13 @@ import 'package:game_tracker/core/custom_theme.dart'; class TextIconListTile extends StatelessWidget { final String text; - final VoidCallback onPressed; + final VoidCallback? onPressed; final bool iconEnabled; const TextIconListTile({ super.key, required this.text, - required this.onPressed, + this.onPressed, this.iconEnabled = true, }); From 8e2befaf3da1a7199d2e388705e60f75fa4c7024 Mon Sep 17 00:00:00 2001 From: Felix Kirchner Date: Wed, 19 Nov 2025 19:19:04 +0100 Subject: [PATCH 140/141] Fixed button color problem --- .../widgets/buttons/custom_width_button.dart | 20 ++++++++++++------- 1 file changed, 13 insertions(+), 7 deletions(-) diff --git a/lib/presentation/widgets/buttons/custom_width_button.dart b/lib/presentation/widgets/buttons/custom_width_button.dart index bce78ed..17c9dc5 100644 --- a/lib/presentation/widgets/buttons/custom_width_button.dart +++ b/lib/presentation/widgets/buttons/custom_width_button.dart @@ -26,11 +26,13 @@ class CustomWidthButton extends StatelessWidget { if (buttonType == ButtonType.primary) { textcolor = Colors.white; - disabledTextColor = Colors.white.withValues(alpha: 0.24); + disabledTextColor = Color.lerp(textcolor, Colors.black, 0.5)!; buttonBackgroundColor = CustomTheme.primaryColor; - disabledBackgroundColor = CustomTheme.primaryColor.withValues( - alpha: 0.24, - ); + disabledBackgroundColor = Color.lerp( + buttonBackgroundColor, + Colors.black, + 0.5, + )!; return ElevatedButton( onPressed: onPressed, @@ -55,12 +57,12 @@ class CustomWidthButton extends StatelessWidget { ); } else if (buttonType == ButtonType.secondary) { textcolor = CustomTheme.primaryColor; - disabledTextColor = CustomTheme.primaryColor.withValues(alpha: 0.5); + disabledTextColor = Color.lerp(textcolor, Colors.black, 0.5)!; buttonBackgroundColor = Colors.transparent; disabledBackgroundColor = Colors.transparent; borderSideColor = onPressed != null ? CustomTheme.primaryColor - : CustomTheme.primaryColor.withValues(alpha: 0.5); + : Color.lerp(CustomTheme.primaryColor, Colors.black, 0.5)!; return OutlinedButton( onPressed: onPressed, @@ -86,7 +88,11 @@ class CustomWidthButton extends StatelessWidget { ); } else { textcolor = CustomTheme.primaryColor; - disabledTextColor = CustomTheme.primaryColor.withValues(alpha: 0.3); + disabledTextColor = Color.lerp( + CustomTheme.primaryColor, + Colors.black, + 0.5, + )!; buttonBackgroundColor = Colors.transparent; disabledBackgroundColor = Colors.transparent; From b684ebd4f66b54ee378ffdf58a365b3fc30953b2 Mon Sep 17 00:00:00 2001 From: Felix Kirchner Date: Wed, 19 Nov 2025 20:25:37 +0100 Subject: [PATCH 141/141] Renamed workflow according to file name --- .gitea/workflows/push.yaml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.gitea/workflows/push.yaml b/.gitea/workflows/push.yaml index c5afb83..700e96b 100644 --- a/.gitea/workflows/push.yaml +++ b/.gitea/workflows/push.yaml @@ -1,4 +1,4 @@ -name: Pull Request Pipeline +name: Push Pipeline on: push: