feat: implemented team score handling
This commit is contained in:
@@ -4,6 +4,7 @@ import 'package:tallee/data/db/database.dart';
|
||||
import 'package:tallee/data/db/tables/player_match_table.dart';
|
||||
import 'package:tallee/data/db/tables/team_table.dart';
|
||||
import 'package:tallee/data/models/player.dart';
|
||||
import 'package:tallee/data/models/score_entry.dart';
|
||||
import 'package:tallee/data/models/team.dart';
|
||||
|
||||
part 'team_dao.g.dart';
|
||||
@@ -186,15 +187,42 @@ class TeamDao extends DatabaseAccessor<AppDatabase> with _$TeamDaoMixin {
|
||||
/// Updates the score of the team with the given [teamId].
|
||||
Future<bool> updateTeamScore({
|
||||
required String teamId,
|
||||
required String matchId,
|
||||
required int score,
|
||||
}) async {
|
||||
await (update(teamTable)..where((t) => t.id.equals(teamId))).write(
|
||||
const TeamTableCompanion(score: Value(null)),
|
||||
);
|
||||
await db.scoreEntryDao.deleteAllScoresForMatch(matchId: matchId);
|
||||
|
||||
final rowsAffected =
|
||||
await (update(teamTable)..where((t) => t.id.equals(teamId))).write(
|
||||
TeamTableCompanion(score: Value(score)),
|
||||
);
|
||||
|
||||
final members = await _getTeamMembers(teamId: teamId);
|
||||
for (final member in members) {
|
||||
await db.scoreEntryDao.updateScore(
|
||||
playerId: member.id,
|
||||
matchId: matchId,
|
||||
entry: ScoreEntry(score: score),
|
||||
);
|
||||
}
|
||||
|
||||
return rowsAffected > 0;
|
||||
}
|
||||
|
||||
Future<bool> removeScoreForTeam({
|
||||
required String teamId,
|
||||
required String matchId,
|
||||
}) async {
|
||||
await (update(teamTable)..where((t) => t.id.equals(teamId))).write(
|
||||
const TeamTableCompanion(score: Value(null)),
|
||||
);
|
||||
await db.scoreEntryDao.deleteAllScoresForMatch(matchId: matchId);
|
||||
return true;
|
||||
}
|
||||
|
||||
/* Delete */
|
||||
|
||||
/// Deletes all teams from the database.
|
||||
@@ -212,4 +240,50 @@ class TeamDao extends DatabaseAccessor<AppDatabase> with _$TeamDaoMixin {
|
||||
final rowsAffected = await query.go();
|
||||
return rowsAffected > 0;
|
||||
}
|
||||
|
||||
/* Score handling */
|
||||
|
||||
Future<bool> setWinnerTeam({
|
||||
required String teamId,
|
||||
required String matchId,
|
||||
}) async {
|
||||
return await updateTeamScore(teamId: teamId, matchId: matchId, score: 1);
|
||||
}
|
||||
|
||||
Future<bool> removeWinnerTeam({
|
||||
required String teamId,
|
||||
required String matchId,
|
||||
}) async {
|
||||
return await removeScoreForTeam(teamId: teamId, matchId: matchId);
|
||||
}
|
||||
|
||||
Future<bool> setLoserTeam({
|
||||
required String teamId,
|
||||
required String matchId,
|
||||
}) async {
|
||||
return await updateTeamScore(teamId: teamId, matchId: matchId, score: 0);
|
||||
}
|
||||
|
||||
Future<bool> removeLoserTeam({
|
||||
required String teamId,
|
||||
required String matchId,
|
||||
}) async {
|
||||
return await removeScoreForTeam(teamId: teamId, matchId: matchId);
|
||||
}
|
||||
|
||||
Future<bool> setTeamPlacements({
|
||||
required String teamId,
|
||||
required String matchId,
|
||||
required List<Team> teams,
|
||||
}) async {
|
||||
List<bool?> success = List.generate(teams.length, (index) => null);
|
||||
for (int i = 0; i < teams.length; i++) {
|
||||
success[i] = await updateTeamScore(
|
||||
matchId: matchId,
|
||||
teamId: teams[i].id,
|
||||
score: teams.length - i,
|
||||
);
|
||||
}
|
||||
return success.every((result) => result == true);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1930,10 +1930,9 @@ class $TeamTableTable extends TeamTable
|
||||
late final GeneratedColumn<int> score = GeneratedColumn<int>(
|
||||
'score',
|
||||
aliasedName,
|
||||
false,
|
||||
true,
|
||||
type: DriftSqlType.int,
|
||||
requiredDuringInsert: false,
|
||||
defaultValue: const Constant(0),
|
||||
);
|
||||
@override
|
||||
List<GeneratedColumn> get $columns => [id, name, createdAt, color, score];
|
||||
@@ -2010,7 +2009,7 @@ class $TeamTableTable extends TeamTable
|
||||
score: attachedDatabase.typeMapping.read(
|
||||
DriftSqlType.int,
|
||||
data['${effectivePrefix}score'],
|
||||
)!,
|
||||
),
|
||||
);
|
||||
}
|
||||
|
||||
@@ -2025,13 +2024,13 @@ class TeamTableData extends DataClass implements Insertable<TeamTableData> {
|
||||
final String name;
|
||||
final DateTime createdAt;
|
||||
final String color;
|
||||
final int score;
|
||||
final int? score;
|
||||
const TeamTableData({
|
||||
required this.id,
|
||||
required this.name,
|
||||
required this.createdAt,
|
||||
required this.color,
|
||||
required this.score,
|
||||
this.score,
|
||||
});
|
||||
@override
|
||||
Map<String, Expression> toColumns(bool nullToAbsent) {
|
||||
@@ -2040,7 +2039,9 @@ class TeamTableData extends DataClass implements Insertable<TeamTableData> {
|
||||
map['name'] = Variable<String>(name);
|
||||
map['created_at'] = Variable<DateTime>(createdAt);
|
||||
map['color'] = Variable<String>(color);
|
||||
map['score'] = Variable<int>(score);
|
||||
if (!nullToAbsent || score != null) {
|
||||
map['score'] = Variable<int>(score);
|
||||
}
|
||||
return map;
|
||||
}
|
||||
|
||||
@@ -2050,7 +2051,9 @@ class TeamTableData extends DataClass implements Insertable<TeamTableData> {
|
||||
name: Value(name),
|
||||
createdAt: Value(createdAt),
|
||||
color: Value(color),
|
||||
score: Value(score),
|
||||
score: score == null && nullToAbsent
|
||||
? const Value.absent()
|
||||
: Value(score),
|
||||
);
|
||||
}
|
||||
|
||||
@@ -2064,7 +2067,7 @@ class TeamTableData extends DataClass implements Insertable<TeamTableData> {
|
||||
name: serializer.fromJson<String>(json['name']),
|
||||
createdAt: serializer.fromJson<DateTime>(json['createdAt']),
|
||||
color: serializer.fromJson<String>(json['color']),
|
||||
score: serializer.fromJson<int>(json['score']),
|
||||
score: serializer.fromJson<int?>(json['score']),
|
||||
);
|
||||
}
|
||||
@override
|
||||
@@ -2075,7 +2078,7 @@ class TeamTableData extends DataClass implements Insertable<TeamTableData> {
|
||||
'name': serializer.toJson<String>(name),
|
||||
'createdAt': serializer.toJson<DateTime>(createdAt),
|
||||
'color': serializer.toJson<String>(color),
|
||||
'score': serializer.toJson<int>(score),
|
||||
'score': serializer.toJson<int?>(score),
|
||||
};
|
||||
}
|
||||
|
||||
@@ -2084,13 +2087,13 @@ class TeamTableData extends DataClass implements Insertable<TeamTableData> {
|
||||
String? name,
|
||||
DateTime? createdAt,
|
||||
String? color,
|
||||
int? score,
|
||||
Value<int?> score = const Value.absent(),
|
||||
}) => TeamTableData(
|
||||
id: id ?? this.id,
|
||||
name: name ?? this.name,
|
||||
createdAt: createdAt ?? this.createdAt,
|
||||
color: color ?? this.color,
|
||||
score: score ?? this.score,
|
||||
score: score.present ? score.value : this.score,
|
||||
);
|
||||
TeamTableData copyWithCompanion(TeamTableCompanion data) {
|
||||
return TeamTableData(
|
||||
@@ -2132,7 +2135,7 @@ class TeamTableCompanion extends UpdateCompanion<TeamTableData> {
|
||||
final Value<String> name;
|
||||
final Value<DateTime> createdAt;
|
||||
final Value<String> color;
|
||||
final Value<int> score;
|
||||
final Value<int?> score;
|
||||
final Value<int> rowid;
|
||||
const TeamTableCompanion({
|
||||
this.id = const Value.absent(),
|
||||
@@ -2175,7 +2178,7 @@ class TeamTableCompanion extends UpdateCompanion<TeamTableData> {
|
||||
Value<String>? name,
|
||||
Value<DateTime>? createdAt,
|
||||
Value<String>? color,
|
||||
Value<int>? score,
|
||||
Value<int?>? score,
|
||||
Value<int>? rowid,
|
||||
}) {
|
||||
return TeamTableCompanion(
|
||||
@@ -5279,7 +5282,7 @@ typedef $$TeamTableTableCreateCompanionBuilder =
|
||||
required String name,
|
||||
required DateTime createdAt,
|
||||
Value<String> color,
|
||||
Value<int> score,
|
||||
Value<int?> score,
|
||||
Value<int> rowid,
|
||||
});
|
||||
typedef $$TeamTableTableUpdateCompanionBuilder =
|
||||
@@ -5288,7 +5291,7 @@ typedef $$TeamTableTableUpdateCompanionBuilder =
|
||||
Value<String> name,
|
||||
Value<DateTime> createdAt,
|
||||
Value<String> color,
|
||||
Value<int> score,
|
||||
Value<int?> score,
|
||||
Value<int> rowid,
|
||||
});
|
||||
|
||||
@@ -5497,7 +5500,7 @@ class $$TeamTableTableTableManager
|
||||
Value<String> name = const Value.absent(),
|
||||
Value<DateTime> createdAt = const Value.absent(),
|
||||
Value<String> color = const Value.absent(),
|
||||
Value<int> score = const Value.absent(),
|
||||
Value<int?> score = const Value.absent(),
|
||||
Value<int> rowid = const Value.absent(),
|
||||
}) => TeamTableCompanion(
|
||||
id: id,
|
||||
@@ -5513,7 +5516,7 @@ class $$TeamTableTableTableManager
|
||||
required String name,
|
||||
required DateTime createdAt,
|
||||
Value<String> color = const Value.absent(),
|
||||
Value<int> score = const Value.absent(),
|
||||
Value<int?> score = const Value.absent(),
|
||||
Value<int> rowid = const Value.absent(),
|
||||
}) => TeamTableCompanion.insert(
|
||||
id: id,
|
||||
|
||||
@@ -5,7 +5,7 @@ class TeamTable extends Table {
|
||||
TextColumn get name => text()();
|
||||
DateTimeColumn get createdAt => dateTime()();
|
||||
TextColumn get color => text().withDefault(const Constant('blue'))();
|
||||
IntColumn get score => integer().withDefault(const Constant(0))();
|
||||
IntColumn get score => integer().nullable()();
|
||||
|
||||
@override
|
||||
Set<Column<Object>> get primaryKey => {id};
|
||||
|
||||
@@ -231,8 +231,13 @@ class Match {
|
||||
}
|
||||
|
||||
List<Team> _getHighestScoreTeam() {
|
||||
if (teams!.every((team) => team.score == null)) {
|
||||
return [];
|
||||
}
|
||||
|
||||
final int highestScore = teams!
|
||||
.map((team) => team.score)
|
||||
.whereType<int>()
|
||||
.reduce((max, score) => score > max ? score : max);
|
||||
|
||||
return teams!.where((team) {
|
||||
@@ -241,8 +246,13 @@ class Match {
|
||||
}
|
||||
|
||||
List<Team> _getLowestScoreTeam() {
|
||||
if (teams!.every((team) => team.score == null)) {
|
||||
return [];
|
||||
}
|
||||
|
||||
final int lowestScore = teams!
|
||||
.map((team) => team.score)
|
||||
.whereType<int>()
|
||||
.reduce((min, score) => score < min ? score : min);
|
||||
|
||||
return teams!.where((team) {
|
||||
|
||||
@@ -9,7 +9,7 @@ class Team {
|
||||
final String name;
|
||||
final DateTime createdAt;
|
||||
final GameColor color;
|
||||
final int score;
|
||||
final int? score;
|
||||
final List<Player> members;
|
||||
|
||||
Team({
|
||||
@@ -17,7 +17,7 @@ class Team {
|
||||
required this.name,
|
||||
DateTime? createdAt,
|
||||
this.color = GameColor.blue,
|
||||
this.score = 0,
|
||||
this.score,
|
||||
required this.members,
|
||||
}) : id = id ?? const Uuid().v4(),
|
||||
createdAt = createdAt ?? clock.now();
|
||||
|
||||
@@ -198,20 +198,7 @@ class _MatchResultViewState extends State<MatchResultView> {
|
||||
}
|
||||
|
||||
void initializeAsTeamMatch() {
|
||||
allTeams =
|
||||
widget.match.teams ??
|
||||
List.generate(
|
||||
4,
|
||||
(index) => Team(
|
||||
name: 'Team ${index + 1}',
|
||||
members: [
|
||||
Player(name: 'Player ${index + 1}'),
|
||||
Player(name: 'Player ${index + 2}'),
|
||||
Player(name: 'Player ${index + 3}'),
|
||||
Player(name: 'Player ${index + 4}'),
|
||||
],
|
||||
),
|
||||
);
|
||||
allTeams = widget.match.teams ?? [];
|
||||
allTeams.sort((a, b) => a.name.compareTo(b.name));
|
||||
|
||||
controller = List.generate(
|
||||
@@ -220,7 +207,26 @@ class _MatchResultViewState extends State<MatchResultView> {
|
||||
);
|
||||
|
||||
// Prefill fields
|
||||
//TODO
|
||||
if (widget.match.mvt.isNotEmpty) {
|
||||
if (rulesetSupportsWinnerSelection()) {
|
||||
_selectedTeam = allTeams.firstWhere(
|
||||
(p) => p.id == widget.match.mvt.first.id,
|
||||
);
|
||||
} else if (rulesetSupportsScoreEntry()) {
|
||||
for (int i = 0; i < allTeams.length; i++) {
|
||||
final score = allTeams[i].score;
|
||||
controller[i].text = score.toString();
|
||||
}
|
||||
} else if (rulesetSupportsPlacement()) {
|
||||
allTeams.sort((a, b) {
|
||||
final scoreA =
|
||||
allTeams.where((team) => a.id == team.id).first.score ?? 0;
|
||||
final scoreB =
|
||||
allTeams.where((team) => b.id == team.id).first.score ?? 0;
|
||||
return scoreB.compareTo(scoreA);
|
||||
});
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void inizializeAsNormalMatch() {
|
||||
@@ -282,41 +288,84 @@ class _MatchResultViewState extends State<MatchResultView> {
|
||||
|
||||
/// Handles saving or removing the winner in the database.
|
||||
Future<bool> _handleWinner() async {
|
||||
if (_selectedPlayer == null) {
|
||||
return await db.scoreEntryDao.removeWinner(matchId: widget.match.id);
|
||||
if (isTeamMatch) {
|
||||
if (_selectedTeam == null) {
|
||||
return await db.teamDao.setWinnerTeam(
|
||||
matchId: widget.match.id,
|
||||
teamId: _selectedTeam!.id,
|
||||
);
|
||||
} else {
|
||||
return await db.teamDao.setLoserTeam(
|
||||
matchId: widget.match.id,
|
||||
teamId: _selectedTeam!.id,
|
||||
);
|
||||
}
|
||||
} else {
|
||||
return await db.scoreEntryDao.setWinner(
|
||||
matchId: widget.match.id,
|
||||
playerId: _selectedPlayer!.id,
|
||||
);
|
||||
if (_selectedPlayer == null) {
|
||||
return await db.scoreEntryDao.removeWinner(matchId: widget.match.id);
|
||||
} else {
|
||||
return await db.scoreEntryDao.setWinner(
|
||||
matchId: widget.match.id,
|
||||
playerId: _selectedPlayer!.id,
|
||||
);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/// Handles saving or removing the loser in the database.
|
||||
Future<bool> _handleLoser() async {
|
||||
if (_selectedPlayer == null) {
|
||||
return await db.scoreEntryDao.removeLoser(matchId: widget.match.id);
|
||||
if (isTeamMatch) {
|
||||
if (_selectedTeam == null) {
|
||||
return await db.teamDao.removeLoserTeam(
|
||||
matchId: widget.match.id,
|
||||
teamId: _selectedTeam!.id,
|
||||
);
|
||||
} else {
|
||||
return await db.teamDao.setLoserTeam(
|
||||
matchId: widget.match.id,
|
||||
teamId: _selectedTeam!.id,
|
||||
);
|
||||
}
|
||||
} else {
|
||||
return await db.scoreEntryDao.setLoser(
|
||||
matchId: widget.match.id,
|
||||
playerId: _selectedPlayer!.id,
|
||||
);
|
||||
if (_selectedPlayer == null) {
|
||||
return await db.scoreEntryDao.removeLoser(matchId: widget.match.id);
|
||||
} else {
|
||||
return await db.scoreEntryDao.setLoser(
|
||||
matchId: widget.match.id,
|
||||
playerId: _selectedPlayer!.id,
|
||||
);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/// Handles saving the scores for each player in the database.
|
||||
Future<void> _handleScores() async {
|
||||
for (int i = 0; i < allPlayers.length; i++) {
|
||||
var text = controller[i].text;
|
||||
if (text.isEmpty) {
|
||||
text = '0';
|
||||
if (isTeamMatch) {
|
||||
for (int i = 0; i < allTeams.length; i++) {
|
||||
var text = controller[i].text;
|
||||
if (text.isEmpty) {
|
||||
text = '0';
|
||||
}
|
||||
final score = int.parse(text);
|
||||
await db.teamDao.updateTeamScore(
|
||||
matchId: widget.match.id,
|
||||
teamId: allTeams[i].id,
|
||||
score: score,
|
||||
);
|
||||
}
|
||||
} else {
|
||||
for (int i = 0; i < allPlayers.length; i++) {
|
||||
var text = controller[i].text;
|
||||
if (text.isEmpty) {
|
||||
text = '0';
|
||||
}
|
||||
final score = int.parse(text);
|
||||
await db.scoreEntryDao.addScore(
|
||||
matchId: widget.match.id,
|
||||
playerId: allPlayers[i].id,
|
||||
entry: ScoreEntry(roundNumber: 0, score: score, change: 0),
|
||||
);
|
||||
}
|
||||
final score = int.parse(text);
|
||||
await db.scoreEntryDao.addScore(
|
||||
matchId: widget.match.id,
|
||||
playerId: allPlayers[i].id,
|
||||
entry: ScoreEntry(roundNumber: 0, score: score, change: 0),
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -1,7 +1,7 @@
|
||||
name: tallee
|
||||
description: "Tracking App for Card Games"
|
||||
publish_to: 'none'
|
||||
version: 0.0.30+281
|
||||
version: 0.0.30+285
|
||||
|
||||
environment:
|
||||
sdk: ^3.8.1
|
||||
|
||||
Reference in New Issue
Block a user