Neuer Regelsatz: Platzierung #213
@@ -18,6 +18,8 @@ String translateRulesetToString(Ruleset ruleset, BuildContext context) {
|
||||
return loc.single_loser;
|
||||
case Ruleset.multipleWinners:
|
||||
return loc.multiple_winners;
|
||||
case Ruleset.placement:
|
||||
return loc.placement;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -32,12 +32,14 @@ enum ExportResult { success, canceled, unknownException }
|
||||
/// - [Ruleset.singleWinner]: The match is won by a single player.
|
||||
/// - [Ruleset.singleLoser]: The match has a single loser.
|
||||
/// - [Ruleset.multipleWinners]: Multiple players can be winners.
|
||||
/// - [Ruleset.placement]: The player with the highest placement wins.
|
||||
enum Ruleset {
|
||||
highestScore,
|
||||
lowestScore,
|
||||
singleWinner,
|
||||
singleLoser,
|
||||
multipleWinners,
|
||||
placement,
|
||||
}
|
||||
|
||||
/// Different colors available for games
|
||||
|
||||
@@ -156,6 +156,9 @@ class Match {
|
||||
|
||||
case Ruleset.multipleWinners:
|
||||
return [];
|
||||
|
||||
case Ruleset.placement:
|
||||
return _getPlayersWithHighestScore().take(1).toList();
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -71,6 +71,7 @@
|
||||
"none": "Kein",
|
||||
"none_group": "Keine",
|
||||
"not_available": "Nicht verfügbar",
|
||||
"placement": "Platzierung",
|
||||
"played_matches": "Gespielte Spiele",
|
||||
"player_name": "Spieler:innenname",
|
||||
"players": "Spieler:innen",
|
||||
@@ -85,6 +86,7 @@
|
||||
"ruleset": "Regelwerk",
|
||||
"ruleset_least_points": "Umgekehrte Wertung: Der/die Spieler:in mit den wenigsten Punkten gewinnt.",
|
||||
"ruleset_most_points": "Traditionelles Regelwerk: Der/die Spieler:in mit den meisten Punkten gewinnt.",
|
||||
"ruleset_placement": "Spieler:innen können in einer Reihenfolge angeordnet werden, die ihre Platzierung reflektiert.",
|
||||
"ruleset_single_loser": "Genau ein:e Verlierer:in wird bestimmt; der letzte Platz erhält die Strafe oder Konsequenz.",
|
||||
"ruleset_single_winner": "Genau ein:e Gewinner:in wird gewählt; Unentschieden werden durch einen vordefinierten Tie-Breaker aufgelöst.",
|
||||
"save_changes": "Änderungen speichern",
|
||||
|
||||
@@ -77,6 +77,9 @@
|
||||
"@delete_match": {
|
||||
"description": "Button text to delete a match"
|
||||
},
|
||||
"@drag_to_set_placement": {
|
||||
"description": "Label for dragging to set placement"
|
||||
},
|
||||
"@edit_group": {
|
||||
"description": "Button & Appbar label for editing a group"
|
||||
},
|
||||
@@ -218,6 +221,9 @@
|
||||
"@not_available": {
|
||||
"description": "Abbreviation for not available"
|
||||
},
|
||||
"@placement": {
|
||||
"description": "Title for placement ruleset"
|
||||
},
|
||||
"@played_matches": {
|
||||
"description": "Label for played matches statistic"
|
||||
},
|
||||
@@ -259,6 +265,9 @@
|
||||
"@ruleset_most_points": {
|
||||
"description": "Description for most points ruleset"
|
||||
},
|
||||
"@ruleset_placement": {
|
||||
"description": "Description for placement ruleset"
|
||||
},
|
||||
"@ruleset_single_loser": {
|
||||
"description": "Description for single loser ruleset"
|
||||
},
|
||||
@@ -358,6 +367,7 @@
|
||||
"delete_all_data": "Delete all data",
|
||||
"delete_group": "Delete Group",
|
||||
"delete_match": "Delete Match",
|
||||
"drag_to_set_placement": "Drag to set placement",
|
||||
"edit_group": "Edit Group",
|
||||
"edit_match": "Edit Match",
|
||||
"enter_points": "Enter points",
|
||||
@@ -405,6 +415,7 @@
|
||||
"none": "None",
|
||||
"none_group": "None",
|
||||
"not_available": "Not available",
|
||||
"placement": "Placement",
|
||||
"played_matches": "Played Matches",
|
||||
"player_name": "Player name",
|
||||
"players": "Players",
|
||||
@@ -418,6 +429,7 @@
|
||||
"ruleset": "Ruleset",
|
||||
"ruleset_least_points": "Inverse scoring: the player with the fewest points wins.",
|
||||
"ruleset_most_points": "Traditional ruleset: the player with the most points wins.",
|
||||
"ruleset_placement": "Players can be arranged in an order, which reflects their placement.",
|
||||
"ruleset_single_loser": "Exactly one loser is determined; last place receives the penalty or consequence.",
|
||||
"ruleset_single_winner": "Exactly one winner is chosen; ties are resolved by a predefined tiebreaker.",
|
||||
"save_changes": "Save Changes",
|
||||
|
||||
@@ -242,6 +242,12 @@ abstract class AppLocalizations {
|
||||
/// **'Delete Match'**
|
||||
String get delete_match;
|
||||
|
||||
/// Label for dragging to set placement
|
||||
///
|
||||
/// In en, this message translates to:
|
||||
/// **'Drag to set placement'**
|
||||
String get drag_to_set_placement;
|
||||
|
||||
/// Button & Appbar label for editing a group
|
||||
///
|
||||
/// In en, this message translates to:
|
||||
@@ -524,6 +530,12 @@ abstract class AppLocalizations {
|
||||
/// **'Not available'**
|
||||
String get not_available;
|
||||
|
||||
/// Title for placement ruleset
|
||||
///
|
||||
/// In en, this message translates to:
|
||||
/// **'Placement'**
|
||||
String get placement;
|
||||
|
||||
/// Label for played matches statistic
|
||||
///
|
||||
/// In en, this message translates to:
|
||||
@@ -602,6 +614,12 @@ abstract class AppLocalizations {
|
||||
/// **'Traditional ruleset: the player with the most points wins.'**
|
||||
String get ruleset_most_points;
|
||||
|
||||
/// Description for placement ruleset
|
||||
///
|
||||
/// In en, this message translates to:
|
||||
/// **'Players can be arranged in an order, which reflects their placement.'**
|
||||
String get ruleset_placement;
|
||||
|
||||
/// Description for single loser ruleset
|
||||
///
|
||||
/// In en, this message translates to:
|
||||
|
||||
@@ -84,6 +84,9 @@ class AppLocalizationsDe extends AppLocalizations {
|
||||
@override
|
||||
String get delete_match => 'Spiel löschen';
|
||||
|
||||
@override
|
||||
String get drag_to_set_placement => 'Ziehen, um die Platzierung zu setzen';
|
||||
|
||||
@override
|
||||
String get edit_group => 'Gruppe bearbeiten';
|
||||
|
||||
@@ -229,6 +232,9 @@ class AppLocalizationsDe extends AppLocalizations {
|
||||
@override
|
||||
String get not_available => 'Nicht verfügbar';
|
||||
|
||||
@override
|
||||
String get placement => 'Platzierung';
|
||||
|
||||
@override
|
||||
String get played_matches => 'Gespielte Spiele';
|
||||
|
||||
@@ -272,6 +278,10 @@ class AppLocalizationsDe extends AppLocalizations {
|
||||
String get ruleset_most_points =>
|
||||
'Traditionelles Regelwerk: Der/die Spieler:in mit den meisten Punkten gewinnt.';
|
||||
|
||||
@override
|
||||
String get ruleset_placement =>
|
||||
'Spieler:innen können in einer Reihenfolge angeordnet werden, die ihre Platzierung reflektiert.';
|
||||
|
||||
@override
|
||||
String get ruleset_single_loser =>
|
||||
'Genau ein:e Verlierer:in wird bestimmt; der letzte Platz erhält die Strafe oder Konsequenz.';
|
||||
|
||||
@@ -84,6 +84,9 @@ class AppLocalizationsEn extends AppLocalizations {
|
||||
@override
|
||||
String get delete_match => 'Delete Match';
|
||||
|
||||
@override
|
||||
String get drag_to_set_placement => 'Drag to set placement';
|
||||
|
||||
@override
|
||||
String get edit_group => 'Edit Group';
|
||||
|
||||
@@ -229,6 +232,9 @@ class AppLocalizationsEn extends AppLocalizations {
|
||||
@override
|
||||
String get not_available => 'Not available';
|
||||
|
||||
@override
|
||||
String get placement => 'Placement';
|
||||
|
||||
@override
|
||||
String get played_matches => 'Played Matches';
|
||||
|
||||
@@ -272,6 +278,10 @@ class AppLocalizationsEn extends AppLocalizations {
|
||||
String get ruleset_most_points =>
|
||||
'Traditional ruleset: the player with the most points wins.';
|
||||
|
||||
@override
|
||||
String get ruleset_placement =>
|
||||
'Players can be arranged in an order, which reflects their placement.';
|
||||
|
||||
@override
|
||||
String get ruleset_single_loser =>
|
||||
'Exactly one loser is determined; last place receives the penalty or consequence.';
|
||||
|
||||
@@ -288,34 +288,39 @@ class _MatchDetailViewState extends State<MatchDetailView> {
|
||||
}
|
||||
}
|
||||
|
||||
/// Returns the result widget for scores
|
||||
/// Returns the result widget for scores or placement
|
||||
Widget getScoreResultWidget(AppLocalizations loc) {
|
||||
List<(String, int)> playerScores = [];
|
||||
for (var player in match.players) {
|
||||
int score = match.scores[player.id]?.score ?? 0;
|
||||
playerScores.add((player.name, score));
|
||||
}
|
||||
if (widget.match.game.ruleset == Ruleset.highestScore) {
|
||||
|
||||
final ruleset = match.game.ruleset;
|
||||
|
||||
if (ruleset == Ruleset.highestScore || ruleset == Ruleset.placement) {
|
||||
playerScores.sort((a, b) => b.$2.compareTo(a.$2));
|
||||
} else if (widget.match.game.ruleset == Ruleset.lowestScore) {
|
||||
} else if (ruleset == Ruleset.lowestScore) {
|
||||
|
sneeex marked this conversation as resolved
Outdated
|
||||
playerScores.sort((a, b) => a.$2.compareTo(b.$2));
|
||||
}
|
||||
|
||||
return Column(
|
||||
children: [
|
||||
for (var score in playerScores)
|
||||
for (var i = 0; i < playerScores.length; i++)
|
||||
Row(
|
||||
mainAxisAlignment: MainAxisAlignment.spaceBetween,
|
||||
children: [
|
||||
Text(
|
||||
score.$1,
|
||||
playerScores[i].$1,
|
||||
style: const TextStyle(
|
||||
fontSize: 16,
|
||||
color: CustomTheme.textColor,
|
||||
),
|
||||
),
|
||||
Text(
|
||||
getPointLabel(loc, score.$2),
|
||||
ruleset == Ruleset.placement
|
||||
? '#${i + 1}'
|
||||
: getPointLabel(loc, playerScores[i].$2),
|
||||
style: const TextStyle(
|
||||
fontSize: 16,
|
||||
fontWeight: FontWeight.bold,
|
||||
|
||||
@@ -10,6 +10,7 @@ import 'package:tallee/l10n/generated/app_localizations.dart';
|
||||
import 'package:tallee/presentation/widgets/buttons/custom_width_button.dart';
|
||||
import 'package:tallee/presentation/widgets/tiles/custom_radio_list_tile.dart';
|
||||
import 'package:tallee/presentation/widgets/tiles/score_list_tile.dart';
|
||||
import 'package:tallee/presentation/widgets/tiles/text_icon_list_tile.dart';
|
||||
|
||||
class MatchResultView extends StatefulWidget {
|
||||
/// A view that allows selecting and saving the winner of a match
|
||||
@@ -68,6 +69,12 @@ class _MatchResultViewState extends State<MatchResultView> {
|
||||
final score = scoreList?.score ?? 0;
|
||||
controller[i].text = score.toString();
|
||||
}
|
||||
} else if (rulesetSupportsPlacement()) {
|
||||
allPlayers.sort((a, b) {
|
||||
final scoreA = widget.match.scores[a.id]?.score ?? 0;
|
||||
final scoreB = widget.match.scores[b.id]?.score ?? 0;
|
||||
return scoreB.compareTo(scoreA);
|
||||
});
|
||||
}
|
||||
super.initState();
|
||||
}
|
||||
@@ -177,6 +184,70 @@ class _MatchResultViewState extends State<MatchResultView> {
|
||||
},
|
||||
),
|
||||
),
|
||||
if (rulesetSupportsPlacement())
|
||||
Expanded(
|
||||
child: Row(
|
||||
children: [
|
||||
Padding(
|
||||
padding: const EdgeInsets.only(right: 8.0),
|
||||
child: Column(
|
||||
children: [
|
||||
for (int i = 0; i < allPlayers.length; i++)
|
||||
Container(
|
||||
alignment: Alignment.center,
|
||||
height: 60,
|
||||
child: Container(
|
||||
decoration:
|
||||
CustomTheme.standardBoxDecoration,
|
||||
|
flixcoo marked this conversation as resolved
Outdated
flixcoo
commented
Vielleicht andere box decoration, maybe keine border und kompletter container in der border color Vielleicht andere box decoration, maybe keine border und kompletter container in der border color
sneeex
commented
flixcoo
commented
ja fair, aber irgendwie würd ich die gern anders darstellen. Nicht genau so wie die list tiles. Und macht die mal quadratisch ja fair, aber irgendwie würd ich die gern anders darstellen. Nicht genau so wie die list tiles. Und macht die mal quadratisch
sneeex
commented
flixcoo
commented
Mach mal color: orange, fontcolor: weiß Mach mal color: orange, fontcolor: weiß
sneeex
commented
|
||||
alignment: Alignment.center,
|
||||
height: 50,
|
||||
width: 40,
|
||||
child: Text(
|
||||
" #${i + 1} ",
|
||||
style: const TextStyle(
|
||||
color: CustomTheme.primaryColor,
|
||||
fontWeight: FontWeight.bold,
|
||||
fontSize: 16,
|
||||
),
|
||||
),
|
||||
),
|
||||
),
|
||||
],
|
||||
),
|
||||
),
|
||||
Expanded(
|
||||
child: ReorderableListView.builder(
|
||||
padding: EdgeInsets.zero,
|
||||
proxyDecorator: (child, index, animation) {
|
||||
return Material(
|
||||
color: Colors.transparent,
|
||||
child: child,
|
||||
|
flixcoo marked this conversation as resolved
Outdated
flixcoo
commented
Gerne hier noch ein kleines Highlighting implementieren, wenn ein Tile gedraggt wird Gerne hier noch ein kleines Highlighting implementieren, wenn ein Tile gedraggt wird
sneeex
commented
so nen highlighting? so nen highlighting?
flixcoo
commented
Das mag ich garnicht. Lieber was simples, z.B. BG color etwas heller, ne weiße border oder so Das mag ich garnicht. Lieber was simples, z.B. BG color etwas heller, ne weiße border oder so
sneeex
commented
dann schau mal selber ich habe wirklich keine ahnung dann schau mal selber ich habe wirklich keine ahnung
|
||||
);
|
||||
},
|
||||
onReorder: (int oldIndex, int newIndex) {
|
||||
setState(() {
|
||||
if (newIndex > oldIndex) {
|
||||
newIndex -= 1;
|
||||
}
|
||||
final Player item = allPlayers.removeAt(
|
||||
oldIndex,
|
||||
);
|
||||
allPlayers.insert(newIndex, item);
|
||||
});
|
||||
},
|
||||
itemCount: allPlayers.length,
|
||||
itemBuilder: (context, index) {
|
||||
return TextIconListTile(
|
||||
key: ValueKey(allPlayers[index].id),
|
||||
text: allPlayers[index].name,
|
||||
iconEnabled: false,
|
||||
);
|
||||
},
|
||||
),
|
||||
),
|
||||
],
|
||||
),
|
||||
),
|
||||
],
|
||||
),
|
||||
),
|
||||
@@ -222,6 +293,8 @@ class _MatchResultViewState extends State<MatchResultView> {
|
||||
} else if (ruleset == Ruleset.lowestScore ||
|
||||
ruleset == Ruleset.highestScore) {
|
||||
await _handleScores();
|
||||
} else if (ruleset == Ruleset.placement) {
|
||||
await _handlePlacement();
|
||||
}
|
||||
|
||||
widget.onWinnerChanged?.call();
|
||||
@@ -267,12 +340,29 @@ class _MatchResultViewState extends State<MatchResultView> {
|
||||
}
|
||||
}
|
||||
|
||||
/// Handles saving the placement for each player in the database.
|
||||
Future<void> _handlePlacement() async {
|
||||
for (int i = 0; i < allPlayers.length; i++) {
|
||||
await db.scoreEntryDao.addScore(
|
||||
matchId: widget.match.id,
|
||||
playerId: allPlayers[i].id,
|
||||
|
sneeex marked this conversation as resolved
Outdated
flixcoo
commented
Bitte neue Methode Bitte neue Methode `setPlacements(List<Player> player)` bei der die Platzierung anhand des Index gesetzt wird.
sneeex
commented
du bist weird, warum soll ich das auslagern, die methode hat doch nur die einzige funktion mit handlePlacement hä du bist weird, warum soll ich das auslagern, die methode hat doch nur die einzige funktion mit handlePlacement hä
flixcoo
commented
Die Methode soll in die Die Methode soll in die `score_entry_dao.dart ` zu den anderen Methoden wie `setWinner()`, `addScore()` etc
|
||||
entry: ScoreEntry(
|
||||
roundNumber: 0,
|
||||
score: allPlayers.length - i,
|
||||
change: 0,
|
||||
),
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
String getTitleForRuleset(AppLocalizations loc) {
|
||||
switch (ruleset) {
|
||||
case Ruleset.singleWinner:
|
||||
return loc.select_winner;
|
||||
case Ruleset.singleLoser:
|
||||
return loc.select_loser;
|
||||
case Ruleset.placement:
|
||||
return loc.drag_to_set_placement;
|
||||
default:
|
||||
return loc.enter_points;
|
||||
}
|
||||
@@ -285,4 +375,8 @@ class _MatchResultViewState extends State<MatchResultView> {
|
||||
bool rulesetSupportsScoreEntry() {
|
||||
return ruleset == Ruleset.lowestScore || ruleset == Ruleset.highestScore;
|
||||
}
|
||||
|
||||
bool rulesetSupportsPlacement() {
|
||||
return ruleset == Ruleset.placement;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -10,6 +10,7 @@ class TextIconListTile extends StatelessWidget {
|
||||
super.key,
|
||||
required this.text,
|
||||
this.suffixText = '',
|
||||
this.prefixText = '',
|
||||
this.iconEnabled = true,
|
||||
this.onPressed,
|
||||
});
|
||||
@@ -20,6 +21,9 @@ class TextIconListTile extends StatelessWidget {
|
||||
/// An optional suffix text to display after the main text.
|
||||
final String suffixText;
|
||||
|
||||
/// An optional prefix text to display before the main text.
|
||||
final String prefixText;
|
||||
|
||||
/// A boolean to determine if the icon should be displayed.
|
||||
final bool iconEnabled;
|
||||
|
||||
@@ -44,6 +48,14 @@ class TextIconListTile extends StatelessWidget {
|
||||
text: TextSpan(
|
||||
style: DefaultTextStyle.of(context).style,
|
||||
children: [
|
||||
TextSpan(
|
||||
text: prefixText,
|
||||
style: TextStyle(
|
||||
fontSize: 16,
|
||||
fontWeight: FontWeight.bold,
|
||||
color: CustomTheme.primaryColor,
|
||||
),
|
||||
),
|
||||
TextSpan(
|
||||
text: text,
|
||||
style: const TextStyle(
|
||||
|
||||
Würde glaub ich hierfür Links in Orange Bold Font "1. (2., 3., ...) Platz" und Rechts dann den Namen des Spielers in White Normal Font
ist aber irgendwie bisschen weird dann anders als die anderen oder?1 weil bisher ist ja alle infos immer rechts und links die spielernamen
Ja sonst ersetz mal erstmal die
#<num>durch<num>. Platz