fix: updating team score in detail view
This commit is contained in:
@@ -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));
|
||||||
|
|||||||
@@ -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,
|
||||||
|
|||||||
@@ -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);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -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,
|
||||||
),
|
),
|
||||||
|
|||||||
@@ -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
|
||||||
|
|||||||
Reference in New Issue
Block a user