Lokalisierung implementieren #112

Merged
sneeex merged 41 commits from feature/100-lokalisierung-hinzufügen into development 2026-01-07 11:30:11 +00:00
22 changed files with 247 additions and 282 deletions
Showing only changes of commit ec94e12ed7 - Show all commits

View File

@@ -35,14 +35,15 @@ enum Ruleset { singleWinner, singleLoser, mostPoints, leastPoints }
/// Translates a [Ruleset] enum value to its corresponding localized string. /// Translates a [Ruleset] enum value to its corresponding localized string.
String translateRulesetToString(Ruleset ruleset, BuildContext context) { String translateRulesetToString(Ruleset ruleset, BuildContext context) {
final loc = AppLocalizations.of(context);
switch (ruleset) { switch (ruleset) {
case Ruleset.singleWinner: case Ruleset.singleWinner:
return AppLocalizations.of(context).single_winner; return loc.single_winner;
case Ruleset.singleLoser: case Ruleset.singleLoser:
return AppLocalizations.of(context).single_loser; return loc.single_loser;
case Ruleset.mostPoints: case Ruleset.mostPoints:
return AppLocalizations.of(context).most_points; return loc.most_points;
case Ruleset.leastPoints: case Ruleset.leastPoints:
return AppLocalizations.of(context).least_points; return loc.least_points;
} }
} }

View File

@@ -3,30 +3,28 @@
"choose_group": "Gruppe wählen", "choose_group": "Gruppe wählen",
"create_new_match": "Neues Match erstellen", "create_new_match": "Neues Match erstellen",
"choose_ruleset": "Regelwerk wählen", "choose_ruleset": "Regelwerk wählen",
"choose_game": "Spiel wählen", "choose_game": "Spielvorlage wählen",
"select_winner": "Gewinner wählen:", "select_winner": "Gewinner:in wählen:",
"no_recent_matches_available": "Keine letzten Matches verfügbar", "no_recent_matches_available": "Keine letzten Matches verfügbar",
"no_second_match_available": "Kein zweites Match verfügbar", "no_second_match_available": "Kein zweites Match verfügbar",
"delete_all_data": "Alle Daten löschen?", "delete_all_data": "Alle Daten löschen?",
"cancel": "Abbrechen", "cancel": "Abbrechen",
"delete": "Löschen", "delete": "Löschen",
"create_new_group": "Neue Gruppe erstellen", "create_new_group": "Neue Gruppe erstellen",
"error_while_creating_group_please_try_again": "Fehler beim Erstellen der Gruppe, bitte erneut versuchen", "error_creating_group": "Fehler beim Erstellen der Gruppe, bitte erneut versuchen",
"selected_players": "Ausgewählte Spieler: {count}", "selected_players": "Ausgewählte Spieler:in: {count}",
"no_players_selected": "Keine Spieler ausgewählt", "no_players_selected": "Keine Spieler:in ausgewählt",
"all_players": "Alle Spieler:", "all_players": "Alle Spieler:innen:",
"successfully_added_player": "Spieler {playerName} erfolgreich hinzugefügt", "successfully_added_player": "Spieler:in {playerName} erfolgreich hinzugefügt",
"could_not_add_player": "Spieler {playerName} konnte nicht hinzugefügt werden", "could_not_add_player": "Spieler:in {playerName} konnte nicht hinzugefügt werden",
"winner": "Gewinner: {winnerName}", "winner": "Gewinner:in: {winnerName}",
"players": "Spieler", "players": "Spieler:in",
"player_name": "Spielername", "player_name": "Spieler:innenname",
"no_statistics_available": "Keine Statistiken verfügbar", "no_statistics_available": "Keine Statistiken verfügbar",
"matches": "Matches", "matches": "Matches",
"groups": "Gruppen", "groups": "Gruppen",
"recent_matches": "Letzte Matches", "recent_matches": "Letzte Matches",
"quick_create": "Schnellzugriff", "quick_create": "Schnellzugriff",
"winner_label": "Gewinner",
"ruleset_label": "Regelwerk",
"match_in_progress": "Match läuft...", "match_in_progress": "Match läuft...",
"menu": "Menü", "menu": "Menü",
"settings": "Einstellungen", "settings": "Einstellungen",
@@ -52,15 +50,15 @@
"group_name": "Gruppenname", "group_name": "Gruppenname",
"no_matches_created_yet": "Noch keine Matches erstellt", "no_matches_created_yet": "Noch keine Matches erstellt",
"match_name": "Matchname", "match_name": "Matchname",
"game": "Spiel", "game": "Spielvorlage",
"ruleset": "Regelwerk", "ruleset": "Regelwerk",
"group": "Gruppe", "group": "Gruppe",
"none": "Kein", "none": "Kein",
"none_group": "Keine", "none_group": "Keine",
"create_match": "Match erstellen", "create_match": "Match erstellen",
"no_players_created_yet": "Noch keine Spieler erstellt", "no_players_created_yet": "Noch keine Spieler:in erstellt",
"all_players_selected": "Alle Spieler ausgewählt", "all_players_selected": "Alle Spieler:innen ausgewählt",
"no_players_found_with_that_name": "Keine Spieler mit diesem Namen gefunden", "no_players_found_with_that_name": "Keine Spieler:in mit diesem Namen gefunden",
"today_at": "Heute um {time}", "today_at": "Heute um {time}",
"yesterday_at": "Gestern um {time}", "yesterday_at": "Gestern um {time}",
"days_ago": "vor {count} Tagen", "days_ago": "vor {count} Tagen",
@@ -69,16 +67,16 @@
"stats": "Statistiken", "stats": "Statistiken",
"players_count": "{count} Spieler", "players_count": "{count} Spieler",
"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",
"game_name": "Spielname", "game_name": "Spielvorlagenname",
sneeex marked this conversation as resolved Outdated

Gendern? (auch generell)

Gendern? (auch generell)
"ruleset_single_winner_desc": "Genau ein Gewinner wird gewählt; Unentschieden werden durch einen vordefinierten Tie-Breaker aufgelöst.", "ruleset_single_winner": "Genau ein:e Gewinner:in wird gewählt; Unentschieden werden durch einen vordefinierten Tie-Breaker aufgelöst.",
"ruleset_single_loser_desc": "Genau ein Verlierer wird bestimmt; der letzte Platz erhält die Strafe oder Konsequenz.", "ruleset_single_loser": "Genau ein:e Verlierer:in wird bestimmt; der letzte Platz erhält die Strafe oder Konsequenz.",
"ruleset_most_points_desc": "Traditionelles Regelwerk: Der Spieler mit den meisten Punkten gewinnt.", "ruleset_most_points": "Traditionelles Regelwerk: Der/die Spieler:in mit den meisten Punkten gewinnt.",
"ruleset_least_points_desc": "Umgekehrte Wertung: Der Spieler mit den wenigsten Punkten gewinnt.", "ruleset_least_points": "Umgekehrte Wertung: Der/die Spieler:in mit den wenigsten Punkten gewinnt.",
"single_winner": "Ein Gewinner", "single_winner": "Ein:e Gewinner:in",
"single_loser": "Ein Verlierer", "single_loser": "Ein:e Verlierer:in",
"most_points": "Höchste Punkte", "most_points": "Höchste Punkte",
"least_points": "Niedrigste Punkte", "least_points": "Niedrigste Punkte",
"search_for_players": "Nach Spielern suchen", "search_for_players": "Nach Spieler:innen suchen",
"search_for_groups": "Nach Gruppen suchen", "search_for_groups": "Nach Gruppen suchen",
"no_data_available": "Keine Daten verfügbar", "no_data_available": "Keine Daten verfügbar",
"not_available": "Nicht verfügbar" "not_available": "Nicht verfügbar"

View File

@@ -20,6 +20,10 @@
"@select_winner": { "@select_winner": {
"description": "Label to select the winner" "description": "Label to select the winner"
}, },
"game_tracker": "Game Tracker",
"@game_tracker": {
"description": "App Name"
},
"no_recent_matches_available": "No recent matches available", "no_recent_matches_available": "No recent matches available",
"@no_recent_matches_available": { "@no_recent_matches_available": {
"description": "Message when no recent matches exist" "description": "Message when no recent matches exist"
@@ -44,8 +48,8 @@
"@create_new_group": { "@create_new_group": {
"description": "Button text to create a new group" "description": "Button text to create a new group"
}, },
"error_while_creating_group_please_try_again": "Error while creating group, please try again", "error_creating_group": "Error while creating group, please try again",
"@error_while_creating_group_please_try_again": { "@error_creating_group": {
"description": "Error message when group creation fails" "description": "Error message when group creation fails"
}, },
"selected_players": "Selected players: {count}", "selected_players": "Selected players: {count}",
@@ -124,14 +128,6 @@
"@quick_create": { "@quick_create": {
"description": "Title for quick create section" "description": "Title for quick create section"
}, },
"winner_label": "Winner",
"@winner_label": {
"description": "Label for winner field"
},
"ruleset_label": "Ruleset",
"@ruleset_label": {
"description": "Label for ruleset field"
},
"match_in_progress": "Match in progress...", "match_in_progress": "Match in progress...",
"@match_in_progress": { "@match_in_progress": {
"description": "Message when match is in progress" "description": "Message when match is in progress"
@@ -330,20 +326,20 @@
"@game_name": { "@game_name": {
"description": "Placeholder for game name search" "description": "Placeholder for game name search"
}, },
"ruleset_single_winner_desc": "Exactly one winner is chosen; ties are resolved by a predefined tiebreaker.", "ruleset_single_winner": "Exactly one winner is chosen; ties are resolved by a predefined tiebreaker.",
"@ruleset_single_winner_desc": { "@ruleset_single_winner": {
"description": "Description for single winner ruleset" "description": "Description for single winner ruleset"
}, },
"ruleset_single_loser_desc": "Exactly one loser is determined; last place receives the penalty or consequence.", "ruleset_single_loser": "Exactly one loser is determined; last place receives the penalty or consequence.",
"@ruleset_single_loser_desc": { "@ruleset_single_loser": {
"description": "Description for single loser ruleset" "description": "Description for single loser ruleset"
}, },
"ruleset_most_points_desc": "Traditional ruleset: the player with the most points wins.", "ruleset_most_points": "Traditional ruleset: the player with the most points wins.",
"@ruleset_most_points_desc": { "@ruleset_most_points": {
"description": "Description for most points ruleset" "description": "Description for most points ruleset"
}, },
"ruleset_least_points_desc": "Inverse scoring: the player with the fewest points wins.", "ruleset_least_points": "Inverse scoring: the player with the fewest points wins.",
"@ruleset_least_points_desc": { "@ruleset_least_points": {
"description": "Description for least points ruleset" "description": "Description for least points ruleset"
}, },
"single_winner": "Single Winner", "single_winner": "Single Winner",

View File

@@ -128,6 +128,12 @@ abstract class AppLocalizations {
/// **'Select Winner:'** /// **'Select Winner:'**
String get select_winner; String get select_winner;
/// App Name
///
/// In en, this message translates to:
/// **'Game Tracker'**
String get game_tracker;
/// Message when no recent matches exist /// Message when no recent matches exist
/// ///
/// In en, this message translates to: /// In en, this message translates to:
@@ -168,7 +174,7 @@ abstract class AppLocalizations {
/// ///
/// 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_while_creating_group_please_try_again; String get error_creating_group;
/// Shows the number of selected players /// Shows the number of selected players
/// ///
@@ -248,18 +254,6 @@ abstract class AppLocalizations {
/// **'Quick Create'** /// **'Quick Create'**
String get quick_create; String get quick_create;
/// Label for winner field
///
/// In en, this message translates to:
/// **'Winner'**
String get winner_label;
/// Label for ruleset field
///
/// In en, this message translates to:
/// **'Ruleset'**
String get ruleset_label;
/// Message when match is in progress /// Message when match is in progress
/// ///
/// In en, this message translates to: /// In en, this message translates to:
@@ -528,25 +522,25 @@ abstract class AppLocalizations {
/// ///
/// 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_desc; String get ruleset_single_winner;
/// Description for single loser ruleset /// Description for single loser ruleset
/// ///
/// 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_desc; String get ruleset_single_loser;
/// Description for most points ruleset /// Description for most points ruleset
/// ///
/// 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_desc; String get ruleset_most_points;
/// Description for least points ruleset /// Description for least points ruleset
/// ///
/// 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_desc; String get ruleset_least_points;
/// Title for single winner ruleset /// Title for single winner ruleset
/// ///

View File

@@ -18,10 +18,13 @@ class AppLocalizationsDe extends AppLocalizations {
String get choose_ruleset => 'Regelwerk wählen'; String get choose_ruleset => 'Regelwerk wählen';
@override @override
String get choose_game => 'Spiel wählen'; String get choose_game => 'Spielvorlage wählen';
@override @override
String get select_winner => 'Gewinner wählen:'; String get select_winner => 'Gewinner:in wählen:';
@override
String get game_tracker => 'Game Tracker';
@override @override
String get no_recent_matches_available => 'Keine letzten Matches verfügbar'; String get no_recent_matches_available => 'Keine letzten Matches verfügbar';
@@ -42,7 +45,7 @@ class AppLocalizationsDe extends AppLocalizations {
String get create_new_group => 'Neue Gruppe erstellen'; String get create_new_group => 'Neue Gruppe erstellen';
@override @override
String get error_while_creating_group_please_try_again => String get error_creating_group =>
'Fehler beim Erstellen der Gruppe, bitte erneut versuchen'; 'Fehler beim Erstellen der Gruppe, bitte erneut versuchen';
@override @override
@@ -52,32 +55,32 @@ class AppLocalizationsDe extends AppLocalizations {
); );
final String countString = countNumberFormat.format(count); final String countString = countNumberFormat.format(count);
return 'Ausgewählte Spieler: $countString'; return 'Ausgewählte Spieler:in: $countString';
} }
@override @override
String get no_players_selected => 'Keine Spieler ausgewählt'; String get no_players_selected => 'Keine Spieler:in ausgewählt';
@override @override
String get all_players => 'Alle Spieler:'; String get all_players => 'Alle Spieler:innen:';
@override @override
String successfully_added_player(String playerName) { String successfully_added_player(String playerName) {
return 'Spieler $playerName erfolgreich hinzugefügt'; return 'Spieler:in $playerName erfolgreich hinzugefügt';
} }
@override @override
String could_not_add_player(String playerName) { String could_not_add_player(String playerName) {
return 'Spieler $playerName konnte nicht hinzugefügt werden'; return 'Spieler:in $playerName konnte nicht hinzugefügt werden';
} }
@override @override
String winner(String winnerName) { String winner(String winnerName) {
return 'Gewinner: $winnerName'; return 'Gewinner:in: $winnerName';
} }
@override @override
String get players => 'Spieler'; String get players => 'Spieler:in';
@override @override
String get no_statistics_available => 'Keine Statistiken verfügbar'; String get no_statistics_available => 'Keine Statistiken verfügbar';
@@ -97,12 +100,6 @@ class AppLocalizationsDe extends AppLocalizations {
@override @override
String get quick_create => 'Schnellzugriff'; String get quick_create => 'Schnellzugriff';
@override
String get winner_label => 'Gewinner';
@override
String get ruleset_label => 'Regelwerk';
@override @override
String get match_in_progress => 'Match läuft...'; String get match_in_progress => 'Match läuft...';
@@ -168,7 +165,7 @@ class AppLocalizationsDe extends AppLocalizations {
String get no_groups_created_yet => 'Noch keine Gruppen erstellt'; String get no_groups_created_yet => 'Noch keine Gruppen erstellt';
@override @override
String get no_players_created_yet => 'Noch keine Spieler erstellt'; String get no_players_created_yet => 'Noch keine Spieler:in erstellt';
@override @override
String get create_group => 'Gruppe erstellen'; String get create_group => 'Gruppe erstellen';
@@ -177,7 +174,7 @@ class AppLocalizationsDe extends AppLocalizations {
String get group_name => 'Gruppenname'; String get group_name => 'Gruppenname';
@override @override
String get player_name => 'Spielername'; String get player_name => 'Spieler:innenname';
@override @override
String get no_matches_created_yet => 'Noch keine Matches erstellt'; String get no_matches_created_yet => 'Noch keine Matches erstellt';
@@ -186,7 +183,7 @@ class AppLocalizationsDe extends AppLocalizations {
String get match_name => 'Matchname'; String get match_name => 'Matchname';
@override @override
String get game => 'Spiel'; String get game => 'Spielvorlage';
@override @override
String get ruleset => 'Regelwerk'; String get ruleset => 'Regelwerk';
@@ -205,10 +202,10 @@ class AppLocalizationsDe extends AppLocalizations {
@override @override
String get no_players_found_with_that_name => String get no_players_found_with_that_name =>
'Keine Spieler mit diesem Namen gefunden'; 'Keine Spieler:in mit diesem Namen gefunden';
@override @override
String get all_players_selected => 'Alle Spieler ausgewählt'; String get all_players_selected => 'Alle Spieler:innen ausgewählt';
@override @override
String today_at(String time) { String today_at(String time) {
@@ -244,29 +241,29 @@ class AppLocalizationsDe extends AppLocalizations {
'Es gibt keine Gruppe, die deiner Suche entspricht'; 'Es gibt keine Gruppe, die deiner Suche entspricht';
@override @override
String get game_name => 'Spielname'; String get game_name => 'Spielvorlagenname';
@override @override
String get ruleset_single_winner_desc => String get ruleset_single_winner =>
'Genau ein Gewinner wird gewählt; Unentschieden werden durch einen vordefinierten Tie-Breaker aufgelöst.'; 'Genau ein:e Gewinner:in wird gewählt; Unentschieden werden durch einen vordefinierten Tie-Breaker aufgelöst.';
@override @override
String get ruleset_single_loser_desc => String get ruleset_single_loser =>
'Genau ein Verlierer wird bestimmt; der letzte Platz erhält die Strafe oder Konsequenz.'; 'Genau ein:e Verlierer:in wird bestimmt; der letzte Platz erhält die Strafe oder Konsequenz.';
@override @override
String get ruleset_most_points_desc => String get ruleset_most_points =>
'Traditionelles Regelwerk: Der Spieler mit den meisten Punkten gewinnt.'; 'Traditionelles Regelwerk: Der/die Spieler:in mit den meisten Punkten gewinnt.';
@override @override
String get ruleset_least_points_desc => String get ruleset_least_points =>
'Umgekehrte Wertung: Der Spieler mit den wenigsten Punkten gewinnt.'; 'Umgekehrte Wertung: Der/die Spieler:in mit den wenigsten Punkten gewinnt.';
@override @override
String get single_winner => 'Ein Gewinner'; String get single_winner => 'Ein:e Gewinner:in';
@override @override
String get single_loser => 'Ein Verlierer'; String get single_loser => 'Ein:e Verlierer:in';
@override @override
String get most_points => 'Höchste Punkte'; String get most_points => 'Höchste Punkte';
@@ -275,7 +272,7 @@ class AppLocalizationsDe extends AppLocalizations {
String get least_points => 'Niedrigste Punkte'; String get least_points => 'Niedrigste Punkte';
@override @override
String get search_for_players => 'Nach Spielern suchen'; String get search_for_players => 'Nach Spieler:innen suchen';
@override @override
String get search_for_groups => 'Nach Gruppen suchen'; String get search_for_groups => 'Nach Gruppen suchen';

View File

@@ -23,6 +23,9 @@ class AppLocalizationsEn extends AppLocalizations {
@override @override
String get select_winner => 'Select Winner:'; String get select_winner => 'Select Winner:';
@override
String get game_tracker => 'Game Tracker';
@override @override
String get no_recent_matches_available => 'No recent matches available'; String get no_recent_matches_available => 'No recent matches available';
@@ -42,7 +45,7 @@ class AppLocalizationsEn extends AppLocalizations {
String get create_new_group => 'Create new group'; String get create_new_group => 'Create new group';
@override @override
String get error_while_creating_group_please_try_again => String get error_creating_group =>
'Error while creating group, please try again'; 'Error while creating group, please try again';
@override @override
@@ -97,12 +100,6 @@ class AppLocalizationsEn extends AppLocalizations {
@override @override
String get quick_create => 'Quick Create'; String get quick_create => 'Quick Create';
@override
String get winner_label => 'Winner';
@override
String get ruleset_label => 'Ruleset';
@override @override
String get match_in_progress => 'Match in progress...'; String get match_in_progress => 'Match in progress...';
@@ -246,19 +243,19 @@ class AppLocalizationsEn extends AppLocalizations {
String get game_name => 'Game Name'; String get game_name => 'Game Name';
@override @override
String get ruleset_single_winner_desc => String get ruleset_single_winner =>
'Exactly one winner is chosen; ties are resolved by a predefined tiebreaker.'; 'Exactly one winner is chosen; ties are resolved by a predefined tiebreaker.';
@override @override
String get ruleset_single_loser_desc => String get ruleset_single_loser =>
'Exactly one loser is determined; last place receives the penalty or consequence.'; 'Exactly one loser is determined; last place receives the penalty or consequence.';
@override @override
String get ruleset_most_points_desc => String get ruleset_most_points =>
'Traditional ruleset: the player with the most points wins.'; 'Traditional ruleset: the player with the most points wins.';
@override @override
String get ruleset_least_points_desc => String get ruleset_least_points =>
'Inverse scoring: the player with the fewest points wins.'; 'Inverse scoring: the player with the fewest points wins.';
@override @override

View File

@@ -20,7 +20,6 @@ class GameTracker extends StatelessWidget {
@override @override
Widget build(BuildContext context) { Widget build(BuildContext context) {
print(AppLocalizations.supportedLocales.first);
return MaterialApp( return MaterialApp(
sneeex marked this conversation as resolved Outdated

Debug-Print entfernen

Debug-Print entfernen
localizationsDelegates: AppLocalizations.localizationsDelegates, localizationsDelegates: AppLocalizations.localizationsDelegates,
supportedLocales: AppLocalizations.supportedLocales, supportedLocales: AppLocalizations.supportedLocales,
@@ -35,7 +34,7 @@ class GameTracker extends StatelessWidget {
); );
}, },
debugShowCheckedModeBanner: false, debugShowCheckedModeBanner: false,
title: 'Game Tracker', onGenerateTitle: (context) => AppLocalizations.of(context).game_tracker,
darkTheme: ThemeData.dark(), darkTheme: ThemeData.dark(),
sneeex marked this conversation as resolved Outdated

Lokalisierung fehlt

Lokalisierung fehlt
themeMode: ThemeMode.dark, // forces dark mode themeMode: ThemeMode.dark, // forces dark mode

View File

@@ -20,13 +20,9 @@ class _CustomNavigationBarState extends State<CustomNavigationBar>
int currentIndex = 0; int currentIndex = 0;
int tabKeyCount = 0; int tabKeyCount = 0;
@override
void initState() {
super.initState();
}
@override @override
Widget build(BuildContext context) { Widget build(BuildContext context) {
final loc = AppLocalizations.of(context);
// Pretty ugly but works // Pretty ugly but works
final List<Widget> tabs = [ final List<Widget> tabs = [
KeyedSubtree(key: ValueKey('home_$tabKeyCount'), child: const HomeView()), KeyedSubtree(key: ValueKey('home_$tabKeyCount'), child: const HomeView()),
@@ -47,7 +43,7 @@ class _CustomNavigationBarState extends State<CustomNavigationBar>
appBar: AppBar( appBar: AppBar(
centerTitle: true, centerTitle: true,
title: Text( title: Text(
_currentTabTitle(), _currentTabTitle(context),
style: const TextStyle(fontSize: 20, fontWeight: FontWeight.bold), style: const TextStyle(fontSize: 20, fontWeight: FontWeight.bold),
), ),
backgroundColor: CustomTheme.backgroundColor, backgroundColor: CustomTheme.backgroundColor,
@@ -90,28 +86,28 @@ class _CustomNavigationBarState extends State<CustomNavigationBar>
index: 0, index: 0,
isSelected: currentIndex == 0, isSelected: currentIndex == 0,
icon: Icons.home_rounded, icon: Icons.home_rounded,
label: AppLocalizations.of(context).home, label: loc.home,
onTabTapped: onTabTapped, onTabTapped: onTabTapped,
), ),
NavbarItem( NavbarItem(
index: 1, index: 1,
isSelected: currentIndex == 1, isSelected: currentIndex == 1,
icon: Icons.gamepad_rounded, icon: Icons.gamepad_rounded,
label: AppLocalizations.of(context).matches, label: loc.matches,
onTabTapped: onTabTapped, onTabTapped: onTabTapped,
), ),
NavbarItem( NavbarItem(
index: 2, index: 2,
isSelected: currentIndex == 2, isSelected: currentIndex == 2,
icon: Icons.group_rounded, icon: Icons.group_rounded,
label: AppLocalizations.of(context).groups, label: loc.groups,
onTabTapped: onTabTapped, onTabTapped: onTabTapped,
), ),
NavbarItem( NavbarItem(
index: 3, index: 3,
isSelected: currentIndex == 3, isSelected: currentIndex == 3,
icon: Icons.bar_chart_rounded, icon: Icons.bar_chart_rounded,
label: AppLocalizations.of(context).statistics, label: loc.statistics,
onTabTapped: onTabTapped, onTabTapped: onTabTapped,
), ),
], ],
@@ -129,16 +125,17 @@ class _CustomNavigationBarState extends State<CustomNavigationBar>
}); });
} }
String _currentTabTitle() { String _currentTabTitle(context) {
final loc = AppLocalizations.of(context);
switch (currentIndex) { switch (currentIndex) {
case 0: case 0:
return AppLocalizations.of(context).home; return loc.home;
case 1: case 1:
return AppLocalizations.of(context).matches; return loc.matches;
case 2: case 2:
return AppLocalizations.of(context).groups; return loc.groups;
case 3: case 3:
return AppLocalizations.of(context).statistics; return loc.statistics;
default: default:
return ''; return '';
} }

View File

@@ -20,11 +20,13 @@ class CreateGroupView extends StatefulWidget {
class _CreateGroupViewState extends State<CreateGroupView> { class _CreateGroupViewState extends State<CreateGroupView> {
final _groupNameController = TextEditingController(); final _groupNameController = TextEditingController();
late final AppDatabase db; late final AppDatabase db;
List<Player> selectedPlayers = []; List<Player> selectedPlayers = [];
@override @override
void initState() { void initState() {
super.initState(); super.initState();
db = Provider.of<AppDatabase>(context, listen: false); db = Provider.of<AppDatabase>(context, listen: false);
_groupNameController.addListener(() { _groupNameController.addListener(() {
setState(() {}); setState(() {});
@@ -39,13 +41,14 @@ class _CreateGroupViewState extends State<CreateGroupView> {
@override @override
Widget build(BuildContext context) { Widget build(BuildContext context) {
final loc = AppLocalizations.of(context);
return Scaffold( return Scaffold(
backgroundColor: CustomTheme.backgroundColor, backgroundColor: CustomTheme.backgroundColor,
appBar: AppBar( appBar: AppBar(
backgroundColor: CustomTheme.backgroundColor, backgroundColor: CustomTheme.backgroundColor,
scrolledUnderElevation: 0, scrolledUnderElevation: 0,
title: Text( title: Text(
AppLocalizations.of(context).create_new_group, loc.create_new_group,
style: const TextStyle(fontSize: 20, fontWeight: FontWeight.bold), style: const TextStyle(fontSize: 20, fontWeight: FontWeight.bold),
), ),
centerTitle: true, centerTitle: true,
@@ -58,7 +61,7 @@ class _CreateGroupViewState extends State<CreateGroupView> {
margin: const EdgeInsets.symmetric(horizontal: 12, vertical: 10), margin: const EdgeInsets.symmetric(horizontal: 12, vertical: 10),
child: TextInputField( child: TextInputField(
controller: _groupNameController, controller: _groupNameController,
hintText: AppLocalizations.of(context).group_name, hintText: loc.group_name,
onChanged: (value) { onChanged: (value) {
setState(() {}); setState(() {});
}, },
@@ -74,7 +77,7 @@ class _CreateGroupViewState extends State<CreateGroupView> {
), ),
), ),
CustomWidthButton( CustomWidthButton(
text: AppLocalizations.of(context).create_group, text: loc.create_group,
sizeRelativeToWidth: 0.95, sizeRelativeToWidth: 0.95,
buttonType: ButtonType.primary, buttonType: ButtonType.primary,
onPressed: onPressed:
@@ -99,7 +102,7 @@ class _CreateGroupViewState extends State<CreateGroupView> {
child: Text( child: Text(
sneeex marked this conversation as resolved Outdated

Abkürzen für etwas generelles, z.B. creating_group_error oder creating_group_error_message

Abkürzen für etwas generelles, z.B. `creating_group_error` oder `creating_group_error_message`
AppLocalizations.of( AppLocalizations.of(
context, context,
).error_while_creating_group_please_try_again, ).error_creating_group,
style: const TextStyle(color: Colors.white), style: const TextStyle(color: Colors.white),
), ),
), ),

View File

@@ -35,12 +35,14 @@ class _GroupsViewState extends State<GroupsView> {
@override @override
void initState() { void initState() {
super.initState(); super.initState();
db = Provider.of<AppDatabase>(context, listen: false); db = Provider.of<AppDatabase>(context, listen: false);
loadGroups(); loadGroups();
} }
@override @override
Widget build(BuildContext context) { Widget build(BuildContext context) {
final loc = AppLocalizations.of(context);
return Scaffold( return Scaffold(
backgroundColor: CustomTheme.backgroundColor, backgroundColor: CustomTheme.backgroundColor,
body: Stack( body: Stack(
@@ -53,8 +55,8 @@ class _GroupsViewState extends State<GroupsView> {
replacement: Center( replacement: Center(
child: TopCenteredMessage( child: TopCenteredMessage(
icon: Icons.info, icon: Icons.info,
title: AppLocalizations.of(context).info, title: loc.info,
message: AppLocalizations.of(context).no_groups_created_yet, message: loc.no_groups_created_yet,
), ),
), ),
child: ListView.builder( child: ListView.builder(
@@ -74,7 +76,7 @@ class _GroupsViewState extends State<GroupsView> {
Positioned( Positioned(
bottom: MediaQuery.paddingOf(context).bottom, bottom: MediaQuery.paddingOf(context).bottom,
child: CustomWidthButton( child: CustomWidthButton(
text: AppLocalizations.of(context).create_group, text: loc.create_group,
sizeRelativeToWidth: 0.90, sizeRelativeToWidth: 0.90,
onPressed: () async { onPressed: () async {
await Navigator.push( await Navigator.push(

View File

@@ -72,6 +72,7 @@ class _HomeViewState extends State<HomeView> {
@override @override
Widget build(BuildContext context) { Widget build(BuildContext context) {
final loc = AppLocalizations.of(context);
return LayoutBuilder( return LayoutBuilder(
builder: (BuildContext context, BoxConstraints constraints) { builder: (BuildContext context, BoxConstraints constraints) {
return AppSkeleton( return AppSkeleton(
@@ -87,7 +88,7 @@ class _HomeViewState extends State<HomeView> {
QuickInfoTile( QuickInfoTile(
width: constraints.maxWidth * 0.45, width: constraints.maxWidth * 0.45,
height: constraints.maxHeight * 0.15, height: constraints.maxHeight * 0.15,
title: AppLocalizations.of(context).matches, title: loc.matches,
icon: Icons.groups_rounded, icon: Icons.groups_rounded,
value: matchCount, value: matchCount,
), ),
@@ -95,7 +96,7 @@ class _HomeViewState extends State<HomeView> {
QuickInfoTile( QuickInfoTile(
width: constraints.maxWidth * 0.45, width: constraints.maxWidth * 0.45,
height: constraints.maxHeight * 0.15, height: constraints.maxHeight * 0.15,
title: AppLocalizations.of(context).groups, title: loc.groups,
icon: Icons.groups_rounded, icon: Icons.groups_rounded,
value: groupCount, value: groupCount,
), ),
@@ -105,7 +106,7 @@ class _HomeViewState extends State<HomeView> {
padding: const EdgeInsets.symmetric(vertical: 16.0), padding: const EdgeInsets.symmetric(vertical: 16.0),
child: InfoTile( child: InfoTile(
width: constraints.maxWidth * 0.95, width: constraints.maxWidth * 0.95,
title: AppLocalizations.of(context).recent_matches, title: loc.recent_matches,
icon: Icons.timer, icon: Icons.timer,
content: Padding( content: Padding(
padding: const EdgeInsets.symmetric(horizontal: 40.0), padding: const EdgeInsets.symmetric(horizontal: 40.0),
@@ -125,11 +126,12 @@ class _HomeViewState extends State<HomeView> {
children: [ children: [
MatchSummaryTile( MatchSummaryTile(
matchTitle: recentMatches[0].name, matchTitle: recentMatches[0].name,
game: AppLocalizations.of(context).winner_label, game: 'Winner',
ruleset: AppLocalizations.of( ruleset: 'Ruleset',
players: _getPlayerText(
sneeex marked this conversation as resolved Outdated

Wenn winner_labelund ruleset_label nirgends anders verwendet werden, einfach die normalen Strings belassen, weil diese ja in Zukunft durch das Ruleset und das Game ersetzt werden

Wenn `winner_label`und `ruleset_label` nirgends anders verwendet werden, einfach die normalen Strings belassen, weil diese ja in Zukunft durch das Ruleset und das Game ersetzt werden
recentMatches[0],
context, context,
).ruleset_label, ),
players: _getPlayerText(recentMatches[0]),
winner: recentMatches[0].winner == null winner: recentMatches[0].winner == null
? AppLocalizations.of( ? AppLocalizations.of(
context, context,
@@ -143,11 +145,12 @@ class _HomeViewState extends State<HomeView> {
if (loadedRecentMatches.length > 1) ...[ if (loadedRecentMatches.length > 1) ...[
MatchSummaryTile( MatchSummaryTile(
matchTitle: recentMatches[1].name, matchTitle: recentMatches[1].name,
game: AppLocalizations.of(context).winner_label, game: 'Winner',
ruleset: AppLocalizations.of( ruleset: 'Ruleset',
players: _getPlayerText(
recentMatches[1],
context, context,
).ruleset_label, ),
players: _getPlayerText(recentMatches[1]),
winner: recentMatches[1].winner == null winner: recentMatches[1].winner == null
? AppLocalizations.of( ? AppLocalizations.of(
context, context,
@@ -173,7 +176,7 @@ class _HomeViewState extends State<HomeView> {
), ),
InfoTile( InfoTile(
width: constraints.maxWidth * 0.95, width: constraints.maxWidth * 0.95,
title: AppLocalizations.of(context).quick_create, title: loc.quick_create,
icon: Icons.add_box_rounded, icon: Icons.add_box_rounded,
content: Column( content: Column(
children: [ children: [
@@ -227,10 +230,11 @@ class _HomeViewState extends State<HomeView> {
); );
} }
String _getPlayerText(Match game) { String _getPlayerText(Match game, context) {
final loc = AppLocalizations.of(context);
if (game.group == null) { if (game.group == null) {
final playerCount = game.players?.length ?? 0; final playerCount = game.players?.length ?? 0;
return AppLocalizations.of(context).players_count(playerCount); return loc.players_count(playerCount);
} }
if (game.players == null || game.players!.isEmpty) { if (game.players == null || game.players!.isEmpty) {
return game.group!.name; return game.group!.name;

View File

@@ -21,6 +21,7 @@ class ChooseGameView extends StatefulWidget {
class _ChooseGameViewState extends State<ChooseGameView> { class _ChooseGameViewState extends State<ChooseGameView> {
late int selectedGameIndex; late int selectedGameIndex;
final TextEditingController searchBarController = TextEditingController(); final TextEditingController searchBarController = TextEditingController();
@override @override
@@ -31,6 +32,7 @@ class _ChooseGameViewState extends State<ChooseGameView> {
@override @override
Widget build(BuildContext context) { Widget build(BuildContext context) {
final loc = AppLocalizations.of(context);
return Scaffold( return Scaffold(
backgroundColor: CustomTheme.backgroundColor, backgroundColor: CustomTheme.backgroundColor,
appBar: AppBar( appBar: AppBar(
@@ -43,7 +45,7 @@ class _ChooseGameViewState extends State<ChooseGameView> {
}, },
), ),
title: Text( title: Text(
AppLocalizations.of(context).choose_game, loc.choose_game,
style: const TextStyle(fontSize: 20, fontWeight: FontWeight.bold), style: const TextStyle(fontSize: 20, fontWeight: FontWeight.bold),
), ),
centerTitle: true, centerTitle: true,
@@ -64,7 +66,7 @@ class _ChooseGameViewState extends State<ChooseGameView> {
padding: const EdgeInsets.symmetric(horizontal: 10), padding: const EdgeInsets.symmetric(horizontal: 10),
child: CustomSearchBar( child: CustomSearchBar(
controller: searchBarController, controller: searchBarController,
hintText: AppLocalizations.of(context).game_name, hintText: loc.game_name,
), ),
), ),
const SizedBox(height: 5), const SizedBox(height: 5),

View File

@@ -34,6 +34,7 @@ class _ChooseGroupViewState extends State<ChooseGroupView> {
@override @override
Widget build(BuildContext context) { Widget build(BuildContext context) {
final loc = AppLocalizations.of(context);
return Scaffold( return Scaffold(
backgroundColor: CustomTheme.backgroundColor, backgroundColor: CustomTheme.backgroundColor,
appBar: AppBar( appBar: AppBar(
@@ -52,7 +53,7 @@ class _ChooseGroupViewState extends State<ChooseGroupView> {
}, },
), ),
title: Text( title: Text(
AppLocalizations.of(context).choose_group, loc.choose_group,
style: const TextStyle(fontSize: 20, fontWeight: FontWeight.bold), style: const TextStyle(fontSize: 20, fontWeight: FontWeight.bold),
), ),
centerTitle: true, centerTitle: true,
@@ -79,7 +80,7 @@ class _ChooseGroupViewState extends State<ChooseGroupView> {
padding: const EdgeInsets.symmetric(horizontal: 10), padding: const EdgeInsets.symmetric(horizontal: 10),
child: CustomSearchBar( child: CustomSearchBar(
controller: controller, controller: controller,
hintText: AppLocalizations.of(context).search_for_groups, hintText: loc.search_for_groups,
onChanged: (value) { onChanged: (value) {
setState(() { setState(() {
filterGroups(value); filterGroups(value);
@@ -94,12 +95,12 @@ class _ChooseGroupViewState extends State<ChooseGroupView> {
visible: widget.groups.isNotEmpty, visible: widget.groups.isNotEmpty,
replacement: TopCenteredMessage( replacement: TopCenteredMessage(
icon: Icons.info, icon: Icons.info,
title: AppLocalizations.of(context).info, title: loc.info,
message: AppLocalizations.of(context).no_groups_created_yet, message: loc.no_groups_created_yet,
), ),
child: TopCenteredMessage( child: TopCenteredMessage(
icon: Icons.info, icon: Icons.info,
title: AppLocalizations.of(context).info, title: loc.info,
message: AppLocalizations.of( message: AppLocalizations.of(
context, context,
).there_is_no_group_matching_your_search, ).there_is_no_group_matching_your_search,

View File

@@ -29,6 +29,7 @@ class _ChooseRulesetViewState extends State<ChooseRulesetView> {
@override @override
Widget build(BuildContext context) { Widget build(BuildContext context) {
final loc = AppLocalizations.of(context);
return DefaultTabController( return DefaultTabController(
length: 2, length: 2,
initialIndex: 0, initialIndex: 0,
@@ -48,7 +49,7 @@ class _ChooseRulesetViewState extends State<ChooseRulesetView> {
}, },
), ),
title: Text( title: Text(
AppLocalizations.of(context).choose_ruleset, loc.choose_ruleset,
style: const TextStyle(fontSize: 20, fontWeight: FontWeight.bold), style: const TextStyle(fontSize: 20, fontWeight: FontWeight.bold),
), ),
centerTitle: true, centerTitle: true,

View File

@@ -90,23 +90,12 @@ class _CreateMatchViewState extends State<CreateMatchView> {
} }
List<(Ruleset, String)> _getRulesets(BuildContext context) { List<(Ruleset, String)> _getRulesets(BuildContext context) {
final loc = AppLocalizations.of(context);
return [ return [
( (Ruleset.singleWinner, loc.ruleset_single_winner),
Ruleset.singleWinner, (Ruleset.singleLoser, loc.ruleset_single_loser),
sneeex marked this conversation as resolved Outdated

Warum _desc?

Warum `_desc`?
AppLocalizations.of(context).ruleset_single_winner_desc, (Ruleset.mostPoints, loc.ruleset_most_points),
), (Ruleset.leastPoints, loc.ruleset_least_points),
(
Ruleset.singleLoser,
AppLocalizations.of(context).ruleset_single_loser_desc,
),
(
Ruleset.mostPoints,
AppLocalizations.of(context).ruleset_most_points_desc,
),
(
Ruleset.leastPoints,
AppLocalizations.of(context).ruleset_least_points_desc,
),
]; ];
} }
@@ -118,13 +107,14 @@ class _CreateMatchViewState extends State<CreateMatchView> {
@override @override
Widget build(BuildContext context) { Widget build(BuildContext context) {
final loc = AppLocalizations.of(context);
return Scaffold( return Scaffold(
backgroundColor: CustomTheme.backgroundColor, backgroundColor: CustomTheme.backgroundColor,
appBar: AppBar( appBar: AppBar(
backgroundColor: CustomTheme.backgroundColor, backgroundColor: CustomTheme.backgroundColor,
scrolledUnderElevation: 0, scrolledUnderElevation: 0,
title: Text( title: Text(
AppLocalizations.of(context).create_new_match, loc.create_new_match,
style: const TextStyle(fontSize: 20, fontWeight: FontWeight.bold), style: const TextStyle(fontSize: 20, fontWeight: FontWeight.bold),
), ),
centerTitle: true, centerTitle: true,
@@ -141,9 +131,9 @@ class _CreateMatchViewState extends State<CreateMatchView> {
), ),
), ),
ChooseTile( ChooseTile(
title: AppLocalizations.of(context).game, title: loc.game,
trailingText: selectedGameIndex == -1 trailingText: selectedGameIndex == -1
? AppLocalizations.of(context).none ? loc.none
: games[selectedGameIndex].$1, : games[selectedGameIndex].$1,
onPressed: () async { onPressed: () async {
selectedGameIndex = await Navigator.of(context).push( selectedGameIndex = await Navigator.of(context).push(
@@ -169,9 +159,9 @@ class _CreateMatchViewState extends State<CreateMatchView> {
}, },
), ),
ChooseTile( ChooseTile(
title: AppLocalizations.of(context).ruleset, title: loc.ruleset,
trailingText: selectedRuleset == null trailingText: selectedRuleset == null
? AppLocalizations.of(context).none ? loc.none
: translateRulesetToString(selectedRuleset!, context), : translateRulesetToString(selectedRuleset!, context),
onPressed: () async { onPressed: () async {
final rulesets = _getRulesets(context); final rulesets = _getRulesets(context);
@@ -192,9 +182,9 @@ class _CreateMatchViewState extends State<CreateMatchView> {
}, },
), ),
ChooseTile( ChooseTile(
title: AppLocalizations.of(context).group, title: loc.group,
trailingText: selectedGroup == null trailingText: selectedGroup == null
? AppLocalizations.of(context).none_group ? loc.none_group
: selectedGroup!.name, : selectedGroup!.name,
onPressed: () async { onPressed: () async {
selectedGroup = await Navigator.of(context).push( selectedGroup = await Navigator.of(context).push(
@@ -231,7 +221,7 @@ class _CreateMatchViewState extends State<CreateMatchView> {
), ),
), ),
CustomWidthButton( CustomWidthButton(
text: AppLocalizations.of(context).create_match, text: loc.create_match,
sizeRelativeToWidth: 0.95, sizeRelativeToWidth: 0.95,
buttonType: ButtonType.primary, buttonType: ButtonType.primary,
onPressed: _enableCreateGameButton() onPressed: _enableCreateGameButton()

View File

@@ -36,6 +36,7 @@ class _MatchResultViewState extends State<MatchResultView> {
@override @override
Widget build(BuildContext context) { Widget build(BuildContext context) {
final loc = AppLocalizations.of(context);
return Scaffold( return Scaffold(
backgroundColor: CustomTheme.backgroundColor, backgroundColor: CustomTheme.backgroundColor,
appBar: AppBar( appBar: AppBar(
@@ -81,7 +82,7 @@ class _MatchResultViewState extends State<MatchResultView> {
crossAxisAlignment: CrossAxisAlignment.start, crossAxisAlignment: CrossAxisAlignment.start,
children: [ children: [
Text( Text(
AppLocalizations.of(context).select_winner, loc.select_winner,
style: const TextStyle( style: const TextStyle(
fontSize: 18, fontSize: 18,
fontWeight: FontWeight.bold, fontWeight: FontWeight.bold,

View File

@@ -44,12 +44,14 @@ class _MatchViewState extends State<MatchView> {
@override @override
void initState() { void initState() {
super.initState(); super.initState();
db = Provider.of<AppDatabase>(context, listen: false); db = Provider.of<AppDatabase>(context, listen: false);
loadGames(); loadGames();
} }
@override @override
Widget build(BuildContext context) { Widget build(BuildContext context) {
final loc = AppLocalizations.of(context);
return Scaffold( return Scaffold(
backgroundColor: CustomTheme.backgroundColor, backgroundColor: CustomTheme.backgroundColor,
body: Stack( body: Stack(
@@ -62,8 +64,8 @@ class _MatchViewState extends State<MatchView> {
replacement: Center( replacement: Center(
child: TopCenteredMessage( child: TopCenteredMessage(
icon: Icons.report, icon: Icons.report,
title: AppLocalizations.of(context).info, title: loc.info,
message: AppLocalizations.of(context).no_matches_created_yet, message: loc.no_matches_created_yet,
), ),
), ),
child: ListView.builder( child: ListView.builder(
@@ -97,7 +99,7 @@ class _MatchViewState extends State<MatchView> {
Positioned( Positioned(
bottom: MediaQuery.paddingOf(context).bottom, bottom: MediaQuery.paddingOf(context).bottom,
child: CustomWidthButton( child: CustomWidthButton(
text: AppLocalizations.of(context).create_match, text: loc.create_match,
sizeRelativeToWidth: 0.90, sizeRelativeToWidth: 0.90,
onPressed: () async { onPressed: () async {
Navigator.push( Navigator.push(

View File

@@ -13,8 +13,14 @@ class SettingsView extends StatefulWidget {
} }
class _SettingsViewState extends State<SettingsView> { class _SettingsViewState extends State<SettingsView> {
@override
void initState() {
super.initState();
}
@override @override
Widget build(BuildContext context) { Widget build(BuildContext context) {
final loc = AppLocalizations.of(context);
return Scaffold( return Scaffold(
appBar: AppBar(backgroundColor: CustomTheme.backgroundColor), appBar: AppBar(backgroundColor: CustomTheme.backgroundColor),
backgroundColor: CustomTheme.backgroundColor, backgroundColor: CustomTheme.backgroundColor,
@@ -29,7 +35,7 @@ class _SettingsViewState extends State<SettingsView> {
padding: const EdgeInsets.fromLTRB(24, 0, 24, 10), padding: const EdgeInsets.fromLTRB(24, 0, 24, 10),
child: Text( child: Text(
textAlign: TextAlign.start, textAlign: TextAlign.start,
AppLocalizations.of(context).menu, loc.menu,
style: const TextStyle( style: const TextStyle(
fontSize: 28, fontSize: 28,
fontWeight: FontWeight.bold, fontWeight: FontWeight.bold,
@@ -43,7 +49,7 @@ class _SettingsViewState extends State<SettingsView> {
), ),
child: Text( child: Text(
textAlign: TextAlign.start, textAlign: TextAlign.start,
AppLocalizations.of(context).settings, loc.settings,
style: const TextStyle( style: const TextStyle(
fontSize: 22, fontSize: 22,
fontWeight: FontWeight.bold, fontWeight: FontWeight.bold,
@@ -51,7 +57,7 @@ class _SettingsViewState extends State<SettingsView> {
), ),
), ),
SettingsListTile( SettingsListTile(
title: AppLocalizations.of(context).export_data, title: loc.export_data,
icon: Icons.upload_outlined, icon: Icons.upload_outlined,
suffixWidget: const Icon(Icons.arrow_forward_ios, size: 16), suffixWidget: const Icon(Icons.arrow_forward_ios, size: 16),
onPressed: () async { onPressed: () async {
@@ -66,7 +72,7 @@ class _SettingsViewState extends State<SettingsView> {
}, },
), ),
SettingsListTile( SettingsListTile(
title: AppLocalizations.of(context).import_data, title: loc.import_data,
icon: Icons.download_outlined, icon: Icons.download_outlined,
suffixWidget: const Icon(Icons.arrow_forward_ios, size: 16), suffixWidget: const Icon(Icons.arrow_forward_ios, size: 16),
onPressed: () async { onPressed: () async {
@@ -78,27 +84,23 @@ class _SettingsViewState extends State<SettingsView> {
}, },
), ),
SettingsListTile( SettingsListTile(
title: AppLocalizations.of(context).delete_all_data, title: loc.delete_all_data,
icon: Icons.download_outlined, icon: Icons.download_outlined,
suffixWidget: const Icon(Icons.arrow_forward_ios, size: 16), suffixWidget: const Icon(Icons.arrow_forward_ios, size: 16),
onPressed: () { onPressed: () {
showDialog<bool>( showDialog<bool>(
context: context, context: context,
flixcoo marked this conversation as resolved Outdated

Hier auch sowas wie popup oder so mit einbauen, dass klar wird, wozu dieser text ist

Hier auch sowas wie `popup` oder so mit einbauen, dass klar wird, wozu dieser text ist

finde nicht, das kann man für verschiedene sachen nutzen und reicht so m. M. n.

finde nicht, das kann man für verschiedene sachen nutzen und reicht so m. M. n.
builder: (context) => AlertDialog( builder: (context) => AlertDialog(
title: Text( title: Text(loc.delete_all_data),
AppLocalizations.of(context).delete_all_data, content: Text(loc.this_cannot_be_undone),
),
content: Text(
AppLocalizations.of(context).this_cannot_be_undone,
),
actions: [ actions: [
TextButton( TextButton(
onPressed: () => Navigator.of(context).pop(false), onPressed: () => Navigator.of(context).pop(false),
child: Text(AppLocalizations.of(context).cancel), child: Text(loc.cancel),
), ),
TextButton( TextButton(
onPressed: () => Navigator.of(context).pop(true), onPressed: () => Navigator.of(context).pop(true),
child: Text(AppLocalizations.of(context).delete), child: Text(loc.delete),
), ),
], ],
), ),
@@ -130,37 +132,20 @@ class _SettingsViewState extends State<SettingsView> {
required BuildContext context, required BuildContext context,
required ImportResult result, required ImportResult result,
}) { }) {
final loc = AppLocalizations.of(context);
switch (result) { switch (result) {
case ImportResult.success: case ImportResult.success:
flixcoo marked this conversation as resolved Outdated

hier sowas wie snackbar?

hier sowas wie `snackbar`?

auch nicht relevant m. M. n.

auch nicht relevant m. M. n.
showSnackbar( showSnackbar(context: context, message: loc.data_successfully_imported);
context: context,
message: AppLocalizations.of(context).data_successfully_imported,
);
case ImportResult.invalidSchema: case ImportResult.invalidSchema:
showSnackbar( showSnackbar(context: context, message: loc.invalid_schema);
context: context,
message: AppLocalizations.of(context).invalid_schema,
);
case ImportResult.fileReadError: case ImportResult.fileReadError:
showSnackbar( showSnackbar(context: context, message: loc.error_reading_file);
context: context,
message: AppLocalizations.of(context).error_reading_file,
);
case ImportResult.canceled: case ImportResult.canceled:
showSnackbar( showSnackbar(context: context, message: loc.import_canceled);
context: context,
message: AppLocalizations.of(context).import_canceled,
);
case ImportResult.formatException: case ImportResult.formatException:
showSnackbar( showSnackbar(context: context, message: loc.format_exception);
context: context,
message: AppLocalizations.of(context).format_exception,
);
case ImportResult.unknownException: case ImportResult.unknownException:
showSnackbar( showSnackbar(context: context, message: loc.unknown_exception);
context: context,
message: AppLocalizations.of(context).unknown_exception,
);
} }
} }
@@ -172,22 +157,14 @@ class _SettingsViewState extends State<SettingsView> {
required BuildContext context, required BuildContext context,
required ExportResult result, required ExportResult result,
}) { }) {
final loc = AppLocalizations.of(context);
switch (result) { switch (result) {
case ExportResult.success: case ExportResult.success:
showSnackbar( showSnackbar(context: context, message: loc.data_successfully_exported);
context: context,
message: AppLocalizations.of(context).data_successfully_exported,
);
case ExportResult.canceled: case ExportResult.canceled:
showSnackbar( showSnackbar(context: context, message: loc.export_canceled);
context: context,
message: AppLocalizations.of(context).export_canceled,
);
case ExportResult.unknownException: case ExportResult.unknownException:
showSnackbar( showSnackbar(context: context, message: loc.unknown_exception);
context: context,
message: AppLocalizations.of(context).unknown_exception,
);
} }
} }
@@ -203,6 +180,7 @@ class _SettingsViewState extends State<SettingsView> {
Duration duration = const Duration(seconds: 3), Duration duration = const Duration(seconds: 3),
VoidCallback? action, VoidCallback? action,
}) { }) {
final loc = AppLocalizations.of(context);
final messenger = ScaffoldMessenger.of(context); final messenger = ScaffoldMessenger.of(context);
messenger.hideCurrentSnackBar(); messenger.hideCurrentSnackBar();
messenger.showSnackBar( messenger.showSnackBar(
@@ -211,10 +189,7 @@ class _SettingsViewState extends State<SettingsView> {
backgroundColor: CustomTheme.onBoxColor, backgroundColor: CustomTheme.onBoxColor,
duration: duration, duration: duration,
action: action != null action: action != null
? SnackBarAction( ? SnackBarAction(label: loc.undo, onPressed: action)
label: AppLocalizations.of(context).undo,
onPressed: action,
)
: null, : null,
), ),
); );

View File

@@ -25,6 +25,7 @@ class _StatisticsViewState extends State<StatisticsView> {
@override @override
void initState() { void initState() {
super.initState(); super.initState();
final db = Provider.of<AppDatabase>(context, listen: false); final db = Provider.of<AppDatabase>(context, listen: false);
Future.wait([ Future.wait([
@@ -32,21 +33,25 @@ class _StatisticsViewState extends State<StatisticsView> {
db.playerDao.getAllPlayers(), db.playerDao.getAllPlayers(),
Future.delayed(minimumSkeletonDuration), Future.delayed(minimumSkeletonDuration),
]).then((results) async { ]).then((results) async {
if (!mounted) return;
final matches = results[0] as List<Match>; final matches = results[0] as List<Match>;
final players = results[1] as List<Player>; final players = results[1] as List<Player>;
winCounts = _calculateWinsForAllPlayers(matches, players); winCounts = _calculateWinsForAllPlayers(matches, players, context);
matchCounts = _calculateMatchAmountsForAllPlayers(matches, players); matchCounts = _calculateMatchAmountsForAllPlayers(
matches,
players,
context,
);
winRates = computeWinRatePercent(wins: winCounts, matches: matchCounts); winRates = computeWinRatePercent(wins: winCounts, matches: matchCounts);
if (mounted) {
setState(() { setState(() {
isLoading = false; isLoading = false;
}); });
}
}); });
} }
@override @override
Widget build(BuildContext context) { Widget build(BuildContext context) {
final loc = AppLocalizations.of(context);
return LayoutBuilder( return LayoutBuilder(
builder: (BuildContext context, BoxConstraints constraints) { builder: (BuildContext context, BoxConstraints constraints) {
return SingleChildScrollView( return SingleChildScrollView(
@@ -69,7 +74,7 @@ class _StatisticsViewState extends State<StatisticsView> {
children: [ children: [
StatisticsTile( StatisticsTile(
icon: Icons.sports_score, icon: Icons.sports_score,
title: AppLocalizations.of(context).wins, title: loc.wins,
width: constraints.maxWidth * 0.95, width: constraints.maxWidth * 0.95,
values: winCounts, values: winCounts,
itemCount: 3, itemCount: 3,
@@ -78,7 +83,7 @@ class _StatisticsViewState extends State<StatisticsView> {
SizedBox(height: constraints.maxHeight * 0.02), SizedBox(height: constraints.maxHeight * 0.02),
StatisticsTile( StatisticsTile(
icon: Icons.percent, icon: Icons.percent,
title: AppLocalizations.of(context).winrate, title: loc.winrate,
width: constraints.maxWidth * 0.95, width: constraints.maxWidth * 0.95,
values: winRates, values: winRates,
itemCount: 5, itemCount: 5,
@@ -87,7 +92,7 @@ class _StatisticsViewState extends State<StatisticsView> {
SizedBox(height: constraints.maxHeight * 0.02), SizedBox(height: constraints.maxHeight * 0.02),
StatisticsTile( StatisticsTile(
icon: Icons.casino, icon: Icons.casino,
title: AppLocalizations.of(context).amount_of_matches, title: loc.amount_of_matches,
width: constraints.maxWidth * 0.95, width: constraints.maxWidth * 0.95,
values: matchCounts, values: matchCounts,
itemCount: 10, itemCount: 10,
@@ -97,7 +102,7 @@ class _StatisticsViewState extends State<StatisticsView> {
), ),
child: TopCenteredMessage( child: TopCenteredMessage(
icon: Icons.info, icon: Icons.info,
title: AppLocalizations.of(context).info, title: loc.info,
message: AppLocalizations.of( message: AppLocalizations.of(
context, context,
).no_statistics_available, ).no_statistics_available,
@@ -118,8 +123,10 @@ class _StatisticsViewState extends State<StatisticsView> {
List<(String, int)> _calculateWinsForAllPlayers( List<(String, int)> _calculateWinsForAllPlayers(
List<Match> matches, List<Match> matches,
List<Player> players, List<Player> players,
BuildContext context,
) { ) {
List<(String, int)> winCounts = []; List<(String, int)> winCounts = [];
final loc = AppLocalizations.of(context);
// Getting the winners // Getting the winners
for (var match in matches) { for (var match in matches) {
@@ -150,10 +157,7 @@ class _StatisticsViewState extends State<StatisticsView> {
final playerId = winCounts[i].$1; final playerId = winCounts[i].$1;
final player = players.firstWhere( final player = players.firstWhere(
(p) => p.id == playerId, (p) => p.id == playerId,
orElse: () => Player( orElse: () => Player(id: playerId, name: loc.not_available),
id: playerId,
name: AppLocalizations.of(context).not_available,
),
); );
winCounts[i] = (player.name, winCounts[i].$2); winCounts[i] = (player.name, winCounts[i].$2);
} }
@@ -168,8 +172,10 @@ class _StatisticsViewState extends State<StatisticsView> {
List<(String, int)> _calculateMatchAmountsForAllPlayers( List<(String, int)> _calculateMatchAmountsForAllPlayers(
List<Match> matches, List<Match> matches,
List<Player> players, List<Player> players,
BuildContext context,
) { ) {
List<(String, int)> matchCounts = []; List<(String, int)> matchCounts = [];
final loc = AppLocalizations.of(context);
// Counting matches for each player // Counting matches for each player
for (var match in matches) { for (var match in matches) {
@@ -215,10 +221,7 @@ class _StatisticsViewState extends State<StatisticsView> {
final playerId = matchCounts[i].$1; final playerId = matchCounts[i].$1;
final player = players.firstWhere( final player = players.firstWhere(
(p) => p.id == playerId, (p) => p.id == playerId,
orElse: () => Player( orElse: () => Player(id: playerId, name: loc.not_available),
id: playerId,
name: AppLocalizations.of(context).not_available,
),
); );
matchCounts[i] = (player.name, matchCounts[i].$2); matchCounts[i] = (player.name, matchCounts[i].$2);
} }

View File

@@ -87,6 +87,7 @@ class _PlayerSelectionState extends State<PlayerSelection> {
@override @override
Widget build(BuildContext context) { Widget build(BuildContext context) {
final loc = AppLocalizations.of(context);
return Container( return Container(
margin: const EdgeInsets.symmetric(horizontal: 12, vertical: 10), margin: const EdgeInsets.symmetric(horizontal: 12, vertical: 10),
padding: const EdgeInsets.symmetric(vertical: 10, horizontal: 10), padding: const EdgeInsets.symmetric(vertical: 10, horizontal: 10),
@@ -97,7 +98,7 @@ class _PlayerSelectionState extends State<PlayerSelection> {
CustomSearchBar( CustomSearchBar(
controller: _searchBarController, controller: _searchBarController,
constraints: const BoxConstraints(maxHeight: 45, minHeight: 45), constraints: const BoxConstraints(maxHeight: 45, minHeight: 45),
hintText: AppLocalizations.of(context).search_for_players, hintText: loc.search_for_players,
trailingButtonShown: true, trailingButtonShown: true,
trailingButtonicon: Icons.add_circle, trailingButtonicon: Icons.add_circle,
trailingButtonEnabled: _searchBarController.text.trim().isNotEmpty, trailingButtonEnabled: _searchBarController.text.trim().isNotEmpty,
@@ -139,11 +140,7 @@ class _PlayerSelectionState extends State<PlayerSelection> {
SizedBox( SizedBox(
height: 50, height: 50,
child: selectedPlayers.isEmpty child: selectedPlayers.isEmpty
? Center( ? Center(child: Text(loc.no_players_selected))
child: Text(
AppLocalizations.of(context).no_players_selected,
),
)
: SingleChildScrollView( : SingleChildScrollView(
scrollDirection: Axis.horizontal, scrollDirection: Axis.horizontal,
child: Row( child: Row(
@@ -185,7 +182,7 @@ class _PlayerSelectionState extends State<PlayerSelection> {
), ),
const SizedBox(height: 10), const SizedBox(height: 10),
Text( Text(
AppLocalizations.of(context).all_players, loc.all_players,
style: const TextStyle(fontSize: 16, fontWeight: FontWeight.bold), style: const TextStyle(fontSize: 16, fontWeight: FontWeight.bold),
), ),
const SizedBox(height: 10), const SizedBox(height: 10),
@@ -196,8 +193,8 @@ class _PlayerSelectionState extends State<PlayerSelection> {
visible: suggestedPlayers.isNotEmpty, visible: suggestedPlayers.isNotEmpty,
replacement: TopCenteredMessage( replacement: TopCenteredMessage(
icon: Icons.info, icon: Icons.info,
title: 'Info', title: loc.info,
message: _getInfoText(), message: _getInfoText(context),
), ),
child: ListView.builder( child: ListView.builder(
itemCount: suggestedPlayers.length, itemCount: suggestedPlayers.length,
@@ -234,6 +231,7 @@ class _PlayerSelectionState extends State<PlayerSelection> {
/// Shows a snackbar indicating success or failure. /// Shows a snackbar indicating success or failure.
/// [context] - BuildContext to show the snackbar. /// [context] - BuildContext to show the snackbar.
void addNewPlayerFromSearch({required BuildContext context}) async { void addNewPlayerFromSearch({required BuildContext context}) async {
final loc = AppLocalizations.of(context);
String playerName = _searchBarController.text.trim(); String playerName = _searchBarController.text.trim();
Player createdPlayer = Player(name: playerName); Player createdPlayer = Player(name: playerName);
bool success = await db.playerDao.addPlayer(player: createdPlayer); bool success = await db.playerDao.addPlayer(player: createdPlayer);
@@ -267,7 +265,7 @@ class _PlayerSelectionState extends State<PlayerSelection> {
backgroundColor: CustomTheme.boxColor, backgroundColor: CustomTheme.boxColor,
content: Center( content: Center(
child: Text( child: Text(
AppLocalizations.of(context).could_not_add_player(playerName), loc.could_not_add_player(playerName),
style: const TextStyle(color: Colors.white), style: const TextStyle(color: Colors.white),
), ),
), ),
@@ -278,18 +276,19 @@ class _PlayerSelectionState extends State<PlayerSelection> {
/// Determines the appropriate info text to display when no players /// Determines the appropriate info text to display when no players
/// are available in the suggested players list. /// are available in the suggested players list.
String _getInfoText() { String _getInfoText(BuildContext context) {
final loc = AppLocalizations.of(context);
if (allPlayers.isEmpty) { if (allPlayers.isEmpty) {
// No players exist in the database // No players exist in the database
return AppLocalizations.of(context).no_players_created_yet; return loc.no_players_created_yet;
} else if (selectedPlayers.length == allPlayers.length || } else if (selectedPlayers.length == allPlayers.length ||
widget.availablePlayers?.isEmpty == true) { widget.availablePlayers?.isEmpty == true) {
// All players have been selected or // All players have been selected or
// available players list is provided but empty // available players list is provided but empty
return AppLocalizations.of(context).all_players_selected; return loc.all_players_selected;
} else { } else {
// No players match the search query // No players match the search query
return AppLocalizations.of(context).no_players_found_with_that_name; return loc.no_players_found_with_that_name;
} }
} }
} }

View File

@@ -21,6 +21,7 @@ class _MatchTileState extends State<MatchTile> {
final group = widget.match.group; final group = widget.match.group;
final winner = widget.match.winner; final winner = widget.match.winner;
final allPlayers = _getAllPlayers(); final allPlayers = _getAllPlayers();
final loc = AppLocalizations.of(context);
return GestureDetector( return GestureDetector(
onTap: widget.onTap, onTap: widget.onTap,
@@ -49,7 +50,7 @@ class _MatchTileState extends State<MatchTile> {
), ),
), ),
Text( Text(
_formatDate(widget.match.createdAt), _formatDate(widget.match.createdAt, context),
style: const TextStyle(fontSize: 12, color: Colors.grey), style: const TextStyle(fontSize: 12, color: Colors.grey),
), ),
], ],
@@ -98,7 +99,7 @@ class _MatchTileState extends State<MatchTile> {
const SizedBox(width: 8), const SizedBox(width: 8),
Expanded( Expanded(
child: Text( child: Text(
AppLocalizations.of(context).winner(winner.name), loc.winner(winner.name),
style: const TextStyle( style: const TextStyle(
fontSize: 14, fontSize: 14,
fontWeight: FontWeight.w600, fontWeight: FontWeight.w600,
@@ -115,7 +116,7 @@ class _MatchTileState extends State<MatchTile> {
if (allPlayers.isNotEmpty) ...[ if (allPlayers.isNotEmpty) ...[
Text( Text(
AppLocalizations.of(context).players, loc.players,
style: const TextStyle( style: const TextStyle(
fontSize: 13, fontSize: 13,
color: Colors.grey, color: Colors.grey,
@@ -137,9 +138,10 @@ class _MatchTileState extends State<MatchTile> {
); );
} }
String _formatDate(DateTime dateTime) { String _formatDate(DateTime dateTime, BuildContext context) {
final now = DateTime.now(); final now = DateTime.now();
final difference = now.difference(dateTime); final difference = now.difference(dateTime);
final loc = AppLocalizations.of(context);
if (difference.inDays == 0) { if (difference.inDays == 0) {
return AppLocalizations.of( return AppLocalizations.of(
@@ -150,7 +152,7 @@ class _MatchTileState extends State<MatchTile> {
context, context,
).yesterday_at(DateFormat('HH:mm').format(dateTime)); ).yesterday_at(DateFormat('HH:mm').format(dateTime));
} else if (difference.inDays < 7) { } else if (difference.inDays < 7) {
return AppLocalizations.of(context).days_ago(difference.inDays); return loc.days_ago(difference.inDays);
} else { } else {
return DateFormat('MMM d, yyyy').format(dateTime); return DateFormat('MMM d, yyyy').format(dateTime);
} }

View File

@@ -25,6 +25,7 @@ class StatisticsTile extends StatelessWidget {
@override @override
Widget build(BuildContext context) { Widget build(BuildContext context) {
final maxBarWidth = MediaQuery.of(context).size.width * 0.65; final maxBarWidth = MediaQuery.of(context).size.width * 0.65;
final loc = AppLocalizations.of(context);
return InfoTile( return InfoTile(
width: width, width: width,
@@ -36,7 +37,7 @@ class StatisticsTile extends StatelessWidget {
visible: values.isNotEmpty, visible: values.isNotEmpty,
replacement: Center( replacement: Center(
heightFactor: 4, heightFactor: 4,
child: Text(AppLocalizations.of(context).no_data_available), child: Text(loc.no_data_available),
), ),
child: Column( child: Column(
children: List.generate(min(values.length, itemCount), (index) { children: List.generate(min(values.length, itemCount), (index) {