fix: updating team score in detail view
Some checks failed
Pull Request Pipeline / lint (pull_request) Successful in 55s
Pull Request Pipeline / test (pull_request) Failing after 10m49s

This commit is contained in:
2026-05-18 00:48:29 +02:00
parent 0a1e14a32d
commit 9bce03d780
5 changed files with 80 additions and 49 deletions

View File

@@ -124,6 +124,24 @@ class TeamDao extends DatabaseAccessor<AppDatabase> with _$TeamDaoMixin {
); );
} }
Future<List<Team>> getTeamsByMatchId({required String matchId}) async {
final playerMatchQuery = select(db.playerMatchTable)
..where((pm) => pm.matchId.equals(matchId));
final playerMatches = await playerMatchQuery.get();
if (playerMatches.isEmpty) return [];
final teamIds = playerMatches
.map((pm) => pm.teamId)
.whereType<String>()
.toSet();
final teams = await Future.wait(
teamIds.map((id) => getTeamById(teamId: id)),
);
return teams;
}
/// Retrieves a [Team] by its [teamId], including its members. /// Retrieves a [Team] by its [teamId], including its members.
Future<Team> getTeamById({required String teamId}) async { Future<Team> getTeamById({required String teamId}) async {
final query = select(teamTable)..where((t) => t.id.equals(teamId)); final query = select(teamTable)..where((t) => t.id.equals(teamId));

View File

@@ -19,7 +19,7 @@ class Match {
final bool isTeamMatch; final bool isTeamMatch;
final List<Team>? teams; final List<Team>? teams;
final String notes; final String notes;
Map<String, ScoreEntry?> scores; final Map<String, ScoreEntry?> scores;
Match({ Match({
required this.name, required this.name,

View File

@@ -8,6 +8,8 @@ import 'package:tallee/core/custom_theme.dart';
import 'package:tallee/core/enums.dart'; import 'package:tallee/core/enums.dart';
import 'package:tallee/data/db/database.dart'; import 'package:tallee/data/db/database.dart';
import 'package:tallee/data/models/match.dart'; import 'package:tallee/data/models/match.dart';
import 'package:tallee/data/models/score_entry.dart';
import 'package:tallee/data/models/team.dart';
import 'package:tallee/l10n/generated/app_localizations.dart'; import 'package:tallee/l10n/generated/app_localizations.dart';
import 'package:tallee/presentation/views/main_menu/match_view/create_match/create_match_view.dart'; import 'package:tallee/presentation/views/main_menu/match_view/create_match/create_match_view.dart';
import 'package:tallee/presentation/views/main_menu/match_view/match_result_view.dart'; import 'package:tallee/presentation/views/main_menu/match_view/match_result_view.dart';
@@ -43,13 +45,19 @@ class MatchDetailView extends StatefulWidget {
class _MatchDetailViewState extends State<MatchDetailView> { class _MatchDetailViewState extends State<MatchDetailView> {
late final AppDatabase db; late final AppDatabase db;
late Match match; late Match localMatch;
late List<Team> localTeams;
late Map<String, ScoreEntry?> localScores;
@override @override
void initState() { void initState() {
super.initState(); super.initState();
db = Provider.of<AppDatabase>(context, listen: false); db = Provider.of<AppDatabase>(context, listen: false);
match = widget.match; localMatch = widget.match;
localScores = localMatch.scores;
localTeams = localMatch.teams ?? [];
} }
@override @override
@@ -83,7 +91,7 @@ class _MatchDetailViewState extends State<MatchDetailView> {
), ),
).then((confirmed) async { ).then((confirmed) async {
if (confirmed! && context.mounted) { if (confirmed! && context.mounted) {
await db.matchDao.deleteMatch(matchId: match.id); await db.matchDao.deleteMatch(matchId: localMatch.id);
if (!context.mounted) return; if (!context.mounted) return;
Navigator.pop(context); Navigator.pop(context);
widget.onMatchUpdate.call(); widget.onMatchUpdate.call();
@@ -117,7 +125,7 @@ class _MatchDetailViewState extends State<MatchDetailView> {
// Match Name // Match Name
Text( Text(
match.name, localMatch.name,
style: const TextStyle( style: const TextStyle(
fontSize: 28, fontSize: 28,
fontWeight: FontWeight.bold, fontWeight: FontWeight.bold,
@@ -129,7 +137,7 @@ class _MatchDetailViewState extends State<MatchDetailView> {
// Creation Date // Creation Date
Text( Text(
'${loc.created_on} ${DateFormat.yMMMd(Localizations.localeOf(context).toString()).format(match.createdAt)}', '${loc.created_on} ${DateFormat.yMMMd(Localizations.localeOf(context).toString()).format(localMatch.createdAt)}',
style: const TextStyle( style: const TextStyle(
fontSize: 12, fontSize: 12,
color: CustomTheme.textColor, color: CustomTheme.textColor,
@@ -139,14 +147,14 @@ class _MatchDetailViewState extends State<MatchDetailView> {
const SizedBox(height: 10), const SizedBox(height: 10),
// Group Name // Group Name
if (match.group != null) ...[ if (localMatch.group != null) ...[
Row( Row(
mainAxisAlignment: MainAxisAlignment.center, mainAxisAlignment: MainAxisAlignment.center,
children: [ children: [
const Icon(Icons.group), const Icon(Icons.group),
const SizedBox(width: 8), const SizedBox(width: 8),
Text( Text(
'${match.group!.name}${getExtraPlayerCount(match)}', '${localMatch.group!.name}${getExtraPlayerCount(localMatch)}',
style: const TextStyle(fontWeight: FontWeight.bold), style: const TextStyle(fontWeight: FontWeight.bold),
), ),
], ],
@@ -155,7 +163,7 @@ class _MatchDetailViewState extends State<MatchDetailView> {
], ],
// Teams or Players // Teams or Players
if (match.isTeamMatch) ...[ if (localMatch.isTeamMatch) ...[
// Teams // Teams
InfoTile( InfoTile(
title: loc.teams, title: loc.teams,
@@ -166,7 +174,7 @@ class _MatchDetailViewState extends State<MatchDetailView> {
crossAxisAlignment: WrapCrossAlignment.start, crossAxisAlignment: WrapCrossAlignment.start,
spacing: 12, spacing: 12,
runSpacing: 8, runSpacing: 8,
children: match.teams!.map((team) { children: localMatch.teams!.map((team) {
return TeamCard(team: team); return TeamCard(team: team);
}).toList(), }).toList(),
), ),
@@ -182,7 +190,7 @@ class _MatchDetailViewState extends State<MatchDetailView> {
crossAxisAlignment: WrapCrossAlignment.start, crossAxisAlignment: WrapCrossAlignment.start,
spacing: 12, spacing: 12,
runSpacing: 8, runSpacing: 8,
children: match.players.map((player) { children: localMatch.players.map((player) {
return TextIconTile( return TextIconTile(
text: player.name, text: player.name,
suffixText: getNameCountText(player), suffixText: getNameCountText(player),
@@ -205,12 +213,12 @@ class _MatchDetailViewState extends State<MatchDetailView> {
horizontal: 8, horizontal: 8,
), ),
child: GameLabel( child: GameLabel(
title: match.game.name, title: localMatch.game.name,
description: translateRulesetToString( description: translateRulesetToString(
match.game.ruleset, localMatch.game.ruleset,
context, context,
), ),
color: match.game.color, color: localMatch.game.color,
), ),
), ),
), ),
@@ -241,7 +249,7 @@ class _MatchDetailViewState extends State<MatchDetailView> {
adaptivePageRoute( adaptivePageRoute(
fullscreenDialog: true, fullscreenDialog: true,
builder: (context) => CreateMatchView( builder: (context) => CreateMatchView(
matchToEdit: match, matchToEdit: localMatch,
onMatchUpdated: onMatchUpdated, onMatchUpdated: onMatchUpdated,
), ),
), ),
@@ -257,12 +265,10 @@ class _MatchDetailViewState extends State<MatchDetailView> {
adaptivePageRoute( adaptivePageRoute(
fullscreenDialog: true, fullscreenDialog: true,
builder: (context) => MatchResultView( builder: (context) => MatchResultView(
match: match, match: localMatch,
onWinnerChanged: () { onWinnerChanged: () async {
widget.onMatchUpdate.call(); widget.onMatchUpdate.call();
setState(() { await updateScoresForCurrentMatch();
updateScoresForCurrentMatch();
});
}, },
), ),
), ),
@@ -282,7 +288,7 @@ class _MatchDetailViewState extends State<MatchDetailView> {
/// updates the match in this view /// updates the match in this view
void onMatchUpdated(Match editedMatch) { void onMatchUpdated(Match editedMatch) {
setState(() { setState(() {
match = editedMatch; localMatch = editedMatch;
}); });
widget.onMatchUpdate.call(); widget.onMatchUpdate.call();
} }
@@ -302,13 +308,13 @@ class _MatchDetailViewState extends State<MatchDetailView> {
/// Returns the result row for single winner/loser rulesets or a placeholder /// Returns the result row for single winner/loser rulesets or a placeholder
/// if no result is entered yet /// if no result is entered yet
List<Widget> getSingleResultRow(AppLocalizations loc) { List<Widget> getSingleResultRow(AppLocalizations loc) {
final ruleset = match.game.ruleset; final ruleset = localMatch.game.ruleset;
if (match.mvp.isNotEmpty || match.mvt.isNotEmpty) { if (localMatch.mvp.isNotEmpty || localMatch.mvt.isNotEmpty) {
// Single Winner / Loser // Single Winner / Loser
final mvpName = match.isTeamMatch final mvpName = localMatch.isTeamMatch
? match.mvt.first.name ? localMatch.mvt.first.name
: match.mvp.first.name; : localMatch.mvp.first.name;
return [ return [
Text( Text(
@@ -361,41 +367,41 @@ class _MatchDetailViewState extends State<MatchDetailView> {
/// Returns a list of player/team names and their corresponding scores, sorted by score according to the ruleset /// Returns a list of player/team names and their corresponding scores, sorted by score according to the ruleset
List<(String, int)> getSortedScores() { List<(String, int)> getSortedScores() {
List<(String, int)> scores = []; List<(String, int)> namedScores = [];
if (match.isTeamMatch) { if (localMatch.isTeamMatch) {
for (var team in match.teams!) { for (var team in localTeams) {
int score = team.score ?? 0; int score = team.score ?? 0;
scores.add((team.name, score)); namedScores.add((team.name, score));
} }
final ruleset = match.game.ruleset; final ruleset = localMatch.game.ruleset;
if (ruleset == Ruleset.highestScore || ruleset == Ruleset.placement) { if (ruleset == Ruleset.highestScore || ruleset == Ruleset.placement) {
scores.sort((a, b) => b.$2.compareTo(a.$2)); namedScores.sort((a, b) => b.$2.compareTo(a.$2));
} else if (ruleset == Ruleset.lowestScore) { } else if (ruleset == Ruleset.lowestScore) {
scores.sort((a, b) => a.$2.compareTo(b.$2)); namedScores.sort((a, b) => a.$2.compareTo(b.$2));
} }
} else { } else {
for (var player in match.players) { for (var player in localMatch.players) {
int score = match.scores[player.id]?.score ?? 0; int score = localScores[player.id]?.score ?? 0;
scores.add((player.name, score)); namedScores.add((player.name, score));
} }
final ruleset = match.game.ruleset; final ruleset = localMatch.game.ruleset;
if (ruleset == Ruleset.highestScore || ruleset == Ruleset.placement) { if (ruleset == Ruleset.highestScore || ruleset == Ruleset.placement) {
scores.sort((a, b) => b.$2.compareTo(a.$2)); namedScores.sort((a, b) => b.$2.compareTo(a.$2));
} else if (ruleset == Ruleset.lowestScore) { } else if (ruleset == Ruleset.lowestScore) {
scores.sort((a, b) => a.$2.compareTo(b.$2)); namedScores.sort((a, b) => a.$2.compareTo(b.$2));
} }
} }
return scores; return namedScores;
} }
/// Returns the text widget for the score or placement value, styled according to the ruleset /// Returns the text widget for the score or placement value, styled according to the ruleset
Widget getResultValueText(AppLocalizations loc, int index, int score) { Widget getResultValueText(AppLocalizations loc, int index, int score) {
final ruleset = match.game.ruleset; final ruleset = localMatch.game.ruleset;
if (ruleset == Ruleset.placement) { if (ruleset == Ruleset.placement) {
return Text( return Text(
@@ -433,8 +439,8 @@ class _MatchDetailViewState extends State<MatchDetailView> {
// Returns if the result can be displayed in a single row // Returns if the result can be displayed in a single row
bool isSingleRowResult() { bool isSingleRowResult() {
return match.game.ruleset == Ruleset.singleWinner || return localMatch.game.ruleset == Ruleset.singleWinner ||
match.game.ruleset == Ruleset.singleLoser; localMatch.game.ruleset == Ruleset.singleLoser;
} }
String getPlacementText(BuildContext context, int rank) { String getPlacementText(BuildContext context, int rank) {
@@ -465,9 +471,16 @@ class _MatchDetailViewState extends State<MatchDetailView> {
} }
} }
void updateScoresForCurrentMatch() { // Die Methode selbst:
db.scoreEntryDao Future<void> updateScoresForCurrentMatch() async {
.getAllMatchScores(matchId: match.id) if (widget.match.isTeamMatch) {
.then((scores) => match.scores = scores); final teams = await db.teamDao.getTeamsByMatchId(matchId: localMatch.id);
if (mounted) setState(() => localTeams = teams);
} else {
final scores = await db.scoreEntryDao.getAllMatchScores(
matchId: localMatch.id,
);
if (mounted) setState(() => localScores = scores);
}
} }
} }

View File

@@ -186,7 +186,7 @@ class _MatchResultViewState extends State<MatchResultView> {
); );
await _handleSaving(); await _handleSaving();
if (!context.mounted) return; if (!context.mounted) return;
Navigator.of(context).pop(_selectedPlayer); Navigator.pop(context);
} }
: null, : null,
), ),

View File

@@ -1,7 +1,7 @@
name: tallee name: tallee
description: "Tracking App for Card Games" description: "Tracking App for Card Games"
publish_to: 'none' publish_to: 'none'
version: 0.0.30+299 version: 0.0.30+304
environment: environment:
sdk: ^3.8.1 sdk: ^3.8.1