Implementierung der Games #203
@@ -1,4 +1,4 @@
|
|||||||
import 'package:flutter/cupertino.dart';
|
import 'package:flutter/material.dart';
|
||||||
import 'package:tallee/core/enums.dart';
|
import 'package:tallee/core/enums.dart';
|
||||||
import 'package:tallee/data/models/match.dart';
|
import 'package:tallee/data/models/match.dart';
|
||||||
import 'package:tallee/data/models/player.dart';
|
import 'package:tallee/data/models/player.dart';
|
||||||
@@ -21,8 +21,71 @@ String translateRulesetToString(Ruleset ruleset, BuildContext context) {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Counts how many players in the match are not part of the group
|
/// Translates a [GameColor] enum value to its corresponding localized string.
|
||||||
/// Returns the count as a string, or an empty string if there is no group
|
String translateGameColorToString(GameColor color, BuildContext context) {
|
||||||
|
final loc = AppLocalizations.of(context);
|
||||||
|
switch (color) {
|
||||||
|
case GameColor.red:
|
||||||
|
return loc.color_red;
|
||||||
|
case GameColor.blue:
|
||||||
|
return loc.color_blue;
|
||||||
|
case GameColor.green:
|
||||||
|
return loc.color_green;
|
||||||
|
case GameColor.yellow:
|
||||||
|
return loc.color_yellow;
|
||||||
|
case GameColor.purple:
|
||||||
|
return loc.color_purple;
|
||||||
|
case GameColor.orange:
|
||||||
|
return loc.color_orange;
|
||||||
|
case GameColor.pink:
|
||||||
|
return loc.color_pink;
|
||||||
|
case GameColor.teal:
|
||||||
|
return loc.color_teal;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Returns the [Color] object corresponding to a [GameColor] enum value.
|
||||||
|
Color getColorFromGameColor(GameColor color) {
|
||||||
|
switch (color) {
|
||||||
|
case GameColor.red:
|
||||||
|
return Colors.red;
|
||||||
|
case GameColor.blue:
|
||||||
|
return Colors.blue;
|
||||||
|
case GameColor.green:
|
||||||
|
return Colors.green;
|
||||||
|
case GameColor.yellow:
|
||||||
|
return const Color(0xFFF7CA28);
|
||||||
|
case GameColor.purple:
|
||||||
|
return Colors.purple;
|
||||||
|
case GameColor.orange:
|
||||||
|
return const Color(0xFFef681f);
|
||||||
|
case GameColor.pink:
|
||||||
|
return Colors.pink;
|
||||||
|
case GameColor.teal:
|
||||||
|
return Colors.teal;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Returns [IconData] corresponding to a [Ruleset] enum value.
|
||||||
|
IconData getRulesetIcon(Ruleset ruleset) {
|
||||||
|
switch (ruleset) {
|
||||||
|
case Ruleset.highestScore:
|
||||||
|
return Icons.arrow_upward;
|
||||||
|
case Ruleset.lowestScore:
|
||||||
|
return Icons.arrow_downward;
|
||||||
|
case Ruleset.singleWinner:
|
||||||
|
return Icons.emoji_events;
|
||||||
|
case Ruleset.singleLoser:
|
||||||
|
return Icons.sentiment_dissatisfied;
|
||||||
|
case Ruleset.multipleWinners:
|
||||||
|
return Icons.group;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Counts how many players in the [match] are not part of the group
|
||||||
|
///
|
||||||
|
/// Returns the text you append after the group name, e.g. " + 5" or an empty
|
||||||
|
/// string if there are no extra players
|
||||||
String getExtraPlayerCount(Match match) {
|
String getExtraPlayerCount(Match match) {
|
||||||
int count = 0;
|
int count = 0;
|
||||||
|
|
||||||
|
|||||||
@@ -19,4 +19,7 @@ class Constants {
|
|||||||
|
|
||||||
/// Maximum length for team names
|
/// Maximum length for team names
|
||||||
static const int MAX_TEAM_NAME_LENGTH = 32;
|
static const int MAX_TEAM_NAME_LENGTH = 32;
|
||||||
|
|
||||||
|
/// Maximum length for game descriptions
|
||||||
|
static const int MAX_GAME_DESCRIPTION_LENGTH = 256;
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -63,9 +63,8 @@ class CustomTheme {
|
|||||||
|
|
||||||
static BoxDecoration highlightedBoxDecoration = BoxDecoration(
|
static BoxDecoration highlightedBoxDecoration = BoxDecoration(
|
||||||
color: boxColor,
|
color: boxColor,
|
||||||
border: Border.all(color: primaryColor),
|
border: Border.all(color: textColor, width: 2),
|
||||||
|
sneeex marked this conversation as resolved
|
|||||||
borderRadius: standardBorderRadiusAll,
|
borderRadius: standardBorderRadiusAll,
|
||||||
boxShadow: [BoxShadow(color: primaryColor.withAlpha(120), blurRadius: 12)],
|
|
||||||
);
|
);
|
||||||
|
|
||||||
// ==================== Component Themes ====================
|
// ==================== Component Themes ====================
|
||||||
|
|||||||
@@ -194,4 +194,25 @@ class GameDao extends DatabaseAccessor<AppDatabase> with _$GameDaoMixin {
|
|||||||
final rowsAffected = await query.go();
|
final rowsAffected = await query.go();
|
||||||
return rowsAffected > 0;
|
return rowsAffected > 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// Retrieves all games with their respective match counts.
|
||||||
|
/// Returns a list of tuples (Game, matchCount).
|
||||||
|
Future<List<(Game, int)>> getGameUsage() async {
|
||||||
|
final games = await getAllGames();
|
||||||
|
|
||||||
|
final results = <(Game, int)>[];
|
||||||
|
|
||||||
|
for (final game in games) {
|
||||||
|
final matchCount =
|
||||||
|
await (selectOnly(db.matchTable)
|
||||||
|
..where(db.matchTable.gameId.equals(game.id))
|
||||||
|
..addColumns([db.matchTable.id.count()]))
|
||||||
|
.map((row) => row.read(db.matchTable.id.count()))
|
||||||
|
.getSingle();
|
||||||
|
|
||||||
|
results.add((game, matchCount ?? 0));
|
||||||
|
}
|
||||||
|
|
||||||
|
return results;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -341,9 +341,20 @@ class MatchDao extends DatabaseAccessor<AppDatabase> with _$MatchDaoMixin {
|
|||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// Retrieves the number of matches associated with a specific game.
|
||||||
|
Future<int> getMatchCountByGame({required String gameId}) async {
|
||||||
|
final count =
|
||||||
|
await (selectOnly(matchTable)
|
||||||
|
..where(matchTable.gameId.equals(gameId))
|
||||||
|
..addColumns([matchTable.id.count()]))
|
||||||
|
.map((row) => row.read(matchTable.id.count()))
|
||||||
|
.getSingle();
|
||||||
|
return count ?? 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
sneeex marked this conversation as resolved
sneeex
commented
würde man das nicht eher in game dao packen? weil es geht doch um games und die damit assozierten matches und nicht andersrum, das steht auch im string da falsch würde man das nicht eher in game dao packen? weil es geht doch um games und die damit assozierten matches und nicht andersrum, das steht auch im string da falsch
flixcoo
commented
Nein, ich will die Anzahl an Matches mit einer spezifischen Game-ID. Ich frage ja auch den Match Table an, deswegen ists in der matchDao Nein, ich will die Anzahl an Matches mit einer spezifischen Game-ID. Ich frage ja auch den Match Table an, deswegen ists in der matchDao
|
|||||||
/// Retrieves all matches associated with the given [groupId].
|
/// Retrieves all matches associated with the given [groupId].
|
||||||
/// Queries the database directly, filtering by [groupId].
|
/// Queries the database directly, filtering by [groupId].
|
||||||
Future<List<Match>> getGroupMatches({required String groupId}) async {
|
Future<List<Match>> getMatchesByGroup({required String groupId}) async {
|
||||||
final query = select(matchTable)..where((m) => m.groupId.equals(groupId));
|
final query = select(matchTable)..where((m) => m.groupId.equals(groupId));
|
||||||
final rows = await query.get();
|
final rows = await query.get();
|
||||||
|
|
||||||
@@ -478,4 +489,12 @@ class MatchDao extends DatabaseAccessor<AppDatabase> with _$MatchDaoMixin {
|
|||||||
final rowsAffected = await query.go();
|
final rowsAffected = await query.go();
|
||||||
return rowsAffected > 0;
|
return rowsAffected > 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// Deletes all matches associated with a specific game.
|
||||||
|
/// Returns the number of matches deleted.
|
||||||
|
Future<int> deleteMatchesByGame({required String gameId}) async {
|
||||||
|
final query = delete(matchTable)..where((m) => m.gameId.equals(gameId));
|
||||||
|
final rowsAffected = await query.go();
|
||||||
|
return rowsAffected;
|
||||||
|
}
|
||||||
|
sneeex marked this conversation as resolved
sneeex
commented
hier genauso? hier genauso?
flixcoo
commented
Ich arbeite auf der Match-Table, deswegen ists in der matchDao Ich arbeite auf der Match-Table, deswegen ists in der matchDao
|
|||||||
}
|
}
|
||||||
|
|||||||
@@ -12,16 +12,15 @@ class Game {
|
|||||||
final String icon;
|
final String icon;
|
||||||
|
|
||||||
Game({
|
Game({
|
||||||
String? id,
|
|
||||||
DateTime? createdAt,
|
|
||||||
required this.name,
|
required this.name,
|
||||||
required this.ruleset,
|
required this.ruleset,
|
||||||
String? description,
|
this.color = GameColor.orange,
|
||||||
required this.color,
|
this.description = '',
|
||||||
required this.icon,
|
this.icon = '',
|
||||||
|
String? id,
|
||||||
|
DateTime? createdAt,
|
||||||
}) : id = id ?? const Uuid().v4(),
|
}) : id = id ?? const Uuid().v4(),
|
||||||
createdAt = createdAt ?? clock.now(),
|
createdAt = createdAt ?? clock.now();
|
||||||
description = description ?? '';
|
|
||||||
|
|
||||||
@override
|
@override
|
||||||
String toString() {
|
String toString() {
|
||||||
|
|||||||
@@ -6,10 +6,21 @@
|
|||||||
"app_name": "Tallee",
|
"app_name": "Tallee",
|
||||||
"best_player": "Beste:r Spieler:in",
|
"best_player": "Beste:r Spieler:in",
|
||||||
"cancel": "Abbrechen",
|
"cancel": "Abbrechen",
|
||||||
|
"choose_color": "Farbe wählen",
|
||||||
"choose_game": "Spielvorlage wählen",
|
"choose_game": "Spielvorlage wählen",
|
||||||
"choose_group": "Gruppe wählen",
|
"choose_group": "Gruppe wählen",
|
||||||
"choose_ruleset": "Regelwerk wählen",
|
"choose_ruleset": "Regelwerk wählen",
|
||||||
|
"color": "Farbe",
|
||||||
|
"color_blue": "Blau",
|
||||||
|
"color_green": "Grün",
|
||||||
|
"color_orange": "Orange",
|
||||||
|
"color_pink": "Rosa",
|
||||||
|
"color_purple": "Lila",
|
||||||
|
"color_red": "Rot",
|
||||||
|
"color_teal": "Türkis",
|
||||||
|
"color_yellow": "Gelb",
|
||||||
"could_not_add_player": "Spieler:in {playerName} konnte nicht hinzugefügt werden",
|
"could_not_add_player": "Spieler:in {playerName} konnte nicht hinzugefügt werden",
|
||||||
|
"create_game": "Spielvorlage erstellen",
|
||||||
"create_group": "Gruppe erstellen",
|
"create_group": "Gruppe erstellen",
|
||||||
"create_match": "Spiel erstellen",
|
"create_match": "Spiel erstellen",
|
||||||
"create_new_group": "Neue Gruppe erstellen",
|
"create_new_group": "Neue Gruppe erstellen",
|
||||||
@@ -22,13 +33,25 @@
|
|||||||
"days_ago": "vor {count} Tagen",
|
"days_ago": "vor {count} Tagen",
|
||||||
"delete": "Löschen",
|
"delete": "Löschen",
|
||||||
"delete_all_data": "Alle Daten löschen",
|
"delete_all_data": "Alle Daten löschen",
|
||||||
|
"delete_game": "Spielvorlage löschen",
|
||||||
|
"delete_game_with_matches_warning": "Wenn du diese Spielvorlage löschst, {count, plural, =1{wird 1 Spiel} other{werden {count} Spiele}} mit dieser Spielvorlage ebenfalls gelöscht.",
|
||||||
|
"@delete_game_with_matches_warning": {
|
||||||
|
"placeholders": {
|
||||||
|
"count": {
|
||||||
|
"type": "int"
|
||||||
|
}
|
||||||
|
}
|
||||||
|
},
|
||||||
|
sneeex marked this conversation as resolved
sneeex
commented
im singular: werden 1 spiel gelöscht? dat passt ja net oder im singular: werden 1 spiel gelöscht? dat passt ja net oder
flixcoo
commented
fixed fixed
|
|||||||
"delete_group": "Gruppe löschen",
|
"delete_group": "Gruppe löschen",
|
||||||
"delete_match": "Spiel löschen",
|
"delete_match": "Spiel löschen",
|
||||||
|
"description": "Beschreibung",
|
||||||
|
"edit_game": "Spielvorlage bearbeiten",
|
||||||
"edit_group": "Gruppe bearbeiten",
|
"edit_group": "Gruppe bearbeiten",
|
||||||
"edit_match": "Gruppe bearbeiten",
|
"edit_match": "Gruppe bearbeiten",
|
||||||
"enter_points": "Punkte eingeben",
|
"enter_points": "Punkte eingeben",
|
||||||
"enter_results": "Ergebnisse eintragen",
|
"enter_results": "Ergebnisse eintragen",
|
||||||
"error_creating_group": "Fehler beim Erstellen der Gruppe, bitte erneut versuchen",
|
"error_creating_group": "Fehler beim Erstellen der Gruppe, bitte erneut versuchen",
|
||||||
|
"error_deleting_game": "Fehler beim Löschen der Spielvorlage, bitte erneut versuchen",
|
||||||
"error_deleting_group": "Fehler beim Löschen der Gruppe, bitte erneut versuchen",
|
"error_deleting_group": "Fehler beim Löschen der Gruppe, bitte erneut versuchen",
|
||||||
"error_editing_group": "Fehler beim Bearbeiten der Gruppe, bitte erneut versuchen",
|
"error_editing_group": "Fehler beim Bearbeiten der Gruppe, bitte erneut versuchen",
|
||||||
"error_reading_file": "Fehler beim Lesen der Datei",
|
"error_reading_file": "Fehler beim Lesen der Datei",
|
||||||
@@ -57,6 +80,7 @@
|
|||||||
"members": "Mitglieder",
|
"members": "Mitglieder",
|
||||||
"most_points": "Höchste Punkte",
|
"most_points": "Höchste Punkte",
|
||||||
"no_data_available": "Keine Daten verfügbar",
|
"no_data_available": "Keine Daten verfügbar",
|
||||||
|
"no_games_created_yet": "Noch keine Spielvorlagen erstellt",
|
||||||
"no_groups_created_yet": "Noch keine Gruppen erstellt",
|
"no_groups_created_yet": "Noch keine Gruppen erstellt",
|
||||||
"no_licenses_found": "Keine Lizenzen gefunden",
|
"no_licenses_found": "Keine Lizenzen gefunden",
|
||||||
"no_license_text_available": "Kein Lizenztext verfügbar",
|
"no_license_text_available": "Kein Lizenztext verfügbar",
|
||||||
@@ -74,7 +98,6 @@
|
|||||||
"played_matches": "Gespielte Spiele",
|
"played_matches": "Gespielte Spiele",
|
||||||
"player_name": "Spieler:innenname",
|
"player_name": "Spieler:innenname",
|
||||||
"players": "Spieler:innen",
|
"players": "Spieler:innen",
|
||||||
"players_count": "{count} Spieler",
|
|
||||||
"point": "Punkt",
|
"point": "Punkt",
|
||||||
"points": "Punkte",
|
"points": "Punkte",
|
||||||
"privacy_policy": "Datenschutzerklärung",
|
"privacy_policy": "Datenschutzerklärung",
|
||||||
@@ -103,6 +126,7 @@
|
|||||||
"statistics": "Statistiken",
|
"statistics": "Statistiken",
|
||||||
"stats": "Statistiken",
|
"stats": "Statistiken",
|
||||||
"successfully_added_player": "Spieler:in {playerName} erfolgreich hinzugefügt",
|
"successfully_added_player": "Spieler:in {playerName} erfolgreich hinzugefügt",
|
||||||
|
"there_are_no_games_matching_your_search": "Es gibt keine Spielvorlagen, die deiner Suche entspricht",
|
||||||
"there_is_no_group_matching_your_search": "Es gibt keine Gruppe, die deiner Suche entspricht",
|
"there_is_no_group_matching_your_search": "Es gibt keine Gruppe, die deiner Suche entspricht",
|
||||||
"this_cannot_be_undone": "Dies kann nicht rückgängig gemacht werden.",
|
"this_cannot_be_undone": "Dies kann nicht rückgängig gemacht werden.",
|
||||||
"tie": "Unentschieden",
|
"tie": "Unentschieden",
|
||||||
|
|||||||
@@ -1,349 +1,27 @@
|
|||||||
{
|
{
|
||||||
"@@locale": "en",
|
"@@locale": "en",
|
||||||
"@all_players": {
|
|
||||||
"description": "Label for all players list"
|
|
||||||
},
|
|
||||||
"@all_players_selected": {
|
|
||||||
"description": "Message when all players are added to selection"
|
|
||||||
},
|
|
||||||
"@amount_of_matches": {
|
|
||||||
"description": "Label for amount of matches statistic"
|
|
||||||
},
|
|
||||||
"@app_name": {
|
|
||||||
"description": "The name of the App"
|
|
||||||
},
|
|
||||||
"@best_player": {
|
|
||||||
"description": "Label for best player statistic"
|
|
||||||
},
|
|
||||||
"@cancel": {
|
|
||||||
"description": "Cancel button text"
|
|
||||||
},
|
|
||||||
"@choose_game": {
|
|
||||||
"description": "Label for choosing a game"
|
|
||||||
},
|
|
||||||
"@choose_group": {
|
|
||||||
"description": "Label for choosing a group"
|
|
||||||
},
|
|
||||||
"@choose_ruleset": {
|
|
||||||
"description": "Label for choosing a ruleset"
|
|
||||||
},
|
|
||||||
"@could_not_add_player": {
|
|
||||||
"description": "Error message when adding a player fails"
|
|
||||||
},
|
|
||||||
"@create_group": {
|
|
||||||
"description": "Button text to create a group"
|
|
||||||
},
|
|
||||||
"@create_match": {
|
|
||||||
"description": "Button text to create a match"
|
|
||||||
},
|
|
||||||
"@create_new_group": {
|
|
||||||
"description": "Appbar text to create a new group"
|
|
||||||
},
|
|
||||||
"@create_new_match": {
|
|
||||||
"description": "Appbar text to create a new match"
|
|
||||||
},
|
|
||||||
"@created_on": {
|
|
||||||
"description": "Label for creation date"
|
|
||||||
},
|
|
||||||
"@data": {
|
|
||||||
"description": "Data label"
|
|
||||||
},
|
|
||||||
"@data_successfully_deleted": {
|
|
||||||
"description": "Success message after deleting data"
|
|
||||||
},
|
|
||||||
"@data_successfully_exported": {
|
|
||||||
"description": "Success message after exporting data"
|
|
||||||
},
|
|
||||||
"@data_successfully_imported": {
|
|
||||||
"description": "Success message after importing data"
|
|
||||||
},
|
|
||||||
"@days_ago": {
|
|
||||||
"description": "Date format for days ago",
|
|
||||||
"placeholders": {
|
|
||||||
"count": {
|
|
||||||
"type": "int"
|
|
||||||
}
|
|
||||||
}
|
|
||||||
},
|
|
||||||
"@delete": {
|
|
||||||
"description": "Delete button text"
|
|
||||||
},
|
|
||||||
"@delete_all_data": {
|
|
||||||
"description": "Confirmation dialog for deleting all data"
|
|
||||||
},
|
|
||||||
"@delete_group": {
|
|
||||||
"description": "Confirmation dialog for deleting a group"
|
|
||||||
},
|
|
||||||
"@delete_match": {
|
|
||||||
"description": "Button text to delete a match"
|
|
||||||
},
|
|
||||||
"@edit_group": {
|
|
||||||
"description": "Button & Appbar label for editing a group"
|
|
||||||
},
|
|
||||||
"@edit_match": {
|
|
||||||
"description": "Button & Appbar label for editing a match"
|
|
||||||
},
|
|
||||||
"@enter_points": {
|
|
||||||
"description": "Label to enter players points"
|
|
||||||
},
|
|
||||||
"@enter_results": {
|
|
||||||
"description": "Button text to enter match results"
|
|
||||||
},
|
|
||||||
"@error_creating_group": {
|
|
||||||
"description": "Error message when group creation fails"
|
|
||||||
},
|
|
||||||
"@error_deleting_group": {
|
|
||||||
"description": "Error message when group deletion fails"
|
|
||||||
},
|
|
||||||
"@error_editing_group": {
|
|
||||||
"description": "Error message when group editing fails"
|
|
||||||
},
|
|
||||||
"@error_reading_file": {
|
|
||||||
"description": "Error message when file cannot be read"
|
|
||||||
},
|
|
||||||
"@export_canceled": {
|
|
||||||
"description": "Message when export is canceled"
|
|
||||||
},
|
|
||||||
"@export_data": {
|
|
||||||
"description": "Export data menu item"
|
|
||||||
},
|
|
||||||
"@format_exception": {
|
|
||||||
"description": "Error message for format exceptions"
|
|
||||||
},
|
|
||||||
"@game": {
|
|
||||||
"description": "Game label"
|
|
||||||
},
|
|
||||||
"@game_name": {
|
|
||||||
"description": "Placeholder for game name search"
|
|
||||||
},
|
|
||||||
"@group": {
|
|
||||||
"description": "Group label"
|
|
||||||
},
|
|
||||||
"@group_name": {
|
|
||||||
"description": "Placeholder for group name input"
|
|
||||||
},
|
|
||||||
"@group_profile": {
|
|
||||||
"description": "Title for group profile view"
|
|
||||||
},
|
|
||||||
"@groups": {
|
|
||||||
"description": "Label for groups"
|
|
||||||
},
|
|
||||||
"@home": {
|
|
||||||
"description": "Home tab label"
|
|
||||||
},
|
|
||||||
"@import_canceled": {
|
|
||||||
"description": "Message when import is canceled"
|
|
||||||
},
|
|
||||||
"@import_data": {
|
|
||||||
"description": "Import data menu item"
|
|
||||||
},
|
|
||||||
"@info": {
|
|
||||||
"description": "Info label"
|
|
||||||
},
|
|
||||||
"@invalid_schema": {
|
|
||||||
"description": "Error message for invalid schema"
|
|
||||||
},
|
|
||||||
"@least_points": {
|
|
||||||
"description": "Title for least points ruleset"
|
|
||||||
},
|
|
||||||
"@legal": {
|
|
||||||
"description": "Legal section header"
|
|
||||||
},
|
|
||||||
"@legal_notice": {
|
|
||||||
"description": "Legal notice menu item"
|
|
||||||
},
|
|
||||||
"@licenses": {
|
|
||||||
"description": "Licenses menu item"
|
|
||||||
},
|
|
||||||
"@match_in_progress": {
|
|
||||||
"description": "Message when match is in progress"
|
|
||||||
},
|
|
||||||
"@match_name": {
|
|
||||||
"description": "Placeholder for match name input"
|
|
||||||
},
|
|
||||||
"@match_profile": {
|
|
||||||
"description": "Title for match profile view"
|
|
||||||
},
|
|
||||||
"@matches": {
|
|
||||||
"description": "Label for matches"
|
|
||||||
},
|
|
||||||
"@members": {
|
|
||||||
"description": "Label for group members"
|
|
||||||
},
|
|
||||||
"@most_points": {
|
|
||||||
"description": "Title for most points ruleset"
|
|
||||||
},
|
|
||||||
"@no_data_available": {
|
|
||||||
"description": "Message when no data in the statistic tiles is given"
|
|
||||||
},
|
|
||||||
"@no_groups_created_yet": {
|
|
||||||
"description": "Message when no groups exist"
|
|
||||||
},
|
|
||||||
"@no_licenses_found": {
|
|
||||||
"description": "Message when no licenses are found"
|
|
||||||
},
|
|
||||||
"@no_license_text_available": {
|
|
||||||
"description": "Message when no license text is available"
|
|
||||||
},
|
|
||||||
"@no_matches_created_yet": {
|
|
||||||
"description": "Message when no matches exist"
|
|
||||||
},
|
|
||||||
"@no_players_created_yet": {
|
|
||||||
"description": "Message when no players exist"
|
|
||||||
},
|
|
||||||
"@no_players_found_with_that_name": {
|
|
||||||
"description": "Message when search returns no results"
|
|
||||||
},
|
|
||||||
"@no_players_selected": {
|
|
||||||
"description": "Message when no players are selected"
|
|
||||||
},
|
|
||||||
"@no_recent_matches_available": {
|
|
||||||
"description": "Message when no recent matches exist"
|
|
||||||
},
|
|
||||||
"@no_results_entered_yet": {
|
|
||||||
"description": "Message when no results have been entered yet"
|
|
||||||
},
|
|
||||||
"@no_second_match_available": {
|
|
||||||
"description": "Message when no second match exists"
|
|
||||||
},
|
|
||||||
"@no_statistics_available": {
|
|
||||||
"description": "Message when no statistics are available, because no matches were played yet"
|
|
||||||
},
|
|
||||||
"@none": {
|
|
||||||
"description": "None option label"
|
|
||||||
},
|
|
||||||
"@none_group": {
|
|
||||||
"description": "None group option label"
|
|
||||||
},
|
|
||||||
"@not_available": {
|
|
||||||
"description": "Abbreviation for not available"
|
|
||||||
},
|
|
||||||
"@played_matches": {
|
|
||||||
"description": "Label for played matches statistic"
|
|
||||||
},
|
|
||||||
"@player_name": {
|
|
||||||
"description": "Placeholder for player name input"
|
|
||||||
},
|
|
||||||
"@players": {
|
|
||||||
"description": "Players label"
|
|
||||||
},
|
|
||||||
"@players_count": {
|
|
||||||
"description": "Shows the number of players",
|
|
||||||
"placeholders": {
|
|
||||||
"count": {
|
|
||||||
"type": "int"
|
|
||||||
}
|
|
||||||
}
|
|
||||||
},
|
|
||||||
"@points": {
|
|
||||||
"description": "Points label"
|
|
||||||
},
|
|
||||||
"@privacy_policy": {
|
|
||||||
"description": "Privacy policy menu item"
|
|
||||||
},
|
|
||||||
"@quick_create": {
|
|
||||||
"description": "Title for quick create section"
|
|
||||||
},
|
|
||||||
"@recent_matches": {
|
|
||||||
"description": "Title for recent matches section"
|
|
||||||
},
|
|
||||||
"@results": {
|
|
||||||
"description": "Label for match results"
|
|
||||||
},
|
|
||||||
"@ruleset": {
|
|
||||||
"description": "Ruleset label"
|
|
||||||
},
|
|
||||||
"@ruleset_least_points": {
|
|
||||||
"description": "Description for least points ruleset"
|
|
||||||
},
|
|
||||||
"@ruleset_most_points": {
|
|
||||||
"description": "Description for most points ruleset"
|
|
||||||
},
|
|
||||||
"@ruleset_single_loser": {
|
|
||||||
"description": "Description for single loser ruleset"
|
|
||||||
},
|
|
||||||
"@ruleset_single_winner": {
|
|
||||||
"description": "Description for single winner ruleset"
|
|
||||||
},
|
|
||||||
"@save_changes": {
|
|
||||||
"description": "Save changes button text"
|
|
||||||
},
|
|
||||||
"@search_for_groups": {
|
|
||||||
"description": "Hint text for group search input field"
|
|
||||||
},
|
|
||||||
"@search_for_players": {
|
|
||||||
"description": "Hint text for player search input field"
|
|
||||||
},
|
|
||||||
"@select_winner": {
|
|
||||||
"description": "Label to select the winner"
|
|
||||||
},
|
|
||||||
"@select_loser": {
|
|
||||||
"description": "Label to select the loser"
|
|
||||||
},
|
|
||||||
"@selected_players": {
|
|
||||||
"description": "Shows the number of selected players"
|
|
||||||
},
|
|
||||||
"@settings": {
|
|
||||||
"description": "Label for the App Settings"
|
|
||||||
},
|
|
||||||
"@single_loser": {
|
|
||||||
"description": "Title for single loser ruleset"
|
|
||||||
},
|
|
||||||
"@single_winner": {
|
|
||||||
"description": "Title for single winner ruleset"
|
|
||||||
},
|
|
||||||
"@statistics": {
|
|
||||||
"description": "Statistics tab label"
|
|
||||||
},
|
|
||||||
"@stats": {
|
|
||||||
"description": "Stats tab label (short)"
|
|
||||||
},
|
|
||||||
"@successfully_added_player": {
|
|
||||||
"description": "Success message when adding a player",
|
|
||||||
"placeholders": {
|
|
||||||
"playerName": {
|
|
||||||
"type": "String",
|
|
||||||
"example": "John"
|
|
||||||
}
|
|
||||||
}
|
|
||||||
},
|
|
||||||
"@there_is_no_group_matching_your_search": {
|
|
||||||
"description": "Message when search returns no groups"
|
|
||||||
},
|
|
||||||
"@this_cannot_be_undone": {
|
|
||||||
"description": "Warning message for irreversible actions"
|
|
||||||
},
|
|
||||||
"@today_at": {
|
|
||||||
"description": "Date format for today"
|
|
||||||
},
|
|
||||||
"@undo": {
|
|
||||||
"description": "Undo button text"
|
|
||||||
},
|
|
||||||
"@unknown_exception": {
|
|
||||||
"description": "Error message for unknown exceptions"
|
|
||||||
},
|
|
||||||
"@winner": {
|
|
||||||
"description": "Winner label"
|
|
||||||
},
|
|
||||||
"@winrate": {
|
|
||||||
"description": "Label for winrate statistic"
|
|
||||||
},
|
|
||||||
"@wins": {
|
|
||||||
"description": "Label for wins statistic"
|
|
||||||
},
|
|
||||||
"@yesterday_at": {
|
|
||||||
"description": "Date format for yesterday"
|
|
||||||
},
|
|
||||||
"all_players": "All players",
|
"all_players": "All players",
|
||||||
"all_players_selected": "All players selected",
|
"all_players_selected": "All players selected",
|
||||||
"amount_of_matches": "Amount of Matches",
|
"amount_of_matches": "Amount of Matches",
|
||||||
"app_name": "Tallee",
|
"app_name": "Tallee",
|
||||||
"best_player": "Best Player",
|
"best_player": "Best Player",
|
||||||
"cancel": "Cancel",
|
"cancel": "Cancel",
|
||||||
|
"choose_color": "Choose Color",
|
||||||
"choose_game": "Choose Game",
|
"choose_game": "Choose Game",
|
||||||
"choose_group": "Choose Group",
|
"choose_group": "Choose Group",
|
||||||
"choose_ruleset": "Choose Ruleset",
|
"choose_ruleset": "Choose Ruleset",
|
||||||
|
"color": "Color",
|
||||||
|
"color_blue": "Blue",
|
||||||
|
"color_green": "Green",
|
||||||
|
"color_orange": "Orange",
|
||||||
|
"color_pink": "Pink",
|
||||||
|
"color_purple": "Purple",
|
||||||
|
"color_red": "Red",
|
||||||
|
"color_teal": "Teal",
|
||||||
|
"color_yellow": "Yellow",
|
||||||
"could_not_add_player": "Could not add player",
|
"could_not_add_player": "Could not add player",
|
||||||
|
"create_game": "Create Game",
|
||||||
"create_group": "Create Group",
|
"create_group": "Create Group",
|
||||||
"create_match": "Create match",
|
"create_match": "Create match",
|
||||||
"create_new_group": "Create new group",
|
"create_new_group": "Create new group",
|
||||||
@@ -356,13 +34,25 @@
|
|||||||
"days_ago": "{count} days ago",
|
"days_ago": "{count} days ago",
|
||||||
"delete": "Delete",
|
"delete": "Delete",
|
||||||
"delete_all_data": "Delete all data",
|
"delete_all_data": "Delete all data",
|
||||||
|
"delete_game": "Delete Game",
|
||||||
|
"delete_game_with_matches_warning": "If you delete this game template, {count, plural, =1{1 match} other{{count} matches}} using this game template will also be deleted.",
|
||||||
|
"@delete_game_with_matches_warning": {
|
||||||
|
"placeholders": {
|
||||||
|
"count": {
|
||||||
|
"type": "int"
|
||||||
|
}
|
||||||
|
}
|
||||||
|
},
|
||||||
"delete_group": "Delete Group",
|
"delete_group": "Delete Group",
|
||||||
"delete_match": "Delete Match",
|
"delete_match": "Delete Match",
|
||||||
|
"description": "Description",
|
||||||
|
"edit_game": "Edit Game",
|
||||||
"edit_group": "Edit Group",
|
"edit_group": "Edit Group",
|
||||||
"edit_match": "Edit Match",
|
"edit_match": "Edit Match",
|
||||||
"enter_points": "Enter points",
|
"enter_points": "Enter points",
|
||||||
"enter_results": "Enter Results",
|
"enter_results": "Enter Results",
|
||||||
"error_creating_group": "Error while creating group, please try again",
|
"error_creating_group": "Error while creating group, please try again",
|
||||||
|
"error_deleting_game": "Error while deleting game, please try again",
|
||||||
"error_deleting_group": "Error while deleting group, please try again",
|
"error_deleting_group": "Error while deleting group, please try again",
|
||||||
"error_editing_group": "Error while editing group, please try again",
|
"error_editing_group": "Error while editing group, please try again",
|
||||||
"error_reading_file": "Error reading file",
|
"error_reading_file": "Error reading file",
|
||||||
@@ -391,6 +81,7 @@
|
|||||||
"members": "Members",
|
"members": "Members",
|
||||||
"most_points": "Most Points",
|
"most_points": "Most Points",
|
||||||
"no_data_available": "No data available",
|
"no_data_available": "No data available",
|
||||||
|
"no_games_created_yet": "No games created yet",
|
||||||
"no_groups_created_yet": "No groups created yet",
|
"no_groups_created_yet": "No groups created yet",
|
||||||
"no_licenses_found": "No licenses found",
|
"no_licenses_found": "No licenses found",
|
||||||
"no_license_text_available": "No license text available",
|
"no_license_text_available": "No license text available",
|
||||||
@@ -408,7 +99,6 @@
|
|||||||
"played_matches": "Played Matches",
|
"played_matches": "Played Matches",
|
||||||
"player_name": "Player name",
|
"player_name": "Player name",
|
||||||
"players": "Players",
|
"players": "Players",
|
||||||
"players_count": "{count} Players",
|
|
||||||
"point": "Point",
|
"point": "Point",
|
||||||
"points": "Points",
|
"points": "Points",
|
||||||
"privacy_policy": "Privacy Policy",
|
"privacy_policy": "Privacy Policy",
|
||||||
@@ -436,6 +126,16 @@
|
|||||||
"statistics": "Statistics",
|
"statistics": "Statistics",
|
||||||
"stats": "Stats",
|
"stats": "Stats",
|
||||||
"successfully_added_player": "Successfully added player {playerName}",
|
"successfully_added_player": "Successfully added player {playerName}",
|
||||||
|
"@successfully_added_player": {
|
||||||
|
"description": "Success message when adding a player",
|
||||||
|
"placeholders": {
|
||||||
|
"playerName": {
|
||||||
|
"type": "String",
|
||||||
|
"example": "John"
|
||||||
|
}
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"there_are_no_games_matching_your_search": "There are no games matching your search",
|
||||||
"there_is_no_group_matching_your_search": "There is no group matching your search",
|
"there_is_no_group_matching_your_search": "There is no group matching your search",
|
||||||
"this_cannot_be_undone": "This can't be undone.",
|
"this_cannot_be_undone": "This can't be undone.",
|
||||||
"tie": "Tie",
|
"tie": "Tie",
|
||||||
|
|||||||
@@ -98,571 +98,667 @@ abstract class AppLocalizations {
|
|||||||
Locale('en'),
|
Locale('en'),
|
||||||
];
|
];
|
||||||
|
|
||||||
/// Label for all players list
|
/// No description provided for @all_players.
|
||||||
///
|
///
|
||||||
/// In en, this message translates to:
|
/// In en, this message translates to:
|
||||||
/// **'All players'**
|
/// **'All players'**
|
||||||
String get all_players;
|
String get all_players;
|
||||||
|
|
||||||
/// Message when all players are added to selection
|
/// No description provided for @all_players_selected.
|
||||||
///
|
///
|
||||||
/// In en, this message translates to:
|
/// In en, this message translates to:
|
||||||
/// **'All players selected'**
|
/// **'All players selected'**
|
||||||
String get all_players_selected;
|
String get all_players_selected;
|
||||||
|
|
||||||
/// Label for amount of matches statistic
|
/// No description provided for @amount_of_matches.
|
||||||
///
|
///
|
||||||
/// In en, this message translates to:
|
/// In en, this message translates to:
|
||||||
/// **'Amount of Matches'**
|
/// **'Amount of Matches'**
|
||||||
String get amount_of_matches;
|
String get amount_of_matches;
|
||||||
|
|
||||||
/// The name of the App
|
/// No description provided for @app_name.
|
||||||
///
|
///
|
||||||
/// In en, this message translates to:
|
/// In en, this message translates to:
|
||||||
/// **'Tallee'**
|
/// **'Tallee'**
|
||||||
String get app_name;
|
String get app_name;
|
||||||
|
|
||||||
/// Label for best player statistic
|
/// No description provided for @best_player.
|
||||||
///
|
///
|
||||||
/// In en, this message translates to:
|
/// In en, this message translates to:
|
||||||
/// **'Best Player'**
|
/// **'Best Player'**
|
||||||
String get best_player;
|
String get best_player;
|
||||||
|
|
||||||
/// Cancel button text
|
/// No description provided for @cancel.
|
||||||
///
|
///
|
||||||
/// In en, this message translates to:
|
/// In en, this message translates to:
|
||||||
/// **'Cancel'**
|
/// **'Cancel'**
|
||||||
String get cancel;
|
String get cancel;
|
||||||
|
|
||||||
/// Label for choosing a game
|
/// No description provided for @choose_color.
|
||||||
|
///
|
||||||
|
/// In en, this message translates to:
|
||||||
|
/// **'Choose Color'**
|
||||||
|
String get choose_color;
|
||||||
|
|
||||||
|
/// No description provided for @choose_game.
|
||||||
///
|
///
|
||||||
/// In en, this message translates to:
|
/// In en, this message translates to:
|
||||||
/// **'Choose Game'**
|
/// **'Choose Game'**
|
||||||
String get choose_game;
|
String get choose_game;
|
||||||
|
|
||||||
/// Label for choosing a group
|
/// No description provided for @choose_group.
|
||||||
///
|
///
|
||||||
/// In en, this message translates to:
|
/// In en, this message translates to:
|
||||||
/// **'Choose Group'**
|
/// **'Choose Group'**
|
||||||
String get choose_group;
|
String get choose_group;
|
||||||
|
|
||||||
/// Label for choosing a ruleset
|
/// No description provided for @choose_ruleset.
|
||||||
///
|
///
|
||||||
/// In en, this message translates to:
|
/// In en, this message translates to:
|
||||||
/// **'Choose Ruleset'**
|
/// **'Choose Ruleset'**
|
||||||
String get choose_ruleset;
|
String get choose_ruleset;
|
||||||
|
|
||||||
/// Error message when adding a player fails
|
/// No description provided for @color.
|
||||||
|
///
|
||||||
|
/// In en, this message translates to:
|
||||||
|
/// **'Color'**
|
||||||
|
String get color;
|
||||||
|
|
||||||
|
/// No description provided for @color_blue.
|
||||||
|
flixcoo marked this conversation as resolved
gelbeinhalb
commented
sind die descriptions hier nicht mies unnötig? sind die descriptions hier nicht mies unnötig?
flixcoo
commented
ja, ich entfern die mal ja, ich entfern die mal
|
|||||||
|
///
|
||||||
|
/// In en, this message translates to:
|
||||||
|
/// **'Blue'**
|
||||||
|
String get color_blue;
|
||||||
|
|
||||||
|
/// No description provided for @color_green.
|
||||||
|
///
|
||||||
|
/// In en, this message translates to:
|
||||||
|
/// **'Green'**
|
||||||
|
String get color_green;
|
||||||
|
|
||||||
|
/// No description provided for @color_orange.
|
||||||
|
///
|
||||||
|
/// In en, this message translates to:
|
||||||
|
/// **'Orange'**
|
||||||
|
String get color_orange;
|
||||||
|
|
||||||
|
/// No description provided for @color_pink.
|
||||||
|
///
|
||||||
|
/// In en, this message translates to:
|
||||||
|
/// **'Pink'**
|
||||||
|
String get color_pink;
|
||||||
|
|
||||||
|
/// No description provided for @color_purple.
|
||||||
|
///
|
||||||
|
/// In en, this message translates to:
|
||||||
|
/// **'Purple'**
|
||||||
|
String get color_purple;
|
||||||
|
|
||||||
|
/// No description provided for @color_red.
|
||||||
|
///
|
||||||
|
/// In en, this message translates to:
|
||||||
|
/// **'Red'**
|
||||||
|
String get color_red;
|
||||||
|
|
||||||
|
/// No description provided for @color_teal.
|
||||||
|
///
|
||||||
|
/// In en, this message translates to:
|
||||||
|
/// **'Teal'**
|
||||||
|
String get color_teal;
|
||||||
|
|
||||||
|
/// No description provided for @color_yellow.
|
||||||
|
///
|
||||||
|
/// In en, this message translates to:
|
||||||
|
/// **'Yellow'**
|
||||||
|
String get color_yellow;
|
||||||
|
|
||||||
|
/// No description provided for @could_not_add_player.
|
||||||
///
|
///
|
||||||
/// In en, this message translates to:
|
/// In en, this message translates to:
|
||||||
/// **'Could not add player'**
|
/// **'Could not add player'**
|
||||||
String could_not_add_player(Object playerName);
|
String could_not_add_player(Object playerName);
|
||||||
|
|
||||||
/// Button text to create a group
|
/// No description provided for @create_game.
|
||||||
|
///
|
||||||
|
/// In en, this message translates to:
|
||||||
|
/// **'Create Game'**
|
||||||
|
String get create_game;
|
||||||
|
|
||||||
|
/// No description provided for @create_group.
|
||||||
///
|
///
|
||||||
/// In en, this message translates to:
|
/// In en, this message translates to:
|
||||||
/// **'Create Group'**
|
/// **'Create Group'**
|
||||||
String get create_group;
|
String get create_group;
|
||||||
|
|
||||||
/// Button text to create a match
|
/// No description provided for @create_match.
|
||||||
///
|
///
|
||||||
/// In en, this message translates to:
|
/// In en, this message translates to:
|
||||||
/// **'Create match'**
|
/// **'Create match'**
|
||||||
String get create_match;
|
String get create_match;
|
||||||
|
|
||||||
/// Appbar text to create a new group
|
/// No description provided for @create_new_group.
|
||||||
///
|
///
|
||||||
/// In en, this message translates to:
|
/// In en, this message translates to:
|
||||||
/// **'Create new group'**
|
/// **'Create new group'**
|
||||||
String get create_new_group;
|
String get create_new_group;
|
||||||
|
|
||||||
/// Label for creation date
|
/// No description provided for @created_on.
|
||||||
///
|
///
|
||||||
/// In en, this message translates to:
|
/// In en, this message translates to:
|
||||||
/// **'Created on'**
|
/// **'Created on'**
|
||||||
String get created_on;
|
String get created_on;
|
||||||
|
|
||||||
/// Appbar text to create a new match
|
/// No description provided for @create_new_match.
|
||||||
///
|
///
|
||||||
/// In en, this message translates to:
|
/// In en, this message translates to:
|
||||||
/// **'Create new match'**
|
/// **'Create new match'**
|
||||||
String get create_new_match;
|
String get create_new_match;
|
||||||
|
|
||||||
/// Data label
|
/// No description provided for @data.
|
||||||
///
|
///
|
||||||
/// In en, this message translates to:
|
/// In en, this message translates to:
|
||||||
/// **'Data'**
|
/// **'Data'**
|
||||||
String get data;
|
String get data;
|
||||||
|
|
||||||
/// Success message after deleting data
|
/// No description provided for @data_successfully_deleted.
|
||||||
///
|
///
|
||||||
/// In en, this message translates to:
|
/// In en, this message translates to:
|
||||||
/// **'Data successfully deleted'**
|
/// **'Data successfully deleted'**
|
||||||
String get data_successfully_deleted;
|
String get data_successfully_deleted;
|
||||||
|
|
||||||
/// Success message after exporting data
|
/// No description provided for @data_successfully_exported.
|
||||||
///
|
///
|
||||||
/// In en, this message translates to:
|
/// In en, this message translates to:
|
||||||
/// **'Data successfully exported'**
|
/// **'Data successfully exported'**
|
||||||
String get data_successfully_exported;
|
String get data_successfully_exported;
|
||||||
|
|
||||||
/// Success message after importing data
|
/// No description provided for @data_successfully_imported.
|
||||||
///
|
///
|
||||||
/// In en, this message translates to:
|
/// In en, this message translates to:
|
||||||
/// **'Data successfully imported'**
|
/// **'Data successfully imported'**
|
||||||
String get data_successfully_imported;
|
String get data_successfully_imported;
|
||||||
|
|
||||||
/// Date format for days ago
|
/// No description provided for @days_ago.
|
||||||
///
|
///
|
||||||
/// In en, this message translates to:
|
/// In en, this message translates to:
|
||||||
/// **'{count} days ago'**
|
/// **'{count} days ago'**
|
||||||
String days_ago(int count);
|
String days_ago(Object count);
|
||||||
|
|
||||||
/// Delete button text
|
/// No description provided for @delete.
|
||||||
///
|
///
|
||||||
/// In en, this message translates to:
|
/// In en, this message translates to:
|
||||||
/// **'Delete'**
|
/// **'Delete'**
|
||||||
String get delete;
|
String get delete;
|
||||||
|
|
||||||
/// Confirmation dialog for deleting all data
|
/// No description provided for @delete_all_data.
|
||||||
///
|
///
|
||||||
/// In en, this message translates to:
|
/// In en, this message translates to:
|
||||||
/// **'Delete all data'**
|
/// **'Delete all data'**
|
||||||
String get delete_all_data;
|
String get delete_all_data;
|
||||||
|
|
||||||
/// Confirmation dialog for deleting a group
|
/// No description provided for @delete_game.
|
||||||
|
///
|
||||||
|
/// In en, this message translates to:
|
||||||
|
/// **'Delete Game'**
|
||||||
|
String get delete_game;
|
||||||
|
|
||||||
|
/// No description provided for @delete_game_with_matches_warning.
|
||||||
|
///
|
||||||
|
/// In en, this message translates to:
|
||||||
|
/// **'If you delete this game template, {count, plural, =1{1 match} other{{count} matches}} using this game template will also be deleted.'**
|
||||||
|
String delete_game_with_matches_warning(int count);
|
||||||
|
|
||||||
|
/// No description provided for @delete_group.
|
||||||
///
|
///
|
||||||
/// In en, this message translates to:
|
/// In en, this message translates to:
|
||||||
/// **'Delete Group'**
|
/// **'Delete Group'**
|
||||||
String get delete_group;
|
String get delete_group;
|
||||||
|
|
||||||
/// Button text to delete a match
|
/// No description provided for @delete_match.
|
||||||
///
|
///
|
||||||
/// In en, this message translates to:
|
/// In en, this message translates to:
|
||||||
/// **'Delete Match'**
|
/// **'Delete Match'**
|
||||||
String get delete_match;
|
String get delete_match;
|
||||||
|
|
||||||
/// Button & Appbar label for editing a group
|
/// No description provided for @description.
|
||||||
|
///
|
||||||
|
/// In en, this message translates to:
|
||||||
|
/// **'Description'**
|
||||||
|
String get description;
|
||||||
|
|
||||||
|
/// No description provided for @edit_game.
|
||||||
|
///
|
||||||
|
/// In en, this message translates to:
|
||||||
|
/// **'Edit Game'**
|
||||||
|
String get edit_game;
|
||||||
|
|
||||||
|
/// No description provided for @edit_group.
|
||||||
///
|
///
|
||||||
/// In en, this message translates to:
|
/// In en, this message translates to:
|
||||||
/// **'Edit Group'**
|
/// **'Edit Group'**
|
||||||
String get edit_group;
|
String get edit_group;
|
||||||
|
|
||||||
/// Button & Appbar label for editing a match
|
/// No description provided for @edit_match.
|
||||||
///
|
///
|
||||||
/// In en, this message translates to:
|
/// In en, this message translates to:
|
||||||
/// **'Edit Match'**
|
/// **'Edit Match'**
|
||||||
String get edit_match;
|
String get edit_match;
|
||||||
|
|
||||||
/// Label to enter players points
|
/// No description provided for @enter_points.
|
||||||
///
|
///
|
||||||
/// In en, this message translates to:
|
/// In en, this message translates to:
|
||||||
/// **'Enter points'**
|
/// **'Enter points'**
|
||||||
String get enter_points;
|
String get enter_points;
|
||||||
|
|
||||||
/// Button text to enter match results
|
/// No description provided for @enter_results.
|
||||||
///
|
///
|
||||||
/// In en, this message translates to:
|
/// In en, this message translates to:
|
||||||
/// **'Enter Results'**
|
/// **'Enter Results'**
|
||||||
String get enter_results;
|
String get enter_results;
|
||||||
|
|
||||||
/// Error message when group creation fails
|
/// No description provided for @error_creating_group.
|
||||||
///
|
///
|
||||||
/// In en, this message translates to:
|
/// In en, this message translates to:
|
||||||
/// **'Error while creating group, please try again'**
|
/// **'Error while creating group, please try again'**
|
||||||
String get error_creating_group;
|
String get error_creating_group;
|
||||||
|
|
||||||
/// Error message when group deletion fails
|
/// No description provided for @error_deleting_game.
|
||||||
|
flixcoo marked this conversation as resolved
Outdated
gelbeinhalb
commented
bitte weniger vibe coden felix 🤓 🫵 bitte weniger vibe coden felix 🤓 🫵
flixcoo
commented
hä was meinst du? :D hä was meinst du? :D
|
|||||||
|
///
|
||||||
|
/// In en, this message translates to:
|
||||||
|
/// **'Error while deleting game, please try again'**
|
||||||
|
String get error_deleting_game;
|
||||||
|
|
||||||
|
/// No description provided for @error_deleting_group.
|
||||||
///
|
///
|
||||||
/// In en, this message translates to:
|
/// In en, this message translates to:
|
||||||
/// **'Error while deleting group, please try again'**
|
/// **'Error while deleting group, please try again'**
|
||||||
String get error_deleting_group;
|
String get error_deleting_group;
|
||||||
|
|
||||||
/// Error message when group editing fails
|
/// No description provided for @error_editing_group.
|
||||||
///
|
///
|
||||||
/// In en, this message translates to:
|
/// In en, this message translates to:
|
||||||
/// **'Error while editing group, please try again'**
|
/// **'Error while editing group, please try again'**
|
||||||
String get error_editing_group;
|
String get error_editing_group;
|
||||||
|
|
||||||
/// Error message when file cannot be read
|
/// No description provided for @error_reading_file.
|
||||||
///
|
///
|
||||||
/// In en, this message translates to:
|
/// In en, this message translates to:
|
||||||
/// **'Error reading file'**
|
/// **'Error reading file'**
|
||||||
String get error_reading_file;
|
String get error_reading_file;
|
||||||
|
|
||||||
/// Message when export is canceled
|
/// No description provided for @export_canceled.
|
||||||
///
|
///
|
||||||
/// In en, this message translates to:
|
/// In en, this message translates to:
|
||||||
/// **'Export canceled'**
|
/// **'Export canceled'**
|
||||||
String get export_canceled;
|
String get export_canceled;
|
||||||
|
|
||||||
/// Export data menu item
|
/// No description provided for @export_data.
|
||||||
///
|
///
|
||||||
/// In en, this message translates to:
|
/// In en, this message translates to:
|
||||||
/// **'Export data'**
|
/// **'Export data'**
|
||||||
String get export_data;
|
String get export_data;
|
||||||
|
|
||||||
/// Error message for format exceptions
|
/// No description provided for @format_exception.
|
||||||
///
|
///
|
||||||
/// In en, this message translates to:
|
/// In en, this message translates to:
|
||||||
/// **'Format Exception (see console)'**
|
/// **'Format Exception (see console)'**
|
||||||
String get format_exception;
|
String get format_exception;
|
||||||
|
|
||||||
/// Game label
|
/// No description provided for @game.
|
||||||
///
|
///
|
||||||
/// In en, this message translates to:
|
/// In en, this message translates to:
|
||||||
/// **'Game'**
|
/// **'Game'**
|
||||||
String get game;
|
String get game;
|
||||||
|
|
||||||
/// Placeholder for game name search
|
/// No description provided for @game_name.
|
||||||
///
|
///
|
||||||
/// In en, this message translates to:
|
/// In en, this message translates to:
|
||||||
/// **'Game Name'**
|
/// **'Game Name'**
|
||||||
String get game_name;
|
String get game_name;
|
||||||
|
|
||||||
/// Group label
|
/// No description provided for @group.
|
||||||
///
|
///
|
||||||
/// In en, this message translates to:
|
/// In en, this message translates to:
|
||||||
/// **'Group'**
|
/// **'Group'**
|
||||||
String get group;
|
String get group;
|
||||||
|
|
||||||
/// Placeholder for group name input
|
/// No description provided for @group_name.
|
||||||
///
|
///
|
||||||
/// In en, this message translates to:
|
/// In en, this message translates to:
|
||||||
/// **'Group name'**
|
/// **'Group name'**
|
||||||
String get group_name;
|
String get group_name;
|
||||||
|
|
||||||
/// Title for group profile view
|
/// No description provided for @group_profile.
|
||||||
///
|
///
|
||||||
/// In en, this message translates to:
|
/// In en, this message translates to:
|
||||||
/// **'Group Profile'**
|
/// **'Group Profile'**
|
||||||
String get group_profile;
|
String get group_profile;
|
||||||
|
|
||||||
/// Label for groups
|
/// No description provided for @groups.
|
||||||
///
|
///
|
||||||
/// In en, this message translates to:
|
/// In en, this message translates to:
|
||||||
/// **'Groups'**
|
/// **'Groups'**
|
||||||
String get groups;
|
String get groups;
|
||||||
|
|
||||||
/// Home tab label
|
/// No description provided for @home.
|
||||||
///
|
///
|
||||||
/// In en, this message translates to:
|
/// In en, this message translates to:
|
||||||
/// **'Home'**
|
/// **'Home'**
|
||||||
String get home;
|
String get home;
|
||||||
|
|
||||||
/// Message when import is canceled
|
/// No description provided for @import_canceled.
|
||||||
///
|
///
|
||||||
/// In en, this message translates to:
|
/// In en, this message translates to:
|
||||||
/// **'Import canceled'**
|
/// **'Import canceled'**
|
||||||
String get import_canceled;
|
String get import_canceled;
|
||||||
|
|
||||||
/// Import data menu item
|
/// No description provided for @import_data.
|
||||||
///
|
///
|
||||||
/// In en, this message translates to:
|
/// In en, this message translates to:
|
||||||
/// **'Import data'**
|
/// **'Import data'**
|
||||||
String get import_data;
|
String get import_data;
|
||||||
|
|
||||||
/// Info label
|
/// No description provided for @info.
|
||||||
///
|
///
|
||||||
/// In en, this message translates to:
|
/// In en, this message translates to:
|
||||||
/// **'Info'**
|
/// **'Info'**
|
||||||
String get info;
|
String get info;
|
||||||
|
|
||||||
/// Error message for invalid schema
|
/// No description provided for @invalid_schema.
|
||||||
///
|
///
|
||||||
/// In en, this message translates to:
|
/// In en, this message translates to:
|
||||||
/// **'Invalid Schema'**
|
/// **'Invalid Schema'**
|
||||||
String get invalid_schema;
|
String get invalid_schema;
|
||||||
|
|
||||||
/// Title for least points ruleset
|
/// No description provided for @least_points.
|
||||||
///
|
///
|
||||||
/// In en, this message translates to:
|
/// In en, this message translates to:
|
||||||
/// **'Least Points'**
|
/// **'Least Points'**
|
||||||
String get least_points;
|
String get least_points;
|
||||||
|
|
||||||
/// Legal section header
|
/// No description provided for @legal.
|
||||||
///
|
///
|
||||||
/// In en, this message translates to:
|
/// In en, this message translates to:
|
||||||
/// **'Legal'**
|
/// **'Legal'**
|
||||||
String get legal;
|
String get legal;
|
||||||
|
|
||||||
/// Legal notice menu item
|
/// No description provided for @legal_notice.
|
||||||
///
|
///
|
||||||
/// In en, this message translates to:
|
/// In en, this message translates to:
|
||||||
/// **'Legal Notice'**
|
/// **'Legal Notice'**
|
||||||
String get legal_notice;
|
String get legal_notice;
|
||||||
|
|
||||||
/// Licenses menu item
|
/// No description provided for @licenses.
|
||||||
///
|
///
|
||||||
/// In en, this message translates to:
|
/// In en, this message translates to:
|
||||||
/// **'Licenses'**
|
/// **'Licenses'**
|
||||||
String get licenses;
|
String get licenses;
|
||||||
|
|
||||||
/// Message when match is in progress
|
/// No description provided for @match_in_progress.
|
||||||
///
|
///
|
||||||
/// In en, this message translates to:
|
/// In en, this message translates to:
|
||||||
/// **'Match in progress...'**
|
/// **'Match in progress...'**
|
||||||
String get match_in_progress;
|
String get match_in_progress;
|
||||||
|
|
||||||
/// Placeholder for match name input
|
/// No description provided for @match_name.
|
||||||
///
|
///
|
||||||
/// In en, this message translates to:
|
/// In en, this message translates to:
|
||||||
/// **'Match name'**
|
/// **'Match name'**
|
||||||
String get match_name;
|
String get match_name;
|
||||||
|
|
||||||
/// Title for match profile view
|
/// No description provided for @match_profile.
|
||||||
///
|
///
|
||||||
/// In en, this message translates to:
|
/// In en, this message translates to:
|
||||||
/// **'Match Profile'**
|
/// **'Match Profile'**
|
||||||
String get match_profile;
|
String get match_profile;
|
||||||
|
|
||||||
/// Label for matches
|
/// No description provided for @matches.
|
||||||
///
|
///
|
||||||
/// In en, this message translates to:
|
/// In en, this message translates to:
|
||||||
/// **'Matches'**
|
/// **'Matches'**
|
||||||
String get matches;
|
String get matches;
|
||||||
|
|
||||||
/// Label for group members
|
/// No description provided for @members.
|
||||||
///
|
///
|
||||||
/// In en, this message translates to:
|
/// In en, this message translates to:
|
||||||
/// **'Members'**
|
/// **'Members'**
|
||||||
String get members;
|
String get members;
|
||||||
|
|
||||||
/// Title for most points ruleset
|
/// No description provided for @most_points.
|
||||||
///
|
///
|
||||||
/// In en, this message translates to:
|
/// In en, this message translates to:
|
||||||
/// **'Most Points'**
|
/// **'Most Points'**
|
||||||
String get most_points;
|
String get most_points;
|
||||||
|
|
||||||
/// Message when no data in the statistic tiles is given
|
/// No description provided for @no_data_available.
|
||||||
///
|
///
|
||||||
/// In en, this message translates to:
|
/// In en, this message translates to:
|
||||||
/// **'No data available'**
|
/// **'No data available'**
|
||||||
String get no_data_available;
|
String get no_data_available;
|
||||||
|
|
||||||
/// Message when no groups exist
|
/// No description provided for @no_games_created_yet.
|
||||||
|
///
|
||||||
|
/// In en, this message translates to:
|
||||||
|
/// **'No games created yet'**
|
||||||
|
String get no_games_created_yet;
|
||||||
|
|
||||||
|
/// No description provided for @no_groups_created_yet.
|
||||||
///
|
///
|
||||||
/// In en, this message translates to:
|
/// In en, this message translates to:
|
||||||
/// **'No groups created yet'**
|
/// **'No groups created yet'**
|
||||||
String get no_groups_created_yet;
|
String get no_groups_created_yet;
|
||||||
|
|
||||||
/// Message when no licenses are found
|
/// No description provided for @no_licenses_found.
|
||||||
///
|
///
|
||||||
/// In en, this message translates to:
|
/// In en, this message translates to:
|
||||||
/// **'No licenses found'**
|
/// **'No licenses found'**
|
||||||
String get no_licenses_found;
|
String get no_licenses_found;
|
||||||
|
|
||||||
/// Message when no license text is available
|
/// No description provided for @no_license_text_available.
|
||||||
///
|
///
|
||||||
/// In en, this message translates to:
|
/// In en, this message translates to:
|
||||||
/// **'No license text available'**
|
/// **'No license text available'**
|
||||||
String get no_license_text_available;
|
String get no_license_text_available;
|
||||||
|
|
||||||
/// Message when no matches exist
|
/// No description provided for @no_matches_created_yet.
|
||||||
///
|
///
|
||||||
/// In en, this message translates to:
|
/// In en, this message translates to:
|
||||||
/// **'No matches created yet'**
|
/// **'No matches created yet'**
|
||||||
String get no_matches_created_yet;
|
String get no_matches_created_yet;
|
||||||
|
|
||||||
/// Message when no players exist
|
/// No description provided for @no_players_created_yet.
|
||||||
///
|
///
|
||||||
/// In en, this message translates to:
|
/// In en, this message translates to:
|
||||||
/// **'No players created yet'**
|
/// **'No players created yet'**
|
||||||
String get no_players_created_yet;
|
String get no_players_created_yet;
|
||||||
|
|
||||||
/// Message when search returns no results
|
/// No description provided for @no_players_found_with_that_name.
|
||||||
///
|
///
|
||||||
/// In en, this message translates to:
|
/// In en, this message translates to:
|
||||||
/// **'No players found with that name'**
|
/// **'No players found with that name'**
|
||||||
String get no_players_found_with_that_name;
|
String get no_players_found_with_that_name;
|
||||||
|
|
||||||
/// Message when no players are selected
|
/// No description provided for @no_players_selected.
|
||||||
///
|
///
|
||||||
/// In en, this message translates to:
|
/// In en, this message translates to:
|
||||||
/// **'No players selected'**
|
/// **'No players selected'**
|
||||||
String get no_players_selected;
|
String get no_players_selected;
|
||||||
|
|
||||||
/// Message when no recent matches exist
|
/// No description provided for @no_recent_matches_available.
|
||||||
///
|
///
|
||||||
/// In en, this message translates to:
|
/// In en, this message translates to:
|
||||||
/// **'No recent matches available'**
|
/// **'No recent matches available'**
|
||||||
String get no_recent_matches_available;
|
String get no_recent_matches_available;
|
||||||
|
|
||||||
/// Message when no results have been entered yet
|
/// No description provided for @no_results_entered_yet.
|
||||||
///
|
///
|
||||||
/// In en, this message translates to:
|
/// In en, this message translates to:
|
||||||
/// **'No results entered yet'**
|
/// **'No results entered yet'**
|
||||||
String get no_results_entered_yet;
|
String get no_results_entered_yet;
|
||||||
|
|
||||||
/// Message when no second match exists
|
/// No description provided for @no_second_match_available.
|
||||||
///
|
///
|
||||||
/// In en, this message translates to:
|
/// In en, this message translates to:
|
||||||
/// **'No second match available'**
|
/// **'No second match available'**
|
||||||
String get no_second_match_available;
|
String get no_second_match_available;
|
||||||
|
|
||||||
/// Message when no statistics are available, because no matches were played yet
|
/// No description provided for @no_statistics_available.
|
||||||
///
|
///
|
||||||
/// In en, this message translates to:
|
/// In en, this message translates to:
|
||||||
/// **'No statistics available'**
|
/// **'No statistics available'**
|
||||||
String get no_statistics_available;
|
String get no_statistics_available;
|
||||||
|
|
||||||
/// None option label
|
/// No description provided for @none.
|
||||||
///
|
///
|
||||||
/// In en, this message translates to:
|
/// In en, this message translates to:
|
||||||
/// **'None'**
|
/// **'None'**
|
||||||
String get none;
|
String get none;
|
||||||
|
|
||||||
/// None group option label
|
/// No description provided for @none_group.
|
||||||
///
|
///
|
||||||
/// In en, this message translates to:
|
/// In en, this message translates to:
|
||||||
/// **'None'**
|
/// **'None'**
|
||||||
String get none_group;
|
String get none_group;
|
||||||
|
|
||||||
/// Abbreviation for not available
|
/// No description provided for @not_available.
|
||||||
///
|
///
|
||||||
/// In en, this message translates to:
|
/// In en, this message translates to:
|
||||||
/// **'Not available'**
|
/// **'Not available'**
|
||||||
String get not_available;
|
String get not_available;
|
||||||
|
|
||||||
/// Label for played matches statistic
|
/// No description provided for @played_matches.
|
||||||
///
|
///
|
||||||
/// In en, this message translates to:
|
/// In en, this message translates to:
|
||||||
/// **'Played Matches'**
|
/// **'Played Matches'**
|
||||||
String get played_matches;
|
String get played_matches;
|
||||||
|
|
||||||
/// Placeholder for player name input
|
/// No description provided for @player_name.
|
||||||
///
|
///
|
||||||
/// In en, this message translates to:
|
/// In en, this message translates to:
|
||||||
/// **'Player name'**
|
/// **'Player name'**
|
||||||
String get player_name;
|
String get player_name;
|
||||||
|
|
||||||
/// Players label
|
/// No description provided for @players.
|
||||||
///
|
///
|
||||||
/// In en, this message translates to:
|
/// In en, this message translates to:
|
||||||
/// **'Players'**
|
/// **'Players'**
|
||||||
String get players;
|
String get players;
|
||||||
|
|
||||||
/// Shows the number of players
|
|
||||||
///
|
|
||||||
/// In en, this message translates to:
|
|
||||||
/// **'{count} Players'**
|
|
||||||
String players_count(int count);
|
|
||||||
|
|
||||||
/// No description provided for @point.
|
/// No description provided for @point.
|
||||||
///
|
///
|
||||||
/// In en, this message translates to:
|
/// In en, this message translates to:
|
||||||
/// **'Point'**
|
/// **'Point'**
|
||||||
String get point;
|
String get point;
|
||||||
|
|
||||||
/// Points label
|
/// No description provided for @points.
|
||||||
///
|
///
|
||||||
/// In en, this message translates to:
|
/// In en, this message translates to:
|
||||||
/// **'Points'**
|
/// **'Points'**
|
||||||
String get points;
|
String get points;
|
||||||
|
|
||||||
/// Privacy policy menu item
|
/// No description provided for @privacy_policy.
|
||||||
///
|
///
|
||||||
/// In en, this message translates to:
|
/// In en, this message translates to:
|
||||||
/// **'Privacy Policy'**
|
/// **'Privacy Policy'**
|
||||||
String get privacy_policy;
|
String get privacy_policy;
|
||||||
|
|
||||||
/// Title for quick create section
|
/// No description provided for @quick_create.
|
||||||
///
|
///
|
||||||
/// In en, this message translates to:
|
/// In en, this message translates to:
|
||||||
/// **'Quick Create'**
|
/// **'Quick Create'**
|
||||||
String get quick_create;
|
String get quick_create;
|
||||||
|
|
||||||
/// Title for recent matches section
|
/// No description provided for @recent_matches.
|
||||||
///
|
///
|
||||||
/// In en, this message translates to:
|
/// In en, this message translates to:
|
||||||
/// **'Recent Matches'**
|
/// **'Recent Matches'**
|
||||||
String get recent_matches;
|
String get recent_matches;
|
||||||
|
|
||||||
/// Label for match results
|
/// No description provided for @results.
|
||||||
///
|
///
|
||||||
/// In en, this message translates to:
|
/// In en, this message translates to:
|
||||||
/// **'Results'**
|
/// **'Results'**
|
||||||
String get results;
|
String get results;
|
||||||
|
|
||||||
/// Ruleset label
|
/// No description provided for @ruleset.
|
||||||
///
|
///
|
||||||
/// In en, this message translates to:
|
/// In en, this message translates to:
|
||||||
/// **'Ruleset'**
|
/// **'Ruleset'**
|
||||||
String get ruleset;
|
String get ruleset;
|
||||||
|
|
||||||
/// Description for least points ruleset
|
/// No description provided for @ruleset_least_points.
|
||||||
///
|
///
|
||||||
/// In en, this message translates to:
|
/// In en, this message translates to:
|
||||||
/// **'Inverse scoring: the player with the fewest points wins.'**
|
/// **'Inverse scoring: the player with the fewest points wins.'**
|
||||||
String get ruleset_least_points;
|
String get ruleset_least_points;
|
||||||
|
|
||||||
/// Description for most points ruleset
|
/// No description provided for @ruleset_most_points.
|
||||||
///
|
///
|
||||||
/// In en, this message translates to:
|
/// In en, this message translates to:
|
||||||
/// **'Traditional ruleset: the player with the most points wins.'**
|
/// **'Traditional ruleset: the player with the most points wins.'**
|
||||||
String get ruleset_most_points;
|
String get ruleset_most_points;
|
||||||
|
|
||||||
/// Description for single loser ruleset
|
/// No description provided for @ruleset_single_loser.
|
||||||
///
|
///
|
||||||
/// In en, this message translates to:
|
/// In en, this message translates to:
|
||||||
/// **'Exactly one loser is determined; last place receives the penalty or consequence.'**
|
/// **'Exactly one loser is determined; last place receives the penalty or consequence.'**
|
||||||
String get ruleset_single_loser;
|
String get ruleset_single_loser;
|
||||||
|
|
||||||
/// Description for single winner ruleset
|
/// No description provided for @ruleset_single_winner.
|
||||||
///
|
///
|
||||||
/// In en, this message translates to:
|
/// In en, this message translates to:
|
||||||
/// **'Exactly one winner is chosen; ties are resolved by a predefined tiebreaker.'**
|
/// **'Exactly one winner is chosen; ties are resolved by a predefined tiebreaker.'**
|
||||||
String get ruleset_single_winner;
|
String get ruleset_single_winner;
|
||||||
|
|
||||||
/// Save changes button text
|
/// No description provided for @save_changes.
|
||||||
///
|
///
|
||||||
/// In en, this message translates to:
|
/// In en, this message translates to:
|
||||||
/// **'Save Changes'**
|
/// **'Save Changes'**
|
||||||
String get save_changes;
|
String get save_changes;
|
||||||
|
|
||||||
/// Hint text for group search input field
|
/// No description provided for @search_for_groups.
|
||||||
///
|
///
|
||||||
/// In en, this message translates to:
|
/// In en, this message translates to:
|
||||||
/// **'Search for groups'**
|
/// **'Search for groups'**
|
||||||
String get search_for_groups;
|
String get search_for_groups;
|
||||||
|
|
||||||
/// Hint text for player search input field
|
/// No description provided for @search_for_players.
|
||||||
///
|
///
|
||||||
/// In en, this message translates to:
|
/// In en, this message translates to:
|
||||||
/// **'Search for players'**
|
/// **'Search for players'**
|
||||||
String get search_for_players;
|
String get search_for_players;
|
||||||
|
|
||||||
/// Label to select the winner
|
/// No description provided for @select_winner.
|
||||||
///
|
///
|
||||||
/// In en, this message translates to:
|
/// In en, this message translates to:
|
||||||
/// **'Select Winner'**
|
/// **'Select Winner'**
|
||||||
String get select_winner;
|
String get select_winner;
|
||||||
|
|
||||||
/// Label to select the loser
|
/// No description provided for @select_loser.
|
||||||
///
|
///
|
||||||
/// In en, this message translates to:
|
/// In en, this message translates to:
|
||||||
/// **'Select Loser'**
|
/// **'Select Loser'**
|
||||||
String get select_loser;
|
String get select_loser;
|
||||||
|
|
||||||
/// Shows the number of selected players
|
/// No description provided for @selected_players.
|
||||||
///
|
///
|
||||||
/// In en, this message translates to:
|
/// In en, this message translates to:
|
||||||
/// **'Selected players'**
|
/// **'Selected players'**
|
||||||
String get selected_players;
|
String get selected_players;
|
||||||
|
|
||||||
/// Label for the App Settings
|
/// No description provided for @settings.
|
||||||
///
|
///
|
||||||
/// In en, this message translates to:
|
/// In en, this message translates to:
|
||||||
/// **'Settings'**
|
/// **'Settings'**
|
||||||
String get settings;
|
String get settings;
|
||||||
|
|
||||||
/// Title for single loser ruleset
|
/// No description provided for @single_loser.
|
||||||
///
|
///
|
||||||
/// In en, this message translates to:
|
/// In en, this message translates to:
|
||||||
/// **'Single Loser'**
|
/// **'Single Loser'**
|
||||||
String get single_loser;
|
String get single_loser;
|
||||||
|
|
||||||
/// Title for single winner ruleset
|
/// No description provided for @single_winner.
|
||||||
///
|
///
|
||||||
/// In en, this message translates to:
|
/// In en, this message translates to:
|
||||||
/// **'Single Winner'**
|
/// **'Single Winner'**
|
||||||
@@ -692,13 +788,13 @@ abstract class AppLocalizations {
|
|||||||
/// **'Multiple Winners'**
|
/// **'Multiple Winners'**
|
||||||
String get multiple_winners;
|
String get multiple_winners;
|
||||||
|
|
||||||
/// Statistics tab label
|
/// No description provided for @statistics.
|
||||||
///
|
///
|
||||||
/// In en, this message translates to:
|
/// In en, this message translates to:
|
||||||
/// **'Statistics'**
|
/// **'Statistics'**
|
||||||
String get statistics;
|
String get statistics;
|
||||||
|
|
||||||
/// Stats tab label (short)
|
/// No description provided for @stats.
|
||||||
///
|
///
|
||||||
/// In en, this message translates to:
|
/// In en, this message translates to:
|
||||||
/// **'Stats'**
|
/// **'Stats'**
|
||||||
@@ -710,13 +806,19 @@ abstract class AppLocalizations {
|
|||||||
/// **'Successfully added player {playerName}'**
|
/// **'Successfully added player {playerName}'**
|
||||||
String successfully_added_player(String playerName);
|
String successfully_added_player(String playerName);
|
||||||
|
|
||||||
/// Message when search returns no groups
|
/// No description provided for @there_are_no_games_matching_your_search.
|
||||||
|
///
|
||||||
|
/// In en, this message translates to:
|
||||||
|
/// **'There are no games matching your search'**
|
||||||
|
String get there_are_no_games_matching_your_search;
|
||||||
|
|
||||||
|
/// No description provided for @there_is_no_group_matching_your_search.
|
||||||
///
|
///
|
||||||
/// In en, this message translates to:
|
/// In en, this message translates to:
|
||||||
/// **'There is no group matching your search'**
|
/// **'There is no group matching your search'**
|
||||||
String get there_is_no_group_matching_your_search;
|
String get there_is_no_group_matching_your_search;
|
||||||
|
|
||||||
/// Warning message for irreversible actions
|
/// No description provided for @this_cannot_be_undone.
|
||||||
///
|
///
|
||||||
/// In en, this message translates to:
|
/// In en, this message translates to:
|
||||||
/// **'This can\'t be undone.'**
|
/// **'This can\'t be undone.'**
|
||||||
@@ -728,43 +830,43 @@ abstract class AppLocalizations {
|
|||||||
/// **'Tie'**
|
/// **'Tie'**
|
||||||
String get tie;
|
String get tie;
|
||||||
|
|
||||||
/// Date format for today
|
/// No description provided for @today_at.
|
||||||
///
|
///
|
||||||
/// In en, this message translates to:
|
/// In en, this message translates to:
|
||||||
/// **'Today at'**
|
/// **'Today at'**
|
||||||
String get today_at;
|
String get today_at;
|
||||||
|
|
||||||
/// Undo button text
|
/// No description provided for @undo.
|
||||||
///
|
///
|
||||||
/// In en, this message translates to:
|
/// In en, this message translates to:
|
||||||
/// **'Undo'**
|
/// **'Undo'**
|
||||||
String get undo;
|
String get undo;
|
||||||
|
|
||||||
/// Error message for unknown exceptions
|
/// No description provided for @unknown_exception.
|
||||||
///
|
///
|
||||||
/// In en, this message translates to:
|
/// In en, this message translates to:
|
||||||
/// **'Unknown Exception (see console)'**
|
/// **'Unknown Exception (see console)'**
|
||||||
String get unknown_exception;
|
String get unknown_exception;
|
||||||
|
|
||||||
/// Winner label
|
/// No description provided for @winner.
|
||||||
///
|
///
|
||||||
/// In en, this message translates to:
|
/// In en, this message translates to:
|
||||||
/// **'Winner'**
|
/// **'Winner'**
|
||||||
String get winner;
|
String get winner;
|
||||||
|
|
||||||
/// Label for winrate statistic
|
/// No description provided for @winrate.
|
||||||
///
|
///
|
||||||
/// In en, this message translates to:
|
/// In en, this message translates to:
|
||||||
/// **'Winrate'**
|
/// **'Winrate'**
|
||||||
String get winrate;
|
String get winrate;
|
||||||
|
|
||||||
/// Label for wins statistic
|
/// No description provided for @wins.
|
||||||
///
|
///
|
||||||
/// In en, this message translates to:
|
/// In en, this message translates to:
|
||||||
/// **'Wins'**
|
/// **'Wins'**
|
||||||
String get wins;
|
String get wins;
|
||||||
|
|
||||||
/// Date format for yesterday
|
/// No description provided for @yesterday_at.
|
||||||
///
|
///
|
||||||
/// In en, this message translates to:
|
/// In en, this message translates to:
|
||||||
/// **'Yesterday at'**
|
/// **'Yesterday at'**
|
||||||
|
|||||||
@@ -26,6 +26,9 @@ class AppLocalizationsDe extends AppLocalizations {
|
|||||||
@override
|
@override
|
||||||
String get cancel => 'Abbrechen';
|
String get cancel => 'Abbrechen';
|
||||||
|
|
||||||
|
@override
|
||||||
|
String get choose_color => 'Farbe wählen';
|
||||||
|
|
||||||
@override
|
@override
|
||||||
String get choose_game => 'Spielvorlage wählen';
|
String get choose_game => 'Spielvorlage wählen';
|
||||||
|
|
||||||
@@ -35,11 +38,41 @@ class AppLocalizationsDe extends AppLocalizations {
|
|||||||
@override
|
@override
|
||||||
String get choose_ruleset => 'Regelwerk wählen';
|
String get choose_ruleset => 'Regelwerk wählen';
|
||||||
|
|
||||||
|
@override
|
||||||
|
String get color => 'Farbe';
|
||||||
|
|
||||||
|
@override
|
||||||
|
String get color_blue => 'Blau';
|
||||||
|
|
||||||
|
@override
|
||||||
|
String get color_green => 'Grün';
|
||||||
|
|
||||||
|
@override
|
||||||
|
String get color_orange => 'Orange';
|
||||||
|
|
||||||
|
@override
|
||||||
|
String get color_pink => 'Rosa';
|
||||||
|
|
||||||
|
@override
|
||||||
|
String get color_purple => 'Lila';
|
||||||
|
|
||||||
|
@override
|
||||||
|
String get color_red => 'Rot';
|
||||||
|
|
||||||
|
@override
|
||||||
|
String get color_teal => 'Türkis';
|
||||||
|
|
||||||
|
@override
|
||||||
|
String get color_yellow => 'Gelb';
|
||||||
|
|
||||||
@override
|
@override
|
||||||
String could_not_add_player(Object playerName) {
|
String could_not_add_player(Object playerName) {
|
||||||
return 'Spieler:in $playerName konnte nicht hinzugefügt werden';
|
return 'Spieler:in $playerName konnte nicht hinzugefügt werden';
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@override
|
||||||
|
String get create_game => 'Spielvorlage erstellen';
|
||||||
|
|
||||||
@override
|
@override
|
||||||
String get create_group => 'Gruppe erstellen';
|
String get create_group => 'Gruppe erstellen';
|
||||||
|
|
||||||
@@ -68,7 +101,7 @@ class AppLocalizationsDe extends AppLocalizations {
|
|||||||
String get data_successfully_imported => 'Daten erfolgreich importiert';
|
String get data_successfully_imported => 'Daten erfolgreich importiert';
|
||||||
|
|
||||||
@override
|
@override
|
||||||
String days_ago(int count) {
|
String days_ago(Object count) {
|
||||||
return 'vor $count Tagen';
|
return 'vor $count Tagen';
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -78,12 +111,32 @@ class AppLocalizationsDe extends AppLocalizations {
|
|||||||
@override
|
@override
|
||||||
String get delete_all_data => 'Alle Daten löschen';
|
String get delete_all_data => 'Alle Daten löschen';
|
||||||
|
|
||||||
|
@override
|
||||||
|
String get delete_game => 'Spielvorlage löschen';
|
||||||
|
|
||||||
|
@override
|
||||||
|
String delete_game_with_matches_warning(int count) {
|
||||||
|
String _temp0 = intl.Intl.pluralLogic(
|
||||||
|
count,
|
||||||
|
locale: localeName,
|
||||||
|
other: 'werden $count Spiele',
|
||||||
|
one: 'wird 1 Spiel',
|
||||||
|
);
|
||||||
|
return 'Wenn du diese Spielvorlage löschst, $_temp0 mit dieser Spielvorlage ebenfalls gelöscht.';
|
||||||
|
}
|
||||||
|
|
||||||
@override
|
@override
|
||||||
String get delete_group => 'Gruppe löschen';
|
String get delete_group => 'Gruppe löschen';
|
||||||
|
|
||||||
@override
|
@override
|
||||||
String get delete_match => 'Spiel löschen';
|
String get delete_match => 'Spiel löschen';
|
||||||
|
|
||||||
|
@override
|
||||||
|
String get description => 'Beschreibung';
|
||||||
|
|
||||||
|
@override
|
||||||
|
String get edit_game => 'Spielvorlage bearbeiten';
|
||||||
|
|
||||||
@override
|
@override
|
||||||
String get edit_group => 'Gruppe bearbeiten';
|
String get edit_group => 'Gruppe bearbeiten';
|
||||||
|
|
||||||
@@ -100,6 +153,10 @@ class AppLocalizationsDe extends AppLocalizations {
|
|||||||
String get error_creating_group =>
|
String get error_creating_group =>
|
||||||
'Fehler beim Erstellen der Gruppe, bitte erneut versuchen';
|
'Fehler beim Erstellen der Gruppe, bitte erneut versuchen';
|
||||||
|
|
||||||
|
@override
|
||||||
|
String get error_deleting_game =>
|
||||||
|
'Fehler beim Löschen der Spielvorlage, bitte erneut versuchen';
|
||||||
|
|
||||||
@override
|
@override
|
||||||
String get error_deleting_group =>
|
String get error_deleting_group =>
|
||||||
'Fehler beim Löschen der Gruppe, bitte erneut versuchen';
|
'Fehler beim Löschen der Gruppe, bitte erneut versuchen';
|
||||||
@@ -186,6 +243,9 @@ class AppLocalizationsDe extends AppLocalizations {
|
|||||||
@override
|
@override
|
||||||
String get no_data_available => 'Keine Daten verfügbar';
|
String get no_data_available => 'Keine Daten verfügbar';
|
||||||
|
|
||||||
|
@override
|
||||||
|
String get no_games_created_yet => 'Noch keine Spielvorlagen erstellt';
|
||||||
|
|
||||||
@override
|
@override
|
||||||
String get no_groups_created_yet => 'Noch keine Gruppen erstellt';
|
String get no_groups_created_yet => 'Noch keine Gruppen erstellt';
|
||||||
|
|
||||||
@@ -238,11 +298,6 @@ class AppLocalizationsDe extends AppLocalizations {
|
|||||||
@override
|
@override
|
||||||
String get players => 'Spieler:innen';
|
String get players => 'Spieler:innen';
|
||||||
|
|
||||||
@override
|
|
||||||
String players_count(int count) {
|
|
||||||
return '$count Spieler';
|
|
||||||
}
|
|
||||||
|
|
||||||
@override
|
@override
|
||||||
String get point => 'Punkt';
|
String get point => 'Punkt';
|
||||||
|
|
||||||
@@ -330,6 +385,10 @@ class AppLocalizationsDe extends AppLocalizations {
|
|||||||
return 'Spieler:in $playerName erfolgreich hinzugefügt';
|
return 'Spieler:in $playerName erfolgreich hinzugefügt';
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@override
|
||||||
|
String get there_are_no_games_matching_your_search =>
|
||||||
|
'Es gibt keine Spielvorlagen, die deiner Suche entspricht';
|
||||||
|
|
||||||
@override
|
@override
|
||||||
String get there_is_no_group_matching_your_search =>
|
String get there_is_no_group_matching_your_search =>
|
||||||
'Es gibt keine Gruppe, die deiner Suche entspricht';
|
'Es gibt keine Gruppe, die deiner Suche entspricht';
|
||||||
|
|||||||
@@ -26,6 +26,9 @@ class AppLocalizationsEn extends AppLocalizations {
|
|||||||
@override
|
@override
|
||||||
String get cancel => 'Cancel';
|
String get cancel => 'Cancel';
|
||||||
|
|
||||||
|
@override
|
||||||
|
String get choose_color => 'Choose Color';
|
||||||
|
|
||||||
@override
|
@override
|
||||||
String get choose_game => 'Choose Game';
|
String get choose_game => 'Choose Game';
|
||||||
|
|
||||||
@@ -35,11 +38,41 @@ class AppLocalizationsEn extends AppLocalizations {
|
|||||||
@override
|
@override
|
||||||
String get choose_ruleset => 'Choose Ruleset';
|
String get choose_ruleset => 'Choose Ruleset';
|
||||||
|
|
||||||
|
@override
|
||||||
|
String get color => 'Color';
|
||||||
|
|
||||||
|
@override
|
||||||
|
String get color_blue => 'Blue';
|
||||||
|
|
||||||
|
@override
|
||||||
|
String get color_green => 'Green';
|
||||||
|
|
||||||
|
@override
|
||||||
|
String get color_orange => 'Orange';
|
||||||
|
|
||||||
|
@override
|
||||||
|
String get color_pink => 'Pink';
|
||||||
|
|
||||||
|
@override
|
||||||
|
String get color_purple => 'Purple';
|
||||||
|
|
||||||
|
@override
|
||||||
|
String get color_red => 'Red';
|
||||||
|
|
||||||
|
@override
|
||||||
|
String get color_teal => 'Teal';
|
||||||
|
|
||||||
|
@override
|
||||||
|
String get color_yellow => 'Yellow';
|
||||||
|
|
||||||
@override
|
@override
|
||||||
String could_not_add_player(Object playerName) {
|
String could_not_add_player(Object playerName) {
|
||||||
return 'Could not add player';
|
return 'Could not add player';
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@override
|
||||||
|
String get create_game => 'Create Game';
|
||||||
|
|
||||||
@override
|
@override
|
||||||
String get create_group => 'Create Group';
|
String get create_group => 'Create Group';
|
||||||
|
|
||||||
@@ -68,7 +101,7 @@ class AppLocalizationsEn extends AppLocalizations {
|
|||||||
String get data_successfully_imported => 'Data successfully imported';
|
String get data_successfully_imported => 'Data successfully imported';
|
||||||
|
|
||||||
@override
|
@override
|
||||||
String days_ago(int count) {
|
String days_ago(Object count) {
|
||||||
return '$count days ago';
|
return '$count days ago';
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -78,12 +111,32 @@ class AppLocalizationsEn extends AppLocalizations {
|
|||||||
@override
|
@override
|
||||||
String get delete_all_data => 'Delete all data';
|
String get delete_all_data => 'Delete all data';
|
||||||
|
|
||||||
|
@override
|
||||||
|
String get delete_game => 'Delete Game';
|
||||||
|
|
||||||
|
@override
|
||||||
|
String delete_game_with_matches_warning(int count) {
|
||||||
|
String _temp0 = intl.Intl.pluralLogic(
|
||||||
|
count,
|
||||||
|
locale: localeName,
|
||||||
|
other: '$count matches',
|
||||||
|
one: '1 match',
|
||||||
|
);
|
||||||
|
return 'If you delete this game template, $_temp0 using this game template will also be deleted.';
|
||||||
|
}
|
||||||
|
|
||||||
@override
|
@override
|
||||||
String get delete_group => 'Delete Group';
|
String get delete_group => 'Delete Group';
|
||||||
|
|
||||||
@override
|
@override
|
||||||
String get delete_match => 'Delete Match';
|
String get delete_match => 'Delete Match';
|
||||||
|
|
||||||
|
@override
|
||||||
|
String get description => 'Description';
|
||||||
|
|
||||||
|
@override
|
||||||
|
String get edit_game => 'Edit Game';
|
||||||
|
|
||||||
@override
|
@override
|
||||||
String get edit_group => 'Edit Group';
|
String get edit_group => 'Edit Group';
|
||||||
|
|
||||||
@@ -100,6 +153,10 @@ class AppLocalizationsEn extends AppLocalizations {
|
|||||||
String get error_creating_group =>
|
String get error_creating_group =>
|
||||||
'Error while creating group, please try again';
|
'Error while creating group, please try again';
|
||||||
|
|
||||||
|
@override
|
||||||
|
String get error_deleting_game =>
|
||||||
|
'Error while deleting game, please try again';
|
||||||
|
|
||||||
@override
|
@override
|
||||||
String get error_deleting_group =>
|
String get error_deleting_group =>
|
||||||
'Error while deleting group, please try again';
|
'Error while deleting group, please try again';
|
||||||
@@ -186,6 +243,9 @@ class AppLocalizationsEn extends AppLocalizations {
|
|||||||
@override
|
@override
|
||||||
String get no_data_available => 'No data available';
|
String get no_data_available => 'No data available';
|
||||||
|
|
||||||
|
@override
|
||||||
|
String get no_games_created_yet => 'No games created yet';
|
||||||
|
|
||||||
@override
|
@override
|
||||||
String get no_groups_created_yet => 'No groups created yet';
|
String get no_groups_created_yet => 'No groups created yet';
|
||||||
|
|
||||||
@@ -238,11 +298,6 @@ class AppLocalizationsEn extends AppLocalizations {
|
|||||||
@override
|
@override
|
||||||
String get players => 'Players';
|
String get players => 'Players';
|
||||||
|
|
||||||
@override
|
|
||||||
String players_count(int count) {
|
|
||||||
return '$count Players';
|
|
||||||
}
|
|
||||||
|
|
||||||
@override
|
@override
|
||||||
String get point => 'Point';
|
String get point => 'Point';
|
||||||
|
|
||||||
@@ -330,6 +385,10 @@ class AppLocalizationsEn extends AppLocalizations {
|
|||||||
return 'Successfully added player $playerName';
|
return 'Successfully added player $playerName';
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@override
|
||||||
|
String get there_are_no_games_matching_your_search =>
|
||||||
|
'There are no games matching your search';
|
||||||
|
|
||||||
@override
|
@override
|
||||||
String get there_is_no_group_matching_your_search =>
|
String get there_is_no_group_matching_your_search =>
|
||||||
'There is no group matching your search';
|
'There is no group matching your search';
|
||||||
|
|||||||
@@ -197,7 +197,7 @@ class _CreateGroupViewState extends State<CreateGroupView> {
|
|||||||
/// obsolete. For each such match, the group association is removed by setting
|
/// obsolete. For each such match, the group association is removed by setting
|
||||||
/// its [groupId] to null.
|
/// its [groupId] to null.
|
||||||
Future<void> deleteObsoleteMatchGroupRelations() async {
|
Future<void> deleteObsoleteMatchGroupRelations() async {
|
||||||
final groupMatches = await db.matchDao.getGroupMatches(
|
final groupMatches = await db.matchDao.getMatchesByGroup(
|
||||||
groupId: widget.groupToEdit!.id,
|
groupId: widget.groupToEdit!.id,
|
||||||
);
|
);
|
||||||
|
|
||||||
|
|||||||
@@ -244,7 +244,9 @@ class _GroupDetailViewState extends State<GroupDetailView> {
|
|||||||
/// Loads statistics for this group
|
/// Loads statistics for this group
|
||||||
Future<void> _loadStatistics() async {
|
Future<void> _loadStatistics() async {
|
||||||
isLoading = true;
|
isLoading = true;
|
||||||
final groupMatches = await db.matchDao.getGroupMatches(groupId: _group.id);
|
final groupMatches = await db.matchDao.getMatchesByGroup(
|
||||||
|
groupId: _group.id,
|
||||||
|
);
|
||||||
|
|
||||||
setState(() {
|
setState(() {
|
||||||
totalMatches = groupMatches.length;
|
totalMatches = groupMatches.length;
|
||||||
|
|||||||
@@ -1,19 +1,26 @@
|
|||||||
import 'package:flutter/material.dart';
|
import 'package:flutter/material.dart';
|
||||||
|
import 'package:provider/provider.dart';
|
||||||
|
import 'package:tallee/core/adaptive_page_route.dart';
|
||||||
import 'package:tallee/core/common.dart';
|
import 'package:tallee/core/common.dart';
|
||||||
import 'package:tallee/core/custom_theme.dart';
|
import 'package:tallee/core/custom_theme.dart';
|
||||||
|
import 'package:tallee/data/db/database.dart';
|
||||||
import 'package:tallee/data/models/game.dart';
|
import 'package:tallee/data/models/game.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_game_view.dart';
|
||||||
import 'package:tallee/presentation/widgets/text_input/custom_search_bar.dart';
|
import 'package:tallee/presentation/widgets/text_input/custom_search_bar.dart';
|
||||||
import 'package:tallee/presentation/widgets/tiles/title_description_list_tile.dart';
|
import 'package:tallee/presentation/widgets/tiles/game_tile.dart';
|
||||||
|
import 'package:tallee/presentation/widgets/top_centered_message.dart';
|
||||||
|
|
||||||
class ChooseGameView extends StatefulWidget {
|
class ChooseGameView extends StatefulWidget {
|
||||||
/// A view that allows the user to choose a game from a list of available games
|
/// A view that allows the user to choose a game from a list of available games
|
||||||
/// - [games]: A list of tuples containing the game name, description and ruleset
|
/// - [games]: The list of available games
|
||||||
/// - [initialGameIndex]: The index of the initially selected game
|
/// - [initialGameId]: The id of the initially selected game
|
||||||
|
/// - [onGamesUpdated]: Optional callback invoked when the games are updated
|
||||||
const ChooseGameView({
|
const ChooseGameView({
|
||||||
super.key,
|
super.key,
|
||||||
required this.games,
|
required this.games,
|
||||||
required this.initialGameId,
|
required this.initialGameId,
|
||||||
|
this.onGamesUpdated,
|
||||||
});
|
});
|
||||||
|
|
||||||
/// A list of tuples containing the game name, description and ruleset
|
/// A list of tuples containing the game name, description and ruleset
|
||||||
@@ -22,20 +29,37 @@ class ChooseGameView extends StatefulWidget {
|
|||||||
/// The id of the initially selected game
|
/// The id of the initially selected game
|
||||||
final String initialGameId;
|
final String initialGameId;
|
||||||
|
|
||||||
|
/// Optional callback invoked when the games are updated
|
||||||
|
final VoidCallback? onGamesUpdated;
|
||||||
|
|
||||||
@override
|
@override
|
||||||
State<ChooseGameView> createState() => _ChooseGameViewState();
|
State<ChooseGameView> createState() => _ChooseGameViewState();
|
||||||
}
|
}
|
||||||
|
|
||||||
class _ChooseGameViewState extends State<ChooseGameView> {
|
class _ChooseGameViewState extends State<ChooseGameView> {
|
||||||
|
late final AppDatabase db;
|
||||||
|
|
||||||
|
late List<(Game, int)> gameCounts = [];
|
||||||
|
|
||||||
/// Controller for the search bar
|
/// Controller for the search bar
|
||||||
final TextEditingController searchBarController = TextEditingController();
|
final TextEditingController searchBarController = TextEditingController();
|
||||||
|
|
||||||
/// Currently selected game index
|
/// Currently selected game index
|
||||||
late String selectedGameId;
|
late String selectedGameId;
|
||||||
|
|
||||||
|
/// Games filtered according to the current search query
|
||||||
|
late List<Game> filteredGames;
|
||||||
|
|
||||||
@override
|
@override
|
||||||
void initState() {
|
void initState() {
|
||||||
|
db = Provider.of<AppDatabase>(context, listen: false);
|
||||||
|
fetchGameCounts();
|
||||||
|
|
||||||
selectedGameId = widget.initialGameId;
|
selectedGameId = widget.initialGameId;
|
||||||
|
|
||||||
|
// Start with all games visible
|
||||||
|
filteredGames = List<Game>.from(widget.games);
|
||||||
|
|
||||||
super.initState();
|
super.initState();
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -58,6 +82,30 @@ class _ChooseGameViewState extends State<ChooseGameView> {
|
|||||||
);
|
);
|
||||||
},
|
},
|
||||||
),
|
),
|
||||||
|
actions: [
|
||||||
|
IconButton(
|
||||||
|
icon: const Icon(Icons.add),
|
||||||
|
onPressed: () async {
|
||||||
|
final result = await Navigator.push(
|
||||||
|
context,
|
||||||
|
adaptivePageRoute(
|
||||||
|
builder: (context) => CreateGameView(
|
||||||
|
onGameChanged: () {
|
||||||
|
widget.onGamesUpdated?.call();
|
||||||
|
},
|
||||||
|
),
|
||||||
|
),
|
||||||
|
);
|
||||||
|
if (result != null && result.game != null) {
|
||||||
|
setState(() {
|
||||||
|
widget.games.insert(0, result.game);
|
||||||
|
});
|
||||||
|
_refreshFromSource();
|
||||||
|
}
|
||||||
|
},
|
||||||
|
),
|
||||||
|
],
|
||||||
|
|
||||||
title: Text(loc.choose_game),
|
title: Text(loc.choose_game),
|
||||||
),
|
),
|
||||||
body: PopScope(
|
body: PopScope(
|
||||||
@@ -72,37 +120,101 @@ class _ChooseGameViewState extends State<ChooseGameView> {
|
|||||||
},
|
},
|
||||||
child: Column(
|
child: Column(
|
||||||
children: [
|
children: [
|
||||||
|
// Search Bar
|
||||||
Padding(
|
Padding(
|
||||||
padding: const EdgeInsets.symmetric(horizontal: 10),
|
padding: const EdgeInsets.symmetric(horizontal: 10),
|
||||||
child: CustomSearchBar(
|
child: CustomSearchBar(
|
||||||
controller: searchBarController,
|
controller: searchBarController,
|
||||||
hintText: loc.game_name,
|
hintText: loc.game_name,
|
||||||
|
onChanged: (value) {
|
||||||
|
_applySearchFilter(value);
|
||||||
|
},
|
||||||
),
|
),
|
||||||
),
|
),
|
||||||
const SizedBox(height: 5),
|
const SizedBox(height: 5),
|
||||||
|
|
||||||
|
// Game list
|
||||||
Expanded(
|
Expanded(
|
||||||
child: ListView.builder(
|
child: Visibility(
|
||||||
itemCount: widget.games.length,
|
visible: filteredGames.isNotEmpty,
|
||||||
itemBuilder: (BuildContext context, int index) {
|
replacement: Visibility(
|
||||||
return TitleDescriptionListTile(
|
visible: widget.games.isNotEmpty,
|
||||||
title: widget.games[index].name,
|
replacement: TopCenteredMessage(
|
||||||
description: widget.games[index].description,
|
icon: Icons.info,
|
||||||
badgeText: translateRulesetToString(
|
title: loc.info,
|
||||||
widget.games[index].ruleset,
|
message: loc.no_games_created_yet,
|
||||||
|
),
|
||||||
|
child: TopCenteredMessage(
|
||||||
|
icon: Icons.info,
|
||||||
|
title: loc.info,
|
||||||
|
message: AppLocalizations.of(
|
||||||
context,
|
context,
|
||||||
),
|
).there_are_no_games_matching_your_search,
|
||||||
isHighlighted: selectedGameId == widget.games[index].id,
|
),
|
||||||
onPressed: () async {
|
),
|
||||||
setState(() {
|
child: ListView.builder(
|
||||||
if (selectedGameId != widget.games[index].id) {
|
itemCount: filteredGames.length,
|
||||||
selectedGameId = widget.games[index].id;
|
itemBuilder: (BuildContext context, int index) {
|
||||||
} else {
|
final game = filteredGames[index];
|
||||||
selectedGameId = '';
|
return GameTile(
|
||||||
|
title: game.name,
|
||||||
|
description: game.description,
|
||||||
|
badgeText: translateRulesetToString(
|
||||||
|
game.ruleset,
|
||||||
|
context,
|
||||||
|
),
|
||||||
|
badgeColor: getColorFromGameColor(game.color),
|
||||||
|
isHighlighted: selectedGameId == game.id,
|
||||||
|
onTap: () async {
|
||||||
|
setState(() {
|
||||||
|
if (selectedGameId == game.id) {
|
||||||
|
selectedGameId = '';
|
||||||
|
} else {
|
||||||
|
selectedGameId = game.id;
|
||||||
|
}
|
||||||
|
});
|
||||||
|
},
|
||||||
|
onLongPress: () async {
|
||||||
|
final result = await Navigator.push(
|
||||||
|
context,
|
||||||
|
adaptivePageRoute(
|
||||||
|
builder: (context) => CreateGameView(
|
||||||
|
gameToEdit: game,
|
||||||
|
matchCount: getMatchCount(game),
|
||||||
|
onGameChanged: () {
|
||||||
|
widget.onGamesUpdated?.call();
|
||||||
|
},
|
||||||
|
),
|
||||||
|
),
|
||||||
|
);
|
||||||
|
if (result != null && result.game != null) {
|
||||||
|
// Find the index in the original list to mutate
|
||||||
|
final originalIndex = widget.games.indexWhere(
|
||||||
|
(g) => g.id == game.id,
|
||||||
|
);
|
||||||
|
if (originalIndex == -1) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
if (result.delete) {
|
||||||
|
setState(() {
|
||||||
|
// deselect the game
|
||||||
|
if (selectedGameId == game.id) {
|
||||||
|
selectedGameId = '';
|
||||||
|
}
|
||||||
|
widget.games.removeAt(originalIndex);
|
||||||
|
widget.onGamesUpdated?.call();
|
||||||
|
});
|
||||||
|
} else {
|
||||||
|
setState(() {
|
||||||
|
widget.games[originalIndex] = result.game;
|
||||||
|
});
|
||||||
|
}
|
||||||
|
_refreshFromSource();
|
||||||
}
|
}
|
||||||
});
|
},
|
||||||
},
|
);
|
||||||
);
|
},
|
||||||
},
|
),
|
||||||
),
|
),
|
||||||
),
|
),
|
||||||
],
|
],
|
||||||
@@ -110,4 +222,39 @@ class _ChooseGameViewState extends State<ChooseGameView> {
|
|||||||
),
|
),
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// Applies the search filter to the games list based on [query].
|
||||||
|
void _applySearchFilter(String query) {
|
||||||
|
final q = query.toLowerCase().trim();
|
||||||
|
if (q.isEmpty) {
|
||||||
|
setState(() {
|
||||||
|
filteredGames = List<Game>.from(widget.games);
|
||||||
|
});
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
setState(() {
|
||||||
|
filteredGames = widget.games.where((game) {
|
||||||
|
final name = game.name.toLowerCase();
|
||||||
|
final description = game.description.toLowerCase();
|
||||||
|
return name.contains(q) || description.contains(q);
|
||||||
|
}).toList();
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Re-applies the current filter after the underlying games list changed.
|
||||||
|
void _refreshFromSource() {
|
||||||
|
_applySearchFilter(searchBarController.text);
|
||||||
|
}
|
||||||
|
|
||||||
|
Future<void> fetchGameCounts() async {
|
||||||
|
gameCounts = await db.gameDao.getGameUsage();
|
||||||
|
}
|
||||||
|
|
||||||
|
// Returns the number of matches that use the given [game].
|
||||||
|
int getMatchCount(Game game) {
|
||||||
|
return gameCounts
|
||||||
|
.firstWhere((gc) => gc.$1.id == game.id, orElse: () => (game, 0))
|
||||||
|
.$2;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -0,0 +1,520 @@
|
|||||||
|
import 'dart:math';
|
||||||
|
|
||||||
|
import 'package:flutter/material.dart';
|
||||||
|
import 'package:flutter_popup/flutter_popup.dart';
|
||||||
|
import 'package:provider/provider.dart';
|
||||||
|
import 'package:tallee/core/common.dart';
|
||||||
|
import 'package:tallee/core/constants.dart';
|
||||||
|
import 'package:tallee/core/custom_theme.dart';
|
||||||
|
import 'package:tallee/core/enums.dart';
|
||||||
|
import 'package:tallee/data/db/database.dart';
|
||||||
|
import 'package:tallee/data/models/game.dart';
|
||||||
|
import 'package:tallee/data/models/group.dart';
|
||||||
|
import 'package:tallee/l10n/generated/app_localizations.dart';
|
||||||
|
import 'package:tallee/presentation/widgets/buttons/custom_width_button.dart';
|
||||||
|
import 'package:tallee/presentation/widgets/dialog/custom_alert_dialog.dart';
|
||||||
|
import 'package:tallee/presentation/widgets/dialog/custom_dialog_action.dart';
|
||||||
|
import 'package:tallee/presentation/widgets/text_input/text_input_field.dart';
|
||||||
|
import 'package:tallee/presentation/widgets/tiles/choose_tile.dart';
|
||||||
|
|
||||||
|
/// A stateful widget for creating or editing a game.
|
||||||
|
/// - [gameToEdit] An optional game to prefill the fields
|
||||||
|
/// - [onGameChanged] Callback to invoke when the game is created or edited
|
||||||
|
class CreateGameView extends StatefulWidget {
|
||||||
|
const CreateGameView({
|
||||||
|
super.key,
|
||||||
|
required this.onGameChanged,
|
||||||
|
this.gameToEdit,
|
||||||
|
this.matchCount = 0,
|
||||||
|
});
|
||||||
|
|
||||||
|
/// Callback to invoke when the game is created or edited
|
||||||
|
final VoidCallback onGameChanged;
|
||||||
|
|
||||||
|
/// An optional game to prefill the fields
|
||||||
|
final Game? gameToEdit;
|
||||||
|
|
||||||
|
final int matchCount;
|
||||||
|
|
||||||
|
@override
|
||||||
|
State<CreateGameView> createState() => _CreateGameViewState();
|
||||||
|
}
|
||||||
|
|
||||||
|
class _CreateGameViewState extends State<CreateGameView> {
|
||||||
|
/// GlobalKey for ScaffoldMessenger to show snackbars
|
||||||
|
final _scaffoldMessengerKey = GlobalKey<ScaffoldMessengerState>();
|
||||||
|
|
||||||
|
late final AppDatabase db;
|
||||||
|
|
||||||
|
late List<(Ruleset, String)> _rulesets;
|
||||||
|
Ruleset? selectedRuleset = Ruleset.singleWinner;
|
||||||
|
|
||||||
|
late List<(GameColor, String)> _colors;
|
||||||
|
GameColor? selectedColor = GameColor.orange;
|
||||||
|
|
||||||
|
/// Controller for the game name input field.
|
||||||
|
final _gameNameController = TextEditingController();
|
||||||
|
|
||||||
|
/// Controller for the game description input field.
|
||||||
|
final _descriptionController = TextEditingController();
|
||||||
|
|
||||||
|
/// The ID of the currently selected group.
|
||||||
|
late String selectedGroupId;
|
||||||
|
|
||||||
|
/// A controller for the search bar input field.
|
||||||
|
final TextEditingController controller = TextEditingController();
|
||||||
|
|
||||||
|
/// A list of groups filtered based on the search query.
|
||||||
|
late final List<Group> filteredGroups;
|
||||||
|
|
||||||
|
@override
|
||||||
|
void initState() {
|
||||||
|
super.initState();
|
||||||
|
db = Provider.of<AppDatabase>(context, listen: false);
|
||||||
|
_gameNameController.addListener(() => setState(() {}));
|
||||||
|
}
|
||||||
|
|
||||||
|
@override
|
||||||
|
void didChangeDependencies() {
|
||||||
|
super.didChangeDependencies();
|
||||||
|
_rulesets = [
|
||||||
|
(
|
||||||
|
Ruleset.singleWinner,
|
||||||
|
translateRulesetToString(Ruleset.singleWinner, context),
|
||||||
|
),
|
||||||
|
(
|
||||||
|
Ruleset.singleLoser,
|
||||||
|
translateRulesetToString(Ruleset.singleLoser, context),
|
||||||
|
),
|
||||||
|
(
|
||||||
|
Ruleset.highestScore,
|
||||||
|
translateRulesetToString(Ruleset.highestScore, context),
|
||||||
|
),
|
||||||
|
(
|
||||||
|
Ruleset.lowestScore,
|
||||||
|
translateRulesetToString(Ruleset.lowestScore, context),
|
||||||
|
),
|
||||||
|
(
|
||||||
|
Ruleset.multipleWinners,
|
||||||
|
translateRulesetToString(Ruleset.multipleWinners, context),
|
||||||
|
),
|
||||||
|
];
|
||||||
|
_colors = [
|
||||||
|
(GameColor.green, translateGameColorToString(GameColor.green, context)),
|
||||||
|
(GameColor.teal, translateGameColorToString(GameColor.teal, context)),
|
||||||
|
(GameColor.blue, translateGameColorToString(GameColor.blue, context)),
|
||||||
|
(GameColor.purple, translateGameColorToString(GameColor.purple, context)),
|
||||||
|
(GameColor.pink, translateGameColorToString(GameColor.pink, context)),
|
||||||
|
(GameColor.red, translateGameColorToString(GameColor.red, context)),
|
||||||
|
(GameColor.orange, translateGameColorToString(GameColor.orange, context)),
|
||||||
|
(GameColor.yellow, translateGameColorToString(GameColor.yellow, context)),
|
||||||
|
];
|
||||||
|
|
||||||
|
if (widget.gameToEdit != null) {
|
||||||
|
_gameNameController.text = widget.gameToEdit!.name;
|
||||||
|
_descriptionController.text = widget.gameToEdit!.description;
|
||||||
|
selectedRuleset = widget.gameToEdit!.ruleset;
|
||||||
|
selectedColor = widget.gameToEdit!.color;
|
||||||
|
selectedRuleset = widget.gameToEdit!.ruleset;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
@override
|
||||||
|
void dispose() {
|
||||||
|
_gameNameController.dispose();
|
||||||
|
_descriptionController.dispose();
|
||||||
|
super.dispose();
|
||||||
|
}
|
||||||
|
|
||||||
|
@override
|
||||||
|
Widget build(BuildContext context) {
|
||||||
|
var loc = AppLocalizations.of(context);
|
||||||
|
final isEditing = widget.gameToEdit != null;
|
||||||
|
|
||||||
|
return ScaffoldMessenger(
|
||||||
|
child: Scaffold(
|
||||||
|
backgroundColor: CustomTheme.backgroundColor,
|
||||||
|
appBar: AppBar(
|
||||||
|
title: Text(isEditing ? loc.edit_game : loc.create_game),
|
||||||
|
actions: [
|
||||||
|
if (isEditMode())
|
||||||
|
IconButton(
|
||||||
|
icon: const Icon(Icons.delete),
|
||||||
|
onPressed: () async {
|
||||||
|
if (!context.mounted) return;
|
||||||
|
|
||||||
|
// Build the dialog content based on match count
|
||||||
|
final String dialogContent = widget.matchCount > 0
|
||||||
|
? loc.delete_game_with_matches_warning(widget.matchCount)
|
||||||
|
: loc.this_cannot_be_undone;
|
||||||
|
|
||||||
|
showDialog<bool>(
|
||||||
|
context: context,
|
||||||
|
builder: (context) => CustomAlertDialog(
|
||||||
|
title: loc.delete_game,
|
||||||
|
content: Text(
|
||||||
|
dialogContent,
|
||||||
|
style: const TextStyle(fontSize: 15),
|
||||||
|
),
|
||||||
|
actions: [
|
||||||
|
CustomDialogAction(
|
||||||
|
isDestructive: true,
|
||||||
|
onPressed: () => Navigator.of(context).pop(true),
|
||||||
|
text: loc.delete,
|
||||||
|
),
|
||||||
|
CustomDialogAction(
|
||||||
|
onPressed: () => Navigator.of(context).pop(false),
|
||||||
|
buttonType: ButtonType.secondary,
|
||||||
|
text: loc.cancel,
|
||||||
|
),
|
||||||
|
],
|
||||||
|
),
|
||||||
|
).then((confirmed) async {
|
||||||
|
if (confirmed == true && context.mounted) {
|
||||||
|
// Delete assocaited matches
|
||||||
|
if (widget.matchCount > 0) {
|
||||||
|
await db.matchDao.deleteMatchesByGame(
|
||||||
|
gameId: widget.gameToEdit!.id,
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
// Delete the targetted game
|
||||||
|
bool success = await db.gameDao.deleteGame(
|
||||||
|
gameId: widget.gameToEdit!.id,
|
||||||
|
);
|
||||||
|
|
||||||
|
if (!context.mounted) return;
|
||||||
|
if (success) {
|
||||||
|
widget.onGameChanged.call();
|
||||||
|
Navigator.of(
|
||||||
|
context,
|
||||||
|
).pop((game: widget.gameToEdit, delete: true));
|
||||||
|
} else {
|
||||||
|
if (!mounted) return;
|
||||||
|
showSnackbar(message: loc.error_deleting_game);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
});
|
||||||
|
},
|
||||||
|
),
|
||||||
|
],
|
||||||
|
),
|
||||||
|
body: SafeArea(
|
||||||
|
child: Column(
|
||||||
|
children: [
|
||||||
|
// Game name input field
|
||||||
|
Container(
|
||||||
|
margin: CustomTheme.tileMargin,
|
||||||
|
child: TextInputField(
|
||||||
|
controller: _gameNameController,
|
||||||
|
maxLength: Constants.MAX_MATCH_NAME_LENGTH,
|
||||||
|
hintText: loc.game_name,
|
||||||
|
),
|
||||||
|
),
|
||||||
|
|
||||||
|
// Choose ruleset tile
|
||||||
|
if (!isEditMode())
|
||||||
|
ChooseTile(title: loc.ruleset, trailing: getColorDropdown(loc)),
|
||||||
|
sneeex
commented
meinste nicht, dass man die tiles hier nicht lieber alle auslagern sollte? die sind arg lang meinste nicht, dass man die tiles hier nicht lieber alle auslagern sollte? die sind arg lang
flixcoo
commented
Ja das ding ist die werden halt nur einmal verwendet Ja das ding ist die werden halt nur einmal verwendet
sneeex
commented
ja oder wenigstens ausgelagert in der datei? ja oder wenigstens ausgelagert in der datei?
flixcoo
commented
ich kanns sonst als funktion unten drunter packen? ich kanns sonst als funktion unten drunter packen?
sneeex
commented
Ja genau Ja genau
|
|||||||
|
|
||||||
|
// Choose color tile
|
||||||
|
ChooseTile(title: loc.color, trailing: getRulesetDropdown(loc)),
|
||||||
|
|
||||||
|
// Description input field
|
||||||
|
Container(
|
||||||
|
margin: CustomTheme.tileMargin,
|
||||||
|
child: TextInputField(
|
||||||
|
controller: _descriptionController,
|
||||||
|
hintText: loc.description,
|
||||||
|
minLines: 6,
|
||||||
|
maxLines: 6,
|
||||||
|
maxLength: Constants.MAX_GAME_DESCRIPTION_LENGTH,
|
||||||
|
showCounterText: true,
|
||||||
|
),
|
||||||
|
),
|
||||||
|
|
||||||
|
const Spacer(),
|
||||||
|
|
||||||
|
// Create/Edit game button
|
||||||
|
Padding(
|
||||||
|
padding: const EdgeInsets.all(12.0),
|
||||||
|
child: CustomWidthButton(
|
||||||
|
text: isEditing ? loc.edit_game : loc.create_game,
|
||||||
|
sizeRelativeToWidth: 1,
|
||||||
|
buttonType: ButtonType.primary,
|
||||||
|
onPressed:
|
||||||
|
_gameNameController.text.trim().isNotEmpty &&
|
||||||
|
selectedRuleset != null &&
|
||||||
|
selectedColor != null
|
||||||
|
? () async {
|
||||||
|
Game newGame = Game(
|
||||||
|
name: _gameNameController.text.trim(),
|
||||||
|
description: _descriptionController.text.trim(),
|
||||||
|
ruleset: selectedRuleset!,
|
||||||
|
color: selectedColor!,
|
||||||
|
);
|
||||||
|
if (isEditing) {
|
||||||
|
await handleGameUpdate(newGame);
|
||||||
|
} else {
|
||||||
|
await handleGameCreation(newGame);
|
||||||
|
}
|
||||||
|
widget.onGameChanged.call();
|
||||||
|
if (context.mounted) {
|
||||||
|
Navigator.of(
|
||||||
|
context,
|
||||||
|
).pop((game: newGame, delete: false));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
: null,
|
||||||
|
),
|
||||||
|
),
|
||||||
|
],
|
||||||
|
),
|
||||||
|
),
|
||||||
|
),
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Handles updating an existing game in the database.
|
||||||
|
///
|
||||||
|
/// [newGame] The updated game object.
|
||||||
|
Future<void> handleGameUpdate(Game newGame) async {
|
||||||
|
final oldGame = widget.gameToEdit!;
|
||||||
|
|
||||||
|
if (oldGame.name != newGame.name) {
|
||||||
|
await db.gameDao.updateGameName(gameId: oldGame.id, name: newGame.name);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (oldGame.description != newGame.description) {
|
||||||
|
await db.gameDao.updateGameDescription(
|
||||||
|
gameId: oldGame.id,
|
||||||
|
description: newGame.description,
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (oldGame.ruleset != newGame.ruleset) {
|
||||||
|
await db.gameDao.updateGameRuleset(
|
||||||
|
gameId: oldGame.id,
|
||||||
|
ruleset: newGame.ruleset,
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (oldGame.color != newGame.color) {
|
||||||
|
await db.gameDao.updateGameColor(
|
||||||
|
gameId: oldGame.id,
|
||||||
|
color: newGame.color,
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (oldGame.icon != newGame.icon) {
|
||||||
|
await db.gameDao.updateGameIcon(gameId: oldGame.id, icon: newGame.icon);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Handles creating a new game in the database.
|
||||||
|
///
|
||||||
|
/// [newGame] The game object to be created.
|
||||||
|
Future<void> handleGameCreation(Game newGame) async {
|
||||||
|
await db.gameDao.addGame(game: newGame);
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Displays a snackbar with the given message and optional action.
|
||||||
|
///
|
||||||
|
/// [message] The message to display in the snackbar.
|
||||||
|
void showSnackbar({required String message}) {
|
||||||
|
final messenger = _scaffoldMessengerKey.currentState;
|
||||||
|
if (messenger != null) {
|
||||||
|
messenger.hideCurrentSnackBar();
|
||||||
|
messenger.showSnackBar(
|
||||||
|
SnackBar(
|
||||||
|
content: Text(message, style: const TextStyle(color: Colors.white)),
|
||||||
|
backgroundColor: CustomTheme.boxColor,
|
||||||
|
),
|
||||||
|
);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
bool isEditMode() {
|
||||||
|
return widget.gameToEdit != null;
|
||||||
|
}
|
||||||
|
|
||||||
|
Widget getRulesetDropdown(AppLocalizations loc) {
|
||||||
|
return CustomPopup(
|
||||||
|
showArrow: true,
|
||||||
|
arrowColor: CustomTheme.boxBorderColor,
|
||||||
|
contentPadding: const EdgeInsets.symmetric(horizontal: 0, vertical: 10),
|
||||||
|
barrierColor: Colors.transparent,
|
||||||
|
contentDecoration: CustomTheme.standardBoxDecoration,
|
||||||
|
content: StatefulBuilder(
|
||||||
|
builder: (context, setPopupState) => SizedBox(
|
||||||
|
width: 280,
|
||||||
|
child: Column(
|
||||||
|
mainAxisSize: MainAxisSize.min,
|
||||||
|
crossAxisAlignment: CrossAxisAlignment.start,
|
||||||
|
children: List.generate(
|
||||||
|
_rulesets.length,
|
||||||
|
(index) => GestureDetector(
|
||||||
|
onTap: () {
|
||||||
|
setState(() {
|
||||||
|
selectedRuleset = _rulesets[index].$1;
|
||||||
|
});
|
||||||
|
setPopupState(() {});
|
||||||
|
},
|
||||||
|
child: Column(
|
||||||
|
children: [
|
||||||
|
Container(
|
||||||
|
margin: const EdgeInsets.symmetric(horizontal: 12),
|
||||||
|
decoration: BoxDecoration(
|
||||||
|
borderRadius: const BorderRadius.all(
|
||||||
|
Radius.circular(8),
|
||||||
|
),
|
||||||
|
color: selectedRuleset == _rulesets[index].$1
|
||||||
|
? CustomTheme.textColor.withAlpha(20)
|
||||||
|
: Colors.transparent,
|
||||||
|
),
|
||||||
|
child: Padding(
|
||||||
|
padding: const EdgeInsets.symmetric(
|
||||||
|
vertical: 8,
|
||||||
|
horizontal: 16,
|
||||||
|
),
|
||||||
|
child: Row(
|
||||||
|
spacing: 8,
|
||||||
|
children: [
|
||||||
|
Icon(getRulesetIcon(_rulesets[index].$1), size: 16),
|
||||||
|
Text(
|
||||||
|
_rulesets[index].$2,
|
||||||
|
style: const TextStyle(
|
||||||
|
color: CustomTheme.textColor,
|
||||||
|
fontSize: 15,
|
||||||
|
),
|
||||||
|
),
|
||||||
|
],
|
||||||
|
),
|
||||||
|
),
|
||||||
|
),
|
||||||
|
if (index < _rulesets.length - 1)
|
||||||
|
const Divider(indent: 15, endIndent: 15),
|
||||||
|
],
|
||||||
|
),
|
||||||
|
),
|
||||||
|
),
|
||||||
|
),
|
||||||
|
),
|
||||||
|
),
|
||||||
|
child: Row(
|
||||||
|
spacing: 8,
|
||||||
|
children: [
|
||||||
|
Icon(getRulesetIcon(selectedRuleset!), size: 16),
|
||||||
|
Padding(
|
||||||
|
padding: const EdgeInsets.only(right: 5),
|
||||||
|
child: Text(
|
||||||
|
translateRulesetToString(selectedRuleset!, context),
|
||||||
|
textAlign: TextAlign.right,
|
||||||
|
),
|
||||||
|
),
|
||||||
|
Transform.rotate(
|
||||||
|
angle: pi / 2,
|
||||||
|
child: const Icon(Icons.arrow_forward_ios, size: 16),
|
||||||
|
),
|
||||||
|
],
|
||||||
|
),
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
Widget getColorDropdown(AppLocalizations loc) {
|
||||||
|
return CustomPopup(
|
||||||
|
showArrow: true,
|
||||||
|
arrowColor: CustomTheme.boxBorderColor,
|
||||||
|
contentPadding: const EdgeInsets.symmetric(horizontal: 0, vertical: 10),
|
||||||
|
barrierColor: Colors.transparent,
|
||||||
|
contentDecoration: CustomTheme.standardBoxDecoration,
|
||||||
|
content: StatefulBuilder(
|
||||||
|
builder: (context, setPopupState) => SizedBox(
|
||||||
|
width: 150,
|
||||||
|
child: Column(
|
||||||
|
mainAxisSize: MainAxisSize.min,
|
||||||
|
crossAxisAlignment: CrossAxisAlignment.start,
|
||||||
|
children: List.generate(
|
||||||
|
_colors.length,
|
||||||
|
(index) => GestureDetector(
|
||||||
|
onTap: () {
|
||||||
|
setState(() {
|
||||||
|
selectedColor = _colors[index].$1;
|
||||||
|
});
|
||||||
|
setPopupState(() {});
|
||||||
|
},
|
||||||
|
child: Column(
|
||||||
|
children: [
|
||||||
|
// Selected Highlighting
|
||||||
|
Container(
|
||||||
|
margin: const EdgeInsets.symmetric(horizontal: 12),
|
||||||
|
decoration: BoxDecoration(
|
||||||
|
borderRadius: const BorderRadius.all(
|
||||||
|
Radius.circular(8),
|
||||||
|
),
|
||||||
|
color: selectedColor == _colors[index].$1
|
||||||
|
? CustomTheme.textColor.withAlpha(20)
|
||||||
|
: Colors.transparent,
|
||||||
|
),
|
||||||
|
child: Padding(
|
||||||
|
padding: const EdgeInsets.symmetric(vertical: 6),
|
||||||
|
child: Row(
|
||||||
|
spacing: 8,
|
||||||
|
children: selectedColor == null
|
||||||
|
? [Text(loc.none)]
|
||||||
|
: [
|
||||||
|
Container(
|
||||||
|
width: 16,
|
||||||
|
height: 16,
|
||||||
|
margin: const EdgeInsets.only(left: 12),
|
||||||
|
decoration: BoxDecoration(
|
||||||
|
color: getColorFromGameColor(
|
||||||
|
_colors[index].$1,
|
||||||
|
),
|
||||||
|
shape: BoxShape.circle,
|
||||||
|
),
|
||||||
|
),
|
||||||
|
Text(
|
||||||
|
_colors[index].$2,
|
||||||
|
style: const TextStyle(
|
||||||
|
color: CustomTheme.textColor,
|
||||||
|
fontSize: 15,
|
||||||
|
),
|
||||||
|
),
|
||||||
|
],
|
||||||
|
),
|
||||||
|
),
|
||||||
|
),
|
||||||
|
if (index < _colors.length - 1)
|
||||||
|
const Divider(indent: 15, endIndent: 15),
|
||||||
|
],
|
||||||
|
),
|
||||||
|
),
|
||||||
|
),
|
||||||
|
),
|
||||||
|
),
|
||||||
|
),
|
||||||
|
child: Row(
|
||||||
|
spacing: 8,
|
||||||
|
children: [
|
||||||
|
// Selected Color
|
||||||
|
Container(
|
||||||
|
width: 16,
|
||||||
|
height: 16,
|
||||||
|
decoration: BoxDecoration(
|
||||||
|
color: getColorFromGameColor(selectedColor!),
|
||||||
|
shape: BoxShape.circle,
|
||||||
|
),
|
||||||
|
),
|
||||||
|
Padding(
|
||||||
|
padding: const EdgeInsets.only(right: 5),
|
||||||
|
child: Text(translateGameColorToString(selectedColor!, context)),
|
||||||
|
),
|
||||||
|
Transform.rotate(
|
||||||
|
angle: pi / 2,
|
||||||
|
child: const Icon(Icons.arrow_forward_ios, size: 16),
|
||||||
|
),
|
||||||
|
],
|
||||||
|
),
|
||||||
|
);
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -28,10 +28,13 @@ class CreateMatchView extends StatefulWidget {
|
|||||||
this.onWinnerChanged,
|
this.onWinnerChanged,
|
||||||
this.matchToEdit,
|
this.matchToEdit,
|
||||||
this.onMatchUpdated,
|
this.onMatchUpdated,
|
||||||
|
this.onMatchesUpdated,
|
||||||
});
|
});
|
||||||
|
|
||||||
final VoidCallback? onWinnerChanged;
|
final VoidCallback? onWinnerChanged;
|
||||||
|
|
||||||
|
final VoidCallback? onMatchesUpdated;
|
||||||
|
sneeex marked this conversation as resolved
sneeex
commented
ist das das callback wenn ein match im edit view/create view gemacht wurde und dann in der liste aktualisiert werden soll? ist das das callback wenn ein match im edit view/create view gemacht wurde und dann in der liste aktualisiert werden soll?
flixcoo
commented
das ist der callback für die MatchDetailView an erster stelle, um dort das Match zu aktualisieren das ist der callback für die MatchDetailView an erster stelle, um dort das Match zu aktualisieren
sneeex
commented
ne das ist doch on match update, on matches updated ist doch was anderes? ne das ist doch on match update, on matches updated ist doch was anderes?
flixcoo
commented
Ja onMatchUpdate ist für ein einzelnes Match und onMatchesUpdate für alle Matches im MatchView Ja onMatchUpdate ist für ein einzelnes Match und onMatchesUpdate für alle Matches im MatchView
|
|||||||
|
|
||||||
final void Function(Match)? onMatchUpdated;
|
final void Function(Match)? onMatchUpdated;
|
||||||
|
|
||||||
/// An optional match to prefill the fields for editing.
|
/// An optional match to prefill the fields for editing.
|
||||||
@@ -115,6 +118,7 @@ class _CreateMatchViewState extends State<CreateMatchView> {
|
|||||||
child: Column(
|
child: Column(
|
||||||
mainAxisAlignment: MainAxisAlignment.start,
|
mainAxisAlignment: MainAxisAlignment.start,
|
||||||
children: [
|
children: [
|
||||||
|
// Match name input field.
|
||||||
Container(
|
Container(
|
||||||
margin: CustomTheme.tileMargin,
|
margin: CustomTheme.tileMargin,
|
||||||
child: TextInputField(
|
child: TextInputField(
|
||||||
@@ -123,34 +127,40 @@ class _CreateMatchViewState extends State<CreateMatchView> {
|
|||||||
maxLength: Constants.MAX_MATCH_NAME_LENGTH,
|
maxLength: Constants.MAX_MATCH_NAME_LENGTH,
|
||||||
),
|
),
|
||||||
),
|
),
|
||||||
ChooseTile(
|
|
||||||
title: loc.game,
|
// Game selection tile.
|
||||||
trailingText: selectedGame == null
|
if (!isEditMode())
|
||||||
? loc.none_group
|
ChooseTile(
|
||||||
: selectedGame!.name,
|
title: loc.game,
|
||||||
onPressed: () async {
|
trailing: selectedGame == null
|
||||||
selectedGame = await Navigator.of(context).push(
|
? Text(loc.none_group)
|
||||||
adaptivePageRoute(
|
: Text(selectedGame!.name),
|
||||||
builder: (context) => ChooseGameView(
|
onPressed: () async {
|
||||||
games: gamesList,
|
selectedGame = await Navigator.of(context).push(
|
||||||
initialGameId: selectedGame?.id ?? '',
|
adaptivePageRoute(
|
||||||
|
builder: (context) => ChooseGameView(
|
||||||
|
games: gamesList,
|
||||||
|
initialGameId: selectedGame?.id ?? '',
|
||||||
|
onGamesUpdated: widget.onMatchesUpdated,
|
||||||
|
),
|
||||||
),
|
),
|
||||||
),
|
);
|
||||||
);
|
setState(() {
|
||||||
setState(() {
|
if (selectedGame != null) {
|
||||||
if (selectedGame != null) {
|
hintText = selectedGame!.name;
|
||||||
hintText = selectedGame!.name;
|
} else {
|
||||||
} else {
|
hintText = loc.match_name;
|
||||||
hintText = loc.match_name;
|
}
|
||||||
}
|
});
|
||||||
});
|
},
|
||||||
},
|
),
|
||||||
),
|
|
||||||
|
// Group selection tile.
|
||||||
ChooseTile(
|
ChooseTile(
|
||||||
title: loc.group,
|
title: loc.group,
|
||||||
trailingText: selectedGroup == null
|
trailing: selectedGroup == null
|
||||||
? loc.none_group
|
? Text(loc.none_group)
|
||||||
: selectedGroup!.name,
|
: Text(selectedGroup!.name),
|
||||||
onPressed: () async {
|
onPressed: () async {
|
||||||
// Remove all players from the previously selected group from
|
// Remove all players from the previously selected group from
|
||||||
// the selected players list, in case the user deselects the
|
// the selected players list, in case the user deselects the
|
||||||
@@ -181,6 +191,8 @@ class _CreateMatchViewState extends State<CreateMatchView> {
|
|||||||
});
|
});
|
||||||
},
|
},
|
||||||
),
|
),
|
||||||
|
|
||||||
|
// Player selection widget.
|
||||||
Expanded(
|
Expanded(
|
||||||
child: PlayerSelection(
|
child: PlayerSelection(
|
||||||
key: ValueKey(selectedGroup?.id ?? 'no_group'),
|
key: ValueKey(selectedGroup?.id ?? 'no_group'),
|
||||||
@@ -193,6 +205,8 @@ class _CreateMatchViewState extends State<CreateMatchView> {
|
|||||||
},
|
},
|
||||||
),
|
),
|
||||||
),
|
),
|
||||||
|
|
||||||
|
// Create or save button.
|
||||||
CustomWidthButton(
|
CustomWidthButton(
|
||||||
text: buttonText,
|
text: buttonText,
|
||||||
sizeRelativeToWidth: 0.95,
|
sizeRelativeToWidth: 0.95,
|
||||||
@@ -218,16 +232,16 @@ class _CreateMatchViewState extends State<CreateMatchView> {
|
|||||||
///
|
///
|
||||||
/// Returns `true` if:
|
/// Returns `true` if:
|
||||||
/// - A ruleset is selected AND
|
/// - A ruleset is selected AND
|
||||||
/// - Either a group is selected OR at least 2 players are selected
|
/// - Either a group is selected OR at least 2 players are selected.
|
||||||
bool _enableCreateGameButton() {
|
bool _enableCreateGameButton() {
|
||||||
return (selectedGroup != null ||
|
return (selectedGroup != null ||
|
||||||
(selectedPlayers.length > 1) && selectedGame != null);
|
(selectedPlayers.length > 1) && selectedGame != null);
|
||||||
}
|
}
|
||||||
|
|
||||||
// If a match was provided to the view, it updates the match in the database
|
/// Handles navigation when the create or save button is pressed.
|
||||||
// and navigates back to the previous screen.
|
///
|
||||||
// If no match was provided, it creates a new match in the database and
|
/// If a match is being edited, updates the match in the database.
|
||||||
// navigates to the MatchResultView for the newly created match.
|
/// Otherwise, creates a new match and navigates to the MatchResultView.
|
||||||
void buttonNavigation(BuildContext context) async {
|
void buttonNavigation(BuildContext context) async {
|
||||||
if (isEditMode()) {
|
if (isEditMode()) {
|
||||||
await updateMatch();
|
await updateMatch();
|
||||||
@@ -252,8 +266,7 @@ class _CreateMatchViewState extends State<CreateMatchView> {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Updates attributes of the existing match in the database based on the
|
/// Updates the existing match in the database.
|
||||||
/// changes made in the edit view.
|
|
||||||
Future<void> updateMatch() async {
|
Future<void> updateMatch() async {
|
||||||
final updatedMatch = Match(
|
final updatedMatch = Match(
|
||||||
id: widget.matchToEdit!.id,
|
id: widget.matchToEdit!.id,
|
||||||
@@ -262,7 +275,7 @@ class _CreateMatchViewState extends State<CreateMatchView> {
|
|||||||
: _matchNameController.text.trim(),
|
: _matchNameController.text.trim(),
|
||||||
group: selectedGroup,
|
group: selectedGroup,
|
||||||
players: selectedPlayers,
|
players: selectedPlayers,
|
||||||
game: widget.matchToEdit!.game,
|
game: selectedGame!,
|
||||||
createdAt: widget.matchToEdit!.createdAt,
|
createdAt: widget.matchToEdit!.createdAt,
|
||||||
endedAt: widget.matchToEdit!.endedAt,
|
endedAt: widget.matchToEdit!.endedAt,
|
||||||
notes: widget.matchToEdit!.notes,
|
notes: widget.matchToEdit!.notes,
|
||||||
|
|||||||
@@ -1,4 +1,5 @@
|
|||||||
import 'package:flutter/material.dart';
|
import 'package:flutter/material.dart';
|
||||||
|
import 'package:fluttericon/rpg_awesome_icons.dart';
|
||||||
import 'package:intl/intl.dart';
|
import 'package:intl/intl.dart';
|
||||||
import 'package:provider/provider.dart';
|
import 'package:provider/provider.dart';
|
||||||
import 'package:tallee/core/adaptive_page_route.dart';
|
import 'package:tallee/core/adaptive_page_route.dart';
|
||||||
@@ -14,6 +15,7 @@ import 'package:tallee/presentation/widgets/buttons/main_menu_button.dart';
|
|||||||
import 'package:tallee/presentation/widgets/colored_icon_container.dart';
|
import 'package:tallee/presentation/widgets/colored_icon_container.dart';
|
||||||
import 'package:tallee/presentation/widgets/dialog/custom_alert_dialog.dart';
|
import 'package:tallee/presentation/widgets/dialog/custom_alert_dialog.dart';
|
||||||
import 'package:tallee/presentation/widgets/dialog/custom_dialog_action.dart';
|
import 'package:tallee/presentation/widgets/dialog/custom_dialog_action.dart';
|
||||||
|
import 'package:tallee/presentation/widgets/game_label.dart';
|
||||||
import 'package:tallee/presentation/widgets/tiles/info_tile.dart';
|
import 'package:tallee/presentation/widgets/tiles/info_tile.dart';
|
||||||
import 'package:tallee/presentation/widgets/tiles/text_icon_tile.dart';
|
import 'package:tallee/presentation/widgets/tiles/text_icon_tile.dart';
|
||||||
|
|
||||||
@@ -102,6 +104,7 @@ class _MatchDetailViewState extends State<MatchDetailView> {
|
|||||||
bottom: 100,
|
bottom: 100,
|
||||||
),
|
),
|
||||||
children: [
|
children: [
|
||||||
|
// Controller Icon
|
||||||
const Center(
|
const Center(
|
||||||
child: ColoredIconContainer(
|
child: ColoredIconContainer(
|
||||||
icon: Icons.sports_esports,
|
icon: Icons.sports_esports,
|
||||||
@@ -110,6 +113,8 @@ class _MatchDetailViewState extends State<MatchDetailView> {
|
|||||||
),
|
),
|
||||||
),
|
),
|
||||||
const SizedBox(height: 10),
|
const SizedBox(height: 10),
|
||||||
|
|
||||||
|
// Match Name
|
||||||
Text(
|
Text(
|
||||||
match.name,
|
match.name,
|
||||||
style: const TextStyle(
|
style: const TextStyle(
|
||||||
@@ -120,6 +125,8 @@ class _MatchDetailViewState extends State<MatchDetailView> {
|
|||||||
textAlign: TextAlign.center,
|
textAlign: TextAlign.center,
|
||||||
),
|
),
|
||||||
const SizedBox(height: 5),
|
const SizedBox(height: 5),
|
||||||
|
|
||||||
|
// 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(match.createdAt)}',
|
||||||
style: const TextStyle(
|
style: const TextStyle(
|
||||||
@@ -129,6 +136,8 @@ class _MatchDetailViewState extends State<MatchDetailView> {
|
|||||||
textAlign: TextAlign.center,
|
textAlign: TextAlign.center,
|
||||||
),
|
),
|
||||||
const SizedBox(height: 10),
|
const SizedBox(height: 10),
|
||||||
|
|
||||||
|
// Group Name
|
||||||
if (match.group != null) ...[
|
if (match.group != null) ...[
|
||||||
Row(
|
Row(
|
||||||
mainAxisAlignment: MainAxisAlignment.center,
|
mainAxisAlignment: MainAxisAlignment.center,
|
||||||
@@ -143,6 +152,8 @@ class _MatchDetailViewState extends State<MatchDetailView> {
|
|||||||
),
|
),
|
||||||
const SizedBox(height: 20),
|
const SizedBox(height: 20),
|
||||||
],
|
],
|
||||||
|
|
||||||
|
// Players
|
||||||
InfoTile(
|
InfoTile(
|
||||||
title: loc.players,
|
title: loc.players,
|
||||||
icon: Icons.people,
|
icon: Icons.people,
|
||||||
@@ -162,6 +173,30 @@ class _MatchDetailViewState extends State<MatchDetailView> {
|
|||||||
),
|
),
|
||||||
),
|
),
|
||||||
const SizedBox(height: 15),
|
const SizedBox(height: 15),
|
||||||
|
|
||||||
|
// Game
|
||||||
|
InfoTile(
|
||||||
|
title: loc.game,
|
||||||
|
icon: RpgAwesome.clovers_card,
|
||||||
|
horizontalAlignment: CrossAxisAlignment.start,
|
||||||
|
content: Padding(
|
||||||
|
padding: const EdgeInsets.symmetric(
|
||||||
|
vertical: 4,
|
||||||
|
horizontal: 8,
|
||||||
|
),
|
||||||
|
child: GameLabel(
|
||||||
|
title: match.game.name,
|
||||||
|
description: translateRulesetToString(
|
||||||
|
match.game.ruleset,
|
||||||
|
context,
|
||||||
|
),
|
||||||
|
color: match.game.color,
|
||||||
|
),
|
||||||
|
),
|
||||||
|
),
|
||||||
|
const SizedBox(height: 15),
|
||||||
|
|
||||||
|
// Results
|
||||||
InfoTile(
|
InfoTile(
|
||||||
title: loc.results,
|
title: loc.results,
|
||||||
icon: Icons.emoji_events,
|
icon: Icons.emoji_events,
|
||||||
|
|||||||
@@ -126,8 +126,10 @@ class _MatchViewState extends State<MatchView> {
|
|||||||
Navigator.push(
|
Navigator.push(
|
||||||
context,
|
context,
|
||||||
adaptivePageRoute(
|
adaptivePageRoute(
|
||||||
builder: (context) =>
|
builder: (context) => CreateMatchView(
|
||||||
CreateMatchView(onWinnerChanged: loadMatches),
|
onWinnerChanged: loadMatches,
|
||||||
|
onMatchesUpdated: loadMatches,
|
||||||
|
),
|
||||||
),
|
),
|
||||||
);
|
);
|
||||||
},
|
},
|
||||||
|
|||||||
@@ -14,6 +14,7 @@ class AnimatedDialogButton extends StatefulWidget {
|
|||||||
required this.onPressed,
|
required this.onPressed,
|
||||||
this.buttonConstraints,
|
this.buttonConstraints,
|
||||||
this.buttonType = ButtonType.primary,
|
this.buttonType = ButtonType.primary,
|
||||||
|
this.isDescructive = false,
|
||||||
});
|
});
|
||||||
|
|
||||||
final String buttonText;
|
final String buttonText;
|
||||||
@@ -24,6 +25,8 @@ class AnimatedDialogButton extends StatefulWidget {
|
|||||||
|
|
||||||
final ButtonType buttonType;
|
final ButtonType buttonType;
|
||||||
|
|
||||||
|
final bool isDescructive;
|
||||||
|
|
||||||
@override
|
@override
|
||||||
State<AnimatedDialogButton> createState() => _AnimatedDialogButtonState();
|
State<AnimatedDialogButton> createState() => _AnimatedDialogButtonState();
|
||||||
}
|
}
|
||||||
@@ -33,28 +36,8 @@ class _AnimatedDialogButtonState extends State<AnimatedDialogButton> {
|
|||||||
|
|
||||||
@override
|
@override
|
||||||
Widget build(BuildContext context) {
|
Widget build(BuildContext context) {
|
||||||
final textStyling = TextStyle(
|
final textStyling = _getTextStyling();
|
||||||
color: widget.buttonType == ButtonType.primary
|
final buttonDecoration = _getButtonDecoration();
|
||||||
? Colors.black
|
|
||||||
: Colors.white,
|
|
||||||
fontSize: 16,
|
|
||||||
fontWeight: FontWeight.bold,
|
|
||||||
);
|
|
||||||
|
|
||||||
final buttonDecoration = widget.buttonType == ButtonType.primary
|
|
||||||
// Primary
|
|
||||||
? BoxDecoration(
|
|
||||||
color: Colors.white,
|
|
||||||
borderRadius: BorderRadius.circular(12),
|
|
||||||
)
|
|
||||||
: widget.buttonType == ButtonType.secondary
|
|
||||||
// Secondary
|
|
||||||
? BoxDecoration(
|
|
||||||
border: BoxBorder.all(color: Colors.white, width: 2),
|
|
||||||
borderRadius: BorderRadius.circular(12),
|
|
||||||
)
|
|
||||||
// Tertiary
|
|
||||||
: const BoxDecoration();
|
|
||||||
|
|
||||||
return GestureDetector(
|
return GestureDetector(
|
||||||
onTapDown: (_) => setState(() => _isPressed = true),
|
onTapDown: (_) => setState(() => _isPressed = true),
|
||||||
@@ -84,4 +67,42 @@ class _AnimatedDialogButtonState extends State<AnimatedDialogButton> {
|
|||||||
),
|
),
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
TextStyle _getTextStyling() {
|
||||||
|
late Color textColor;
|
||||||
|
if (widget.buttonType == ButtonType.primary) {
|
||||||
|
textColor = widget.isDescructive ? Colors.white : Colors.black;
|
||||||
|
} else if (widget.buttonType == ButtonType.secondary) {
|
||||||
|
textColor = widget.isDescructive ? Colors.red : Colors.white;
|
||||||
|
} else {
|
||||||
|
textColor = widget.isDescructive ? Colors.red : Colors.white;
|
||||||
|
}
|
||||||
|
|
||||||
|
return TextStyle(
|
||||||
|
color: textColor,
|
||||||
|
fontSize: 16,
|
||||||
|
fontWeight: FontWeight.bold,
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
BoxDecoration _getButtonDecoration() {
|
||||||
|
if (widget.buttonType == ButtonType.primary) {
|
||||||
|
// Primary
|
||||||
|
return BoxDecoration(
|
||||||
|
color: widget.isDescructive ? Colors.red : Colors.white,
|
||||||
|
borderRadius: BorderRadius.circular(12),
|
||||||
|
);
|
||||||
|
} else if (widget.buttonType == ButtonType.secondary) {
|
||||||
|
// Secondary
|
||||||
|
return BoxDecoration(
|
||||||
|
border: BoxBorder.all(
|
||||||
|
color: widget.isDescructive ? Colors.red : Colors.white,
|
||||||
|
width: 2,
|
||||||
|
),
|
||||||
|
borderRadius: BorderRadius.circular(12),
|
||||||
|
);
|
||||||
|
}
|
||||||
|
// Tertiary
|
||||||
|
return const BoxDecoration();
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -12,6 +12,7 @@ class CustomDialogAction extends StatelessWidget {
|
|||||||
required this.onPressed,
|
required this.onPressed,
|
||||||
required this.text,
|
required this.text,
|
||||||
this.buttonType = ButtonType.primary,
|
this.buttonType = ButtonType.primary,
|
||||||
|
this.isDestructive = false,
|
||||||
});
|
});
|
||||||
|
|
||||||
final String text;
|
final String text;
|
||||||
@@ -20,12 +21,15 @@ class CustomDialogAction extends StatelessWidget {
|
|||||||
|
|
||||||
final VoidCallback onPressed;
|
final VoidCallback onPressed;
|
||||||
|
|
||||||
|
final bool isDestructive;
|
||||||
|
|
||||||
@override
|
@override
|
||||||
Widget build(BuildContext context) {
|
Widget build(BuildContext context) {
|
||||||
return AnimatedDialogButton(
|
return AnimatedDialogButton(
|
||||||
onPressed: onPressed,
|
onPressed: onPressed,
|
||||||
buttonText: text,
|
buttonText: text,
|
||||||
buttonType: buttonType,
|
buttonType: buttonType,
|
||||||
|
isDescructive: isDestructive,
|
||||||
|
sneeex marked this conversation as resolved
sneeex
commented
was macht das? was macht das?
flixcoo
commented
Das macht den Button auf Rot Das macht den Button auf Rot
|
|||||||
buttonConstraints: const BoxConstraints(minWidth: 300),
|
buttonConstraints: const BoxConstraints(minWidth: 300),
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|||||||
71
lib/presentation/widgets/game_label.dart
Normal file
@@ -0,0 +1,71 @@
|
|||||||
|
import 'package:flutter/material.dart';
|
||||||
|
import 'package:tallee/core/common.dart';
|
||||||
|
import 'package:tallee/core/enums.dart';
|
||||||
|
|
||||||
|
class GameLabel extends StatelessWidget {
|
||||||
|
const GameLabel({
|
||||||
|
super.key,
|
||||||
|
required this.title,
|
||||||
|
required this.description,
|
||||||
|
required this.color,
|
||||||
|
});
|
||||||
|
|
||||||
|
final String title;
|
||||||
|
final String description;
|
||||||
|
final GameColor color;
|
||||||
|
|
||||||
|
@override
|
||||||
|
Widget build(BuildContext context) {
|
||||||
|
final backgroundColor = getColorFromGameColor(color);
|
||||||
|
final fontColor = backgroundColor.computeLuminance() > 0.5
|
||||||
|
? Colors.black
|
||||||
|
: Colors.white;
|
||||||
|
|
||||||
|
return IntrinsicHeight(
|
||||||
|
child: Row(
|
||||||
|
mainAxisSize: MainAxisSize.min,
|
||||||
|
children: [
|
||||||
|
// Title
|
||||||
|
Container(
|
||||||
|
decoration: BoxDecoration(
|
||||||
|
color: backgroundColor.withAlpha(230),
|
||||||
|
borderRadius: const BorderRadius.only(
|
||||||
|
topLeft: Radius.circular(8),
|
||||||
|
bottomLeft: Radius.circular(8),
|
||||||
|
),
|
||||||
|
),
|
||||||
|
padding: const EdgeInsets.symmetric(vertical: 4, horizontal: 8),
|
||||||
|
child: Text(
|
||||||
|
title,
|
||||||
|
style: TextStyle(
|
||||||
|
fontSize: 12,
|
||||||
|
color: fontColor,
|
||||||
|
fontWeight: FontWeight.bold,
|
||||||
|
),
|
||||||
|
),
|
||||||
|
),
|
||||||
|
|
||||||
|
// Description
|
||||||
|
Container(
|
||||||
|
decoration: BoxDecoration(
|
||||||
|
color: backgroundColor.withAlpha(140),
|
||||||
|
borderRadius: const BorderRadius.only(
|
||||||
|
topRight: Radius.circular(8),
|
||||||
|
bottomRight: Radius.circular(8),
|
||||||
|
),
|
||||||
|
),
|
||||||
|
padding: const EdgeInsets.symmetric(vertical: 4, horizontal: 8),
|
||||||
|
child: Text(
|
||||||
|
description,
|
||||||
|
style: TextStyle(
|
||||||
|
fontSize: 12,
|
||||||
|
color: fontColor,
|
||||||
|
fontWeight: FontWeight.bold,
|
||||||
|
),
|
||||||
|
),
|
||||||
|
),
|
||||||
|
],
|
||||||
|
),
|
||||||
|
);
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -8,12 +8,18 @@ class TextInputField extends StatelessWidget {
|
|||||||
/// - [onChanged]: Optional callback invoked when the text in the field changes.
|
/// - [onChanged]: Optional callback invoked when the text in the field changes.
|
||||||
/// - [hintText]: The hint text displayed in the text input field when it is empty
|
/// - [hintText]: The hint text displayed in the text input field when it is empty
|
||||||
/// - [maxLength]: Optional parameter for maximum length of the input text.
|
/// - [maxLength]: Optional parameter for maximum length of the input text.
|
||||||
|
/// - [maxLines]: The maximum number of lines for the text input field. Defaults to 1.
|
||||||
|
/// - [minLines]: The minimum number of lines for the text input field. Defaults to 1.
|
||||||
|
/// - [showCounterText]: Whether to show the counter text in the text input field. Defaults to false.
|
||||||
const TextInputField({
|
const TextInputField({
|
||||||
super.key,
|
super.key,
|
||||||
required this.controller,
|
required this.controller,
|
||||||
required this.hintText,
|
required this.hintText,
|
||||||
this.onChanged,
|
this.onChanged,
|
||||||
this.maxLength,
|
this.maxLength,
|
||||||
|
this.maxLines = 1,
|
||||||
|
this.minLines = 1,
|
||||||
|
this.showCounterText = false,
|
||||||
});
|
});
|
||||||
|
|
||||||
/// The controller for the text input field.
|
/// The controller for the text input field.
|
||||||
@@ -28,6 +34,15 @@ class TextInputField extends StatelessWidget {
|
|||||||
/// Optional parameter for maximum length of the input text.
|
/// Optional parameter for maximum length of the input text.
|
||||||
final int? maxLength;
|
final int? maxLength;
|
||||||
|
|
||||||
|
/// The maximum number of lines for the text input field.
|
||||||
|
final int? maxLines;
|
||||||
|
|
||||||
|
/// The minimum number of lines for the text input field.
|
||||||
|
final int? minLines;
|
||||||
|
|
||||||
|
/// Whether to show the counter text in the text input field.
|
||||||
|
final bool showCounterText;
|
||||||
|
|
||||||
@override
|
@override
|
||||||
Widget build(BuildContext context) {
|
Widget build(BuildContext context) {
|
||||||
return TextField(
|
return TextField(
|
||||||
@@ -35,13 +50,15 @@ class TextInputField extends StatelessWidget {
|
|||||||
onChanged: onChanged,
|
onChanged: onChanged,
|
||||||
maxLength: maxLength,
|
maxLength: maxLength,
|
||||||
maxLengthEnforcement: MaxLengthEnforcement.truncateAfterCompositionEnds,
|
maxLengthEnforcement: MaxLengthEnforcement.truncateAfterCompositionEnds,
|
||||||
|
maxLines: maxLines,
|
||||||
|
minLines: minLines,
|
||||||
|
|
||||||
decoration: InputDecoration(
|
decoration: InputDecoration(
|
||||||
filled: true,
|
filled: true,
|
||||||
fillColor: CustomTheme.boxColor,
|
fillColor: CustomTheme.boxColor,
|
||||||
hintText: hintText,
|
hintText: hintText,
|
||||||
hintStyle: const TextStyle(fontSize: 18),
|
hintStyle: const TextStyle(fontSize: 18),
|
||||||
// Hides the character counter
|
counterText: showCounterText ? null : '',
|
||||||
counterText: '',
|
|
||||||
enabledBorder: const OutlineInputBorder(
|
enabledBorder: const OutlineInputBorder(
|
||||||
borderRadius: BorderRadius.all(Radius.circular(12)),
|
borderRadius: BorderRadius.all(Radius.circular(12)),
|
||||||
borderSide: BorderSide(color: CustomTheme.boxBorderColor),
|
borderSide: BorderSide(color: CustomTheme.boxBorderColor),
|
||||||
|
|||||||
@@ -4,12 +4,12 @@ import 'package:tallee/core/custom_theme.dart';
|
|||||||
class ChooseTile extends StatefulWidget {
|
class ChooseTile extends StatefulWidget {
|
||||||
/// A tile widget that allows users to choose an option by tapping on it.
|
/// A tile widget that allows users to choose an option by tapping on it.
|
||||||
/// - [title]: The title text displayed on the tile.
|
/// - [title]: The title text displayed on the tile.
|
||||||
/// - [trailingText]: Optional trailing text displayed on the tile.
|
/// - [trailing]: Optional trailing text displayed on the tile.
|
||||||
/// - [onPressed]: The callback invoked when the tile is tapped.
|
/// - [onPressed]: The callback invoked when the tile is tapped.
|
||||||
const ChooseTile({
|
const ChooseTile({
|
||||||
super.key,
|
super.key,
|
||||||
required this.title,
|
required this.title,
|
||||||
this.trailingText,
|
this.trailing,
|
||||||
this.onPressed,
|
this.onPressed,
|
||||||
});
|
});
|
||||||
|
|
||||||
@@ -20,7 +20,7 @@ class ChooseTile extends StatefulWidget {
|
|||||||
final VoidCallback? onPressed;
|
final VoidCallback? onPressed;
|
||||||
|
|
||||||
/// Optional trailing text displayed on the tile.
|
/// Optional trailing text displayed on the tile.
|
||||||
final String? trailingText;
|
final Widget? trailing;
|
||||||
|
|
||||||
@override
|
@override
|
||||||
State<ChooseTile> createState() => _ChooseTileState();
|
State<ChooseTile> createState() => _ChooseTileState();
|
||||||
@@ -42,9 +42,11 @@ class _ChooseTileState extends State<ChooseTile> {
|
|||||||
style: const TextStyle(fontSize: 16, fontWeight: FontWeight.bold),
|
style: const TextStyle(fontSize: 16, fontWeight: FontWeight.bold),
|
||||||
),
|
),
|
||||||
const Spacer(),
|
const Spacer(),
|
||||||
if (widget.trailingText != null) Text(widget.trailingText!),
|
if (widget.trailing != null) widget.trailing!,
|
||||||
const SizedBox(width: 10),
|
if (widget.onPressed != null) ...[
|
||||||
const Icon(Icons.arrow_forward_ios, size: 16),
|
const SizedBox(width: 10),
|
||||||
|
const Icon(Icons.arrow_forward_ios, size: 16),
|
||||||
|
],
|
||||||
],
|
],
|
||||||
),
|
),
|
||||||
),
|
),
|
||||||
|
|||||||
151
lib/presentation/widgets/tiles/game_tile.dart
Normal file
@@ -0,0 +1,151 @@
|
|||||||
|
import 'package:flutter/material.dart';
|
||||||
|
import 'package:tallee/core/common.dart';
|
||||||
|
import 'package:tallee/core/custom_theme.dart';
|
||||||
|
import 'package:tallee/core/enums.dart';
|
||||||
|
|
||||||
|
class GameTile extends StatelessWidget {
|
||||||
|
/// A list tile widget that displays a title and description, with optional highlighting and badge.
|
||||||
|
/// - [title]: The title text displayed on the tile.
|
||||||
|
/// - [description]: The description text displayed below the title.
|
||||||
|
/// - [onTap]: The callback invoked when the tile is tapped.
|
||||||
|
/// - [onLongPress]: The callback invoked when the tile is tapped.
|
||||||
|
/// - [isHighlighted]: A boolean to determine if the tile should be highlighted.
|
||||||
|
/// - [badgeText]: Optional text to display in a badge on the right side of the title.
|
||||||
|
/// - [badgeColor]: Optional color for the badge background.
|
||||||
|
const GameTile({
|
||||||
|
super.key,
|
||||||
|
required this.title,
|
||||||
|
required this.description,
|
||||||
|
this.onTap,
|
||||||
|
this.onLongPress,
|
||||||
|
this.isHighlighted = false,
|
||||||
|
this.badgeText,
|
||||||
|
this.badgeColor,
|
||||||
|
});
|
||||||
|
|
||||||
|
/// The title text displayed on the tile.
|
||||||
|
final String title;
|
||||||
|
|
||||||
|
/// The description text displayed below the title.
|
||||||
|
final String description;
|
||||||
|
|
||||||
|
/// The callback invoked when the tile is tapped.
|
||||||
|
final VoidCallback? onTap;
|
||||||
|
|
||||||
|
/// The callback invoked when the tile is long-pressed.
|
||||||
|
final VoidCallback? onLongPress;
|
||||||
|
|
||||||
|
/// A boolean to determine if the tile should be highlighted.
|
||||||
|
final bool isHighlighted;
|
||||||
|
|
||||||
|
/// Optional text to display in a badge on the right side of the title.
|
||||||
|
final String? badgeText;
|
||||||
|
|
||||||
|
/// Optional color for the badge background.
|
||||||
|
final Color? badgeColor;
|
||||||
|
|
||||||
|
@override
|
||||||
|
Widget build(BuildContext context) {
|
||||||
|
final badgeTextColor = badgeColor != null
|
||||||
|
? (badgeColor!.computeLuminance() > 0.5 ? Colors.black : Colors.white)
|
||||||
|
: Colors.white;
|
||||||
|
|
||||||
|
final gameColor = badgeColor ?? getColorFromGameColor(GameColor.orange);
|
||||||
|
|
||||||
|
return GestureDetector(
|
||||||
|
onTap: onTap,
|
||||||
|
onLongPress: onLongPress,
|
||||||
|
child: AnimatedContainer(
|
||||||
|
margin: const EdgeInsets.symmetric(vertical: 10, horizontal: 10),
|
||||||
|
decoration: !isHighlighted
|
||||||
|
? CustomTheme.standardBoxDecoration
|
||||||
|
: CustomTheme.highlightedBoxDecoration.copyWith(
|
||||||
|
border: Border.all(
|
||||||
|
color: gameColor.withValues(alpha: 0.9),
|
||||||
|
width: 2,
|
||||||
|
),
|
||||||
|
),
|
||||||
|
duration: const Duration(milliseconds: 200),
|
||||||
|
child: Stack(
|
||||||
|
children: [
|
||||||
|
// Gradient overlay
|
||||||
|
Positioned.fill(
|
||||||
|
child: Container(
|
||||||
|
decoration: BoxDecoration(
|
||||||
|
borderRadius: BorderRadius.circular(8),
|
||||||
|
gradient: LinearGradient(
|
||||||
|
begin: Alignment.topLeft,
|
||||||
|
end: Alignment.bottomRight,
|
||||||
|
colors: [
|
||||||
|
gameColor.withValues(alpha: 0.08),
|
||||||
|
gameColor.withValues(alpha: 0.02),
|
||||||
|
Colors.transparent,
|
||||||
|
],
|
||||||
|
stops: const [0.0, 0.5, 1.0],
|
||||||
|
),
|
||||||
|
),
|
||||||
|
),
|
||||||
|
),
|
||||||
|
|
||||||
|
// Content
|
||||||
|
Padding(
|
||||||
|
padding: const EdgeInsets.symmetric(vertical: 6, horizontal: 12),
|
||||||
|
child: Column(
|
||||||
|
crossAxisAlignment: CrossAxisAlignment.start,
|
||||||
|
mainAxisAlignment: MainAxisAlignment.center,
|
||||||
|
mainAxisSize: MainAxisSize.min,
|
||||||
|
children: [
|
||||||
|
// Title
|
||||||
|
Text(
|
||||||
|
title,
|
||||||
|
overflow: TextOverflow.ellipsis,
|
||||||
|
maxLines: 1,
|
||||||
|
softWrap: false,
|
||||||
|
style: const TextStyle(
|
||||||
|
fontWeight: FontWeight.bold,
|
||||||
|
fontSize: 18,
|
||||||
|
),
|
||||||
|
),
|
||||||
|
|
||||||
|
// Badge
|
||||||
|
if (badgeText != null) ...[
|
||||||
|
const SizedBox(height: 5),
|
||||||
|
Container(
|
||||||
|
constraints: const BoxConstraints(maxWidth: 250),
|
||||||
|
padding: const EdgeInsets.symmetric(
|
||||||
|
vertical: 2,
|
||||||
|
horizontal: 6,
|
||||||
|
),
|
||||||
|
decoration: BoxDecoration(
|
||||||
|
color: gameColor,
|
||||||
|
borderRadius: BorderRadius.circular(4),
|
||||||
|
),
|
||||||
|
child: Text(
|
||||||
|
badgeText!,
|
||||||
|
overflow: TextOverflow.ellipsis,
|
||||||
|
maxLines: 1,
|
||||||
|
softWrap: false,
|
||||||
|
style: TextStyle(
|
||||||
|
color: badgeTextColor,
|
||||||
|
fontSize: 12,
|
||||||
|
fontWeight: FontWeight.bold,
|
||||||
|
),
|
||||||
|
),
|
||||||
|
),
|
||||||
|
],
|
||||||
|
|
||||||
|
// Description
|
||||||
|
if (description.isNotEmpty) ...[
|
||||||
|
const SizedBox(height: 10),
|
||||||
|
Text(description, style: const TextStyle(fontSize: 14)),
|
||||||
|
const SizedBox(height: 2.5),
|
||||||
|
],
|
||||||
|
],
|
||||||
|
),
|
||||||
|
),
|
||||||
|
],
|
||||||
|
),
|
||||||
|
),
|
||||||
|
);
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -7,6 +7,7 @@ import 'package:tallee/core/custom_theme.dart';
|
|||||||
import 'package:tallee/core/enums.dart';
|
import 'package:tallee/core/enums.dart';
|
||||||
import 'package:tallee/data/models/match.dart';
|
import 'package:tallee/data/models/match.dart';
|
||||||
import 'package:tallee/l10n/generated/app_localizations.dart';
|
import 'package:tallee/l10n/generated/app_localizations.dart';
|
||||||
|
import 'package:tallee/presentation/widgets/game_label.dart';
|
||||||
import 'package:tallee/presentation/widgets/tiles/text_icon_tile.dart';
|
import 'package:tallee/presentation/widgets/tiles/text_icon_tile.dart';
|
||||||
|
|
||||||
class MatchTile extends StatefulWidget {
|
class MatchTile extends StatefulWidget {
|
||||||
@@ -116,56 +117,13 @@ class _MatchTileState extends State<MatchTile> {
|
|||||||
|
|
||||||
// Game + Ruleset Badge
|
// Game + Ruleset Badge
|
||||||
if (!widget.compact)
|
if (!widget.compact)
|
||||||
IntrinsicHeight(
|
GameLabel(
|
||||||
child: Row(
|
title: match.game.name,
|
||||||
mainAxisSize: MainAxisSize.min,
|
description: translateRulesetToString(
|
||||||
children: [
|
match.game.ruleset,
|
||||||
// Game
|
context,
|
||||||
Container(
|
|
||||||
decoration: BoxDecoration(
|
|
||||||
color: CustomTheme.primaryColor.withAlpha(230),
|
|
||||||
borderRadius: const BorderRadius.only(
|
|
||||||
topLeft: Radius.circular(8),
|
|
||||||
bottomLeft: Radius.circular(8),
|
|
||||||
),
|
|
||||||
),
|
|
||||||
padding: const EdgeInsets.symmetric(
|
|
||||||
vertical: 4,
|
|
||||||
horizontal: 8,
|
|
||||||
),
|
|
||||||
child: Text(
|
|
||||||
match.game.name,
|
|
||||||
style: const TextStyle(
|
|
||||||
fontSize: 12,
|
|
||||||
color: Colors.white,
|
|
||||||
fontWeight: FontWeight.bold,
|
|
||||||
),
|
|
||||||
),
|
|
||||||
),
|
|
||||||
// Ruleset
|
|
||||||
Container(
|
|
||||||
decoration: BoxDecoration(
|
|
||||||
color: CustomTheme.primaryColor.withAlpha(140),
|
|
||||||
borderRadius: const BorderRadius.only(
|
|
||||||
topRight: Radius.circular(8),
|
|
||||||
bottomRight: Radius.circular(8),
|
|
||||||
),
|
|
||||||
),
|
|
||||||
padding: const EdgeInsets.symmetric(
|
|
||||||
vertical: 4,
|
|
||||||
horizontal: 8,
|
|
||||||
),
|
|
||||||
child: Text(
|
|
||||||
translateRulesetToString(match.game.ruleset, context),
|
|
||||||
style: const TextStyle(
|
|
||||||
fontSize: 12,
|
|
||||||
color: Colors.white,
|
|
||||||
fontWeight: FontWeight.bold,
|
|
||||||
),
|
|
||||||
),
|
|
||||||
),
|
|
||||||
],
|
|
||||||
),
|
),
|
||||||
|
color: match.game.color,
|
||||||
),
|
),
|
||||||
|
|
||||||
const SizedBox(height: 12),
|
const SizedBox(height: 12),
|
||||||
|
|||||||
@@ -2,21 +2,17 @@ import 'package:flutter/material.dart';
|
|||||||
import 'package:tallee/core/custom_theme.dart';
|
import 'package:tallee/core/custom_theme.dart';
|
||||||
|
|
||||||
class TitleDescriptionListTile extends StatelessWidget {
|
class TitleDescriptionListTile extends StatelessWidget {
|
||||||
/// A list tile widget that displays a title and description, with optional highlighting and badge.
|
/// A list tile widget that displays a title and description
|
||||||
/// - [title]: The title text displayed on the tile.
|
/// - [title]: The title text displayed on the tile.
|
||||||
/// - [description]: The description text displayed below the title.
|
/// - [description]: The description text displayed below the title.
|
||||||
/// - [onPressed]: The callback invoked when the tile is tapped.
|
/// - [onTap]: The callback invoked when the tile is tapped.
|
||||||
/// - [isHighlighted]: A boolean to determine if the tile should be highlighted.
|
/// - [isHighlighted]: A boolean to determine if the tile should be highlighted.
|
||||||
/// - [badgeText]: Optional text to display in a badge on the right side of the title.
|
|
||||||
/// - [badgeColor]: Optional color for the badge background.
|
|
||||||
const TitleDescriptionListTile({
|
const TitleDescriptionListTile({
|
||||||
super.key,
|
super.key,
|
||||||
required this.title,
|
required this.title,
|
||||||
required this.description,
|
required this.description,
|
||||||
this.onPressed,
|
this.onTap,
|
||||||
this.isHighlighted = false,
|
this.isHighlighted = false,
|
||||||
this.badgeText,
|
|
||||||
this.badgeColor,
|
|
||||||
});
|
});
|
||||||
|
|
||||||
/// The title text displayed on the tile.
|
/// The title text displayed on the tile.
|
||||||
@@ -26,21 +22,15 @@ class TitleDescriptionListTile extends StatelessWidget {
|
|||||||
final String description;
|
final String description;
|
||||||
|
|
||||||
/// The callback invoked when the tile is tapped.
|
/// The callback invoked when the tile is tapped.
|
||||||
final VoidCallback? onPressed;
|
final VoidCallback? onTap;
|
||||||
|
|
||||||
/// A boolean to determine if the tile should be highlighted.
|
/// A boolean to determine if the tile should be highlighted.
|
||||||
final bool isHighlighted;
|
final bool isHighlighted;
|
||||||
|
|
||||||
/// Optional text to display in a badge on the right side of the title.
|
|
||||||
final String? badgeText;
|
|
||||||
|
|
||||||
/// Optional color for the badge background.
|
|
||||||
final Color? badgeColor;
|
|
||||||
|
|
||||||
@override
|
@override
|
||||||
Widget build(BuildContext context) {
|
Widget build(BuildContext context) {
|
||||||
return GestureDetector(
|
return GestureDetector(
|
||||||
onTap: onPressed,
|
onTap: onTap,
|
||||||
child: AnimatedContainer(
|
child: AnimatedContainer(
|
||||||
margin: const EdgeInsets.symmetric(vertical: 10, horizontal: 10),
|
margin: const EdgeInsets.symmetric(vertical: 10, horizontal: 10),
|
||||||
padding: const EdgeInsets.symmetric(vertical: 6, horizontal: 12),
|
padding: const EdgeInsets.symmetric(vertical: 6, horizontal: 12),
|
||||||
@@ -51,53 +41,26 @@ class TitleDescriptionListTile extends StatelessWidget {
|
|||||||
child: Column(
|
child: Column(
|
||||||
crossAxisAlignment: CrossAxisAlignment.start,
|
crossAxisAlignment: CrossAxisAlignment.start,
|
||||||
mainAxisAlignment: MainAxisAlignment.center,
|
mainAxisAlignment: MainAxisAlignment.center,
|
||||||
|
mainAxisSize: MainAxisSize.min,
|
||||||
children: [
|
children: [
|
||||||
Row(
|
// Title
|
||||||
mainAxisAlignment: MainAxisAlignment.start,
|
SizedBox(
|
||||||
crossAxisAlignment: CrossAxisAlignment.center,
|
width: 230,
|
||||||
children: [
|
child: Text(
|
||||||
SizedBox(
|
title,
|
||||||
width: 230,
|
overflow: TextOverflow.ellipsis,
|
||||||
child: Text(
|
maxLines: 1,
|
||||||
title,
|
softWrap: false,
|
||||||
overflow: TextOverflow.ellipsis,
|
style: const TextStyle(
|
||||||
maxLines: 1,
|
fontWeight: FontWeight.bold,
|
||||||
softWrap: false,
|
fontSize: 18,
|
||||||
style: const TextStyle(
|
|
||||||
fontWeight: FontWeight.bold,
|
|
||||||
fontSize: 18,
|
|
||||||
),
|
|
||||||
),
|
|
||||||
),
|
),
|
||||||
if (badgeText != null) ...[
|
),
|
||||||
const Spacer(),
|
|
||||||
Container(
|
|
||||||
constraints: const BoxConstraints(maxWidth: 115),
|
|
||||||
padding: const EdgeInsets.symmetric(
|
|
||||||
vertical: 2,
|
|
||||||
horizontal: 6,
|
|
||||||
),
|
|
||||||
decoration: BoxDecoration(
|
|
||||||
color: badgeColor ?? CustomTheme.primaryColor,
|
|
||||||
borderRadius: BorderRadius.circular(4),
|
|
||||||
),
|
|
||||||
child: Text(
|
|
||||||
badgeText!,
|
|
||||||
overflow: TextOverflow.ellipsis,
|
|
||||||
maxLines: 1,
|
|
||||||
softWrap: false,
|
|
||||||
style: const TextStyle(
|
|
||||||
color: Colors.white,
|
|
||||||
fontSize: 12,
|
|
||||||
fontWeight: FontWeight.bold,
|
|
||||||
),
|
|
||||||
),
|
|
||||||
),
|
|
||||||
],
|
|
||||||
],
|
|
||||||
),
|
),
|
||||||
|
|
||||||
|
// Description
|
||||||
if (description.isNotEmpty) ...[
|
if (description.isNotEmpty) ...[
|
||||||
const SizedBox(height: 5),
|
const SizedBox(height: 10),
|
||||||
Text(description, style: const TextStyle(fontSize: 14)),
|
Text(description, style: const TextStyle(fontSize: 14)),
|
||||||
const SizedBox(height: 2.5),
|
const SizedBox(height: 2.5),
|
||||||
],
|
],
|
||||||
|
|||||||
@@ -18,6 +18,7 @@ dependencies:
|
|||||||
sdk: flutter
|
sdk: flutter
|
||||||
flutter_localizations:
|
flutter_localizations:
|
||||||
sdk: flutter
|
sdk: flutter
|
||||||
|
flutter_popup: ^3.3.9
|
||||||
fluttericon: ^2.0.0
|
fluttericon: ^2.0.0
|
||||||
font_awesome_flutter: ^11.0.0
|
font_awesome_flutter: ^11.0.0
|
||||||
intl: any
|
intl: any
|
||||||
|
|||||||
@@ -241,15 +241,15 @@ void main() {
|
|||||||
expect(matchExists, isTrue);
|
expect(matchExists, isTrue);
|
||||||
});
|
});
|
||||||
|
|
||||||
test('getGroupMatches() works correctly', () async {
|
test('getMatchesByGroup() works correctly', () async {
|
||||||
var matches = await database.matchDao.getGroupMatches(
|
var matches = await database.matchDao.getMatchesByGroup(
|
||||||
groupId: 'non-existing-id',
|
groupId: 'non-existing-id',
|
||||||
);
|
);
|
||||||
|
|
||||||
expect(matches, isEmpty);
|
expect(matches, isEmpty);
|
||||||
|
|
||||||
await database.matchDao.addMatch(match: testMatch1);
|
await database.matchDao.addMatch(match: testMatch1);
|
||||||
matches = await database.matchDao.getGroupMatches(
|
matches = await database.matchDao.getMatchesByGroup(
|
||||||
groupId: testGroup1.id,
|
groupId: testGroup1.id,
|
||||||
);
|
);
|
||||||
expect(matches, isNotEmpty);
|
expect(matches, isNotEmpty);
|
||||||
@@ -259,6 +259,69 @@ void main() {
|
|||||||
expect(match.group, isNotNull);
|
expect(match.group, isNotNull);
|
||||||
expect(match.group!.id, testGroup1.id);
|
expect(match.group!.id, testGroup1.id);
|
||||||
});
|
});
|
||||||
|
|
||||||
|
test('getMatchCount() works correctly', () async {
|
||||||
|
var count = await database.matchDao.getMatchCount();
|
||||||
|
expect(count, 0);
|
||||||
|
|
||||||
|
await database.matchDao.addMatch(match: testMatch1);
|
||||||
|
|
||||||
|
count = await database.matchDao.getMatchCount();
|
||||||
|
expect(count, 1);
|
||||||
|
|
||||||
|
await database.matchDao.addMatch(match: testMatch2);
|
||||||
|
|
||||||
|
count = await database.matchDao.getMatchCount();
|
||||||
|
expect(count, 2);
|
||||||
|
|
||||||
|
await database.matchDao.deleteMatch(matchId: testMatch1.id);
|
||||||
|
|
||||||
|
count = await database.matchDao.getMatchCount();
|
||||||
|
expect(count, 1);
|
||||||
|
|
||||||
|
await database.matchDao.deleteMatch(matchId: testMatch2.id);
|
||||||
|
|
||||||
|
count = await database.matchDao.getMatchCount();
|
||||||
|
expect(count, 0);
|
||||||
|
});
|
||||||
|
|
||||||
|
test('getMatchCountByGame() works correctly', () async {
|
||||||
|
var count = await database.matchDao.getMatchCountByGame(
|
||||||
|
gameId: testGame.id,
|
||||||
|
);
|
||||||
|
expect(count, 0);
|
||||||
|
|
||||||
|
await database.matchDao.addMatch(match: testMatch1);
|
||||||
|
count = await database.matchDao.getMatchCountByGame(
|
||||||
|
gameId: testGame.id,
|
||||||
|
);
|
||||||
|
expect(count, 1);
|
||||||
|
|
||||||
|
await database.matchDao.addMatch(match: testMatch2);
|
||||||
|
count = await database.matchDao.getMatchCountByGame(
|
||||||
|
gameId: testGame.id,
|
||||||
|
);
|
||||||
|
expect(count, 2);
|
||||||
|
|
||||||
|
sneeex marked this conversation as resolved
Outdated
sneeex
commented
oben testest du auch noch löschen hier nicht? wieso? oben testest du auch noch löschen hier nicht? wieso?
flixcoo
commented
fixed fixed
|
|||||||
|
await database.matchDao.deleteMatch(matchId: testMatch1.id);
|
||||||
|
count = await database.matchDao.getMatchCountByGame(
|
||||||
|
gameId: testGame.id,
|
||||||
|
);
|
||||||
|
expect(count, 1);
|
||||||
|
|
||||||
|
await database.matchDao.deleteMatch(matchId: testMatch2.id);
|
||||||
|
count = await database.matchDao.getMatchCountByGame(
|
||||||
|
gameId: testGame.id,
|
||||||
|
);
|
||||||
|
expect(count, 0);
|
||||||
|
});
|
||||||
|
|
||||||
|
test('getMatchCountByGame() returns 0 for non-existent game', () async {
|
||||||
|
final count = await database.matchDao.getMatchCountByGame(
|
||||||
|
gameId: 'non-existent-game-id',
|
||||||
|
);
|
||||||
|
expect(count, 0);
|
||||||
|
});
|
||||||
});
|
});
|
||||||
|
|
||||||
group('UPDATE', () {
|
group('UPDATE', () {
|
||||||
@@ -386,7 +449,6 @@ void main() {
|
|||||||
await database.matchDao.addMatch(match: testMatch1);
|
await database.matchDao.addMatch(match: testMatch1);
|
||||||
|
|
||||||
DateTime newEndedAt = DateTime(2030, 1, 1, 12, 0, 0);
|
DateTime newEndedAt = DateTime(2030, 1, 1, 12, 0, 0);
|
||||||
print(newEndedAt);
|
|
||||||
await database.matchDao.updateMatchEndedAt(
|
await database.matchDao.updateMatchEndedAt(
|
||||||
matchId: testMatch1.id,
|
matchId: testMatch1.id,
|
||||||
endedAt: newEndedAt,
|
endedAt: newEndedAt,
|
||||||
@@ -408,31 +470,6 @@ void main() {
|
|||||||
final allMatches = await database.matchDao.getAllMatches();
|
final allMatches = await database.matchDao.getAllMatches();
|
||||||
expect(allMatches, isEmpty);
|
expect(allMatches, isEmpty);
|
||||||
});
|
});
|
||||||
|
|
||||||
test('Getting the match count works correctly', () async {
|
|
||||||
var matchCount = await database.matchDao.getMatchCount();
|
|
||||||
expect(matchCount, 0);
|
|
||||||
|
|
||||||
await database.matchDao.addMatch(match: testMatch1);
|
|
||||||
|
|
||||||
matchCount = await database.matchDao.getMatchCount();
|
|
||||||
expect(matchCount, 1);
|
|
||||||
|
|
||||||
await database.matchDao.addMatch(match: testMatch2);
|
|
||||||
|
|
||||||
matchCount = await database.matchDao.getMatchCount();
|
|
||||||
expect(matchCount, 2);
|
|
||||||
|
|
||||||
await database.matchDao.deleteMatch(matchId: testMatch1.id);
|
|
||||||
|
|
||||||
matchCount = await database.matchDao.getMatchCount();
|
|
||||||
expect(matchCount, 1);
|
|
||||||
|
|
||||||
await database.matchDao.deleteMatch(matchId: testMatch2.id);
|
|
||||||
|
|
||||||
matchCount = await database.matchDao.getMatchCount();
|
|
||||||
expect(matchCount, 0);
|
|
||||||
});
|
|
||||||
});
|
});
|
||||||
|
|
||||||
group('DELETE', () {
|
group('DELETE', () {
|
||||||
@@ -471,5 +508,33 @@ void main() {
|
|||||||
expect(deleted, isFalse);
|
expect(deleted, isFalse);
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
|
|
||||||
|
test('deleteMatchesByGame() deletes all matches for a game', () async {
|
||||||
|
await database.matchDao.addMatch(match: testMatch1);
|
||||||
|
await database.matchDao.addMatch(match: testMatch2);
|
||||||
|
|
||||||
|
var count = await database.matchDao.getMatchCountByGame(
|
||||||
|
gameId: testGame.id,
|
||||||
|
);
|
||||||
|
expect(count, 2);
|
||||||
|
|
||||||
|
final deletedCount = await database.matchDao.deleteMatchesByGame(
|
||||||
|
gameId: testGame.id,
|
||||||
|
);
|
||||||
|
expect(deletedCount, 2);
|
||||||
|
|
||||||
|
count = await database.matchDao.getMatchCountByGame(gameId: testGame.id);
|
||||||
|
expect(count, 0);
|
||||||
|
|
||||||
|
final allMatches = await database.matchDao.getAllMatches();
|
||||||
|
expect(allMatches, isEmpty);
|
||||||
|
});
|
||||||
|
|
||||||
|
test('deleteMatchesByGame() returns 0 for non-existent game', () async {
|
||||||
|
final deletedCount = await database.matchDao.deleteMatchesByGame(
|
||||||
|
gameId: 'non-existent-game-id',
|
||||||
|
);
|
||||||
|
expect(deletedCount, 0);
|
||||||
|
});
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|||||||
warum ist die border hier die textcolor? checks nicht so vom prinzip, weil in dem game view sind die highlighted border ja in der jeweiligen game farbe und nicht der text farbe
Das hat nichts mit der
ChooseGameViewzutun, ich wollte einfach nur das Highlighting von Containern ändern.