Lokalisierung implementieren #112
@@ -1,3 +1,6 @@
|
||||
import 'package:flutter/material.dart';
|
||||
import 'package:game_tracker/l10n/generated/app_localizations.dart';
|
||||
|
||||
/// Button types used for styling the [CustomWidthButton]
|
||||
enum ButtonType { primary, secondary, tertiary }
|
||||
|
||||
@@ -30,16 +33,16 @@ enum ExportResult { success, canceled, unknownException }
|
||||
/// - [Ruleset.leastPoints]: The player with the fewest points wins.
|
||||
enum Ruleset { singleWinner, singleLoser, mostPoints, leastPoints }
|
||||
|
||||
/// Translates a [Ruleset] enum value to its corresponding string representation.
|
||||
String translateRulesetToString(Ruleset ruleset) {
|
||||
/// Translates a [Ruleset] enum value to its corresponding localized string.
|
||||
String translateRulesetToString(Ruleset ruleset, BuildContext context) {
|
||||
switch (ruleset) {
|
||||
case Ruleset.singleWinner:
|
||||
return 'Single Winner';
|
||||
return AppLocalizations.of(context)!.single_winner;
|
||||
case Ruleset.singleLoser:
|
||||
return 'Single Loser';
|
||||
return AppLocalizations.of(context)!.single_loser;
|
||||
case Ruleset.mostPoints:
|
||||
return 'Most Points';
|
||||
return AppLocalizations.of(context)!.most_points;
|
||||
case Ruleset.leastPoints:
|
||||
return 'Least Points';
|
||||
return AppLocalizations.of(context)!.least_points;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,6 +1,7 @@
|
||||
import 'package:flutter/material.dart';
|
||||
import 'package:game_tracker/core/custom_theme.dart';
|
||||
import 'package:game_tracker/data/db/database.dart';
|
||||
import 'package:game_tracker/l10n/generated/app_localizations.dart';
|
||||
import 'package:game_tracker/presentation/views/main_menu/custom_navigation_bar.dart';
|
||||
import 'package:provider/provider.dart';
|
||||
|
||||
@@ -20,6 +21,8 @@ class GameTracker extends StatelessWidget {
|
||||
@override
|
||||
Widget build(BuildContext context) {
|
||||
return MaterialApp(
|
||||
|
sneeex marked this conversation as resolved
Outdated
|
||||
localizationsDelegates: AppLocalizations.localizationsDelegates,
|
||||
supportedLocales: AppLocalizations.supportedLocales,
|
||||
debugShowCheckedModeBanner: false,
|
||||
title: 'Game Tracker',
|
||||
darkTheme: ThemeData.dark(),
|
||||
|
||||
@@ -1,5 +1,6 @@
|
||||
import 'package:flutter/material.dart';
|
||||
import 'package:game_tracker/core/custom_theme.dart';
|
||||
import 'package:game_tracker/l10n/generated/app_localizations.dart';
|
||||
import 'package:game_tracker/presentation/views/main_menu/group_view/groups_view.dart';
|
||||
import 'package:game_tracker/presentation/views/main_menu/home_view.dart';
|
||||
import 'package:game_tracker/presentation/views/main_menu/match_view/match_view.dart';
|
||||
@@ -89,28 +90,28 @@ class _CustomNavigationBarState extends State<CustomNavigationBar>
|
||||
index: 0,
|
||||
isSelected: currentIndex == 0,
|
||||
icon: Icons.home_rounded,
|
||||
label: 'Home',
|
||||
label: AppLocalizations.of(context)!.home,
|
||||
onTabTapped: onTabTapped,
|
||||
),
|
||||
NavbarItem(
|
||||
index: 1,
|
||||
isSelected: currentIndex == 1,
|
||||
icon: Icons.gamepad_rounded,
|
||||
label: 'Matches',
|
||||
label: AppLocalizations.of(context)!.matches,
|
||||
onTabTapped: onTabTapped,
|
||||
),
|
||||
NavbarItem(
|
||||
index: 2,
|
||||
isSelected: currentIndex == 2,
|
||||
icon: Icons.group_rounded,
|
||||
label: 'Groups',
|
||||
label: AppLocalizations.of(context)!.groups,
|
||||
onTabTapped: onTabTapped,
|
||||
),
|
||||
NavbarItem(
|
||||
index: 3,
|
||||
isSelected: currentIndex == 3,
|
||||
icon: Icons.bar_chart_rounded,
|
||||
label: 'Stats',
|
||||
label: AppLocalizations.of(context)!.statistics,
|
||||
onTabTapped: onTabTapped,
|
||||
),
|
||||
],
|
||||
@@ -131,13 +132,13 @@ class _CustomNavigationBarState extends State<CustomNavigationBar>
|
||||
String _currentTabTitle() {
|
||||
switch (currentIndex) {
|
||||
case 0:
|
||||
return 'Home';
|
||||
return AppLocalizations.of(context)!.home;
|
||||
case 1:
|
||||
return 'Matches';
|
||||
return AppLocalizations.of(context)!.matches;
|
||||
case 2:
|
||||
return 'Groups';
|
||||
return AppLocalizations.of(context)!.groups;
|
||||
case 3:
|
||||
return 'Statistics';
|
||||
return AppLocalizations.of(context)!.statistics;
|
||||
default:
|
||||
return '';
|
||||
}
|
||||
|
||||
@@ -4,6 +4,7 @@ import 'package:game_tracker/core/enums.dart';
|
||||
import 'package:game_tracker/data/db/database.dart';
|
||||
import 'package:game_tracker/data/dto/group.dart';
|
||||
import 'package:game_tracker/data/dto/player.dart';
|
||||
import 'package:game_tracker/l10n/generated/app_localizations.dart';
|
||||
import 'package:game_tracker/presentation/widgets/buttons/custom_width_button.dart';
|
||||
import 'package:game_tracker/presentation/widgets/player_selection.dart';
|
||||
import 'package:game_tracker/presentation/widgets/text_input/text_input_field.dart';
|
||||
@@ -43,8 +44,8 @@ class _CreateGroupViewState extends State<CreateGroupView> {
|
||||
appBar: AppBar(
|
||||
backgroundColor: CustomTheme.backgroundColor,
|
||||
scrolledUnderElevation: 0,
|
||||
title: const Text(
|
||||
'Create new group',
|
||||
title: Text(
|
||||
AppLocalizations.of(context)!.create_new_group,
|
||||
style: TextStyle(fontSize: 20, fontWeight: FontWeight.bold),
|
||||
),
|
||||
centerTitle: true,
|
||||
@@ -57,7 +58,7 @@ class _CreateGroupViewState extends State<CreateGroupView> {
|
||||
margin: const EdgeInsets.symmetric(horizontal: 12, vertical: 10),
|
||||
child: TextInputField(
|
||||
controller: _groupNameController,
|
||||
hintText: 'Group name',
|
||||
hintText: AppLocalizations.of(context)!.group_name,
|
||||
onChanged: (value) {
|
||||
setState(() {});
|
||||
},
|
||||
@@ -73,7 +74,7 @@ class _CreateGroupViewState extends State<CreateGroupView> {
|
||||
),
|
||||
),
|
||||
CustomWidthButton(
|
||||
text: 'Create group',
|
||||
text: AppLocalizations.of(context)!.create_group,
|
||||
sizeRelativeToWidth: 0.95,
|
||||
buttonType: ButtonType.primary,
|
||||
onPressed:
|
||||
@@ -94,10 +95,12 @@ class _CreateGroupViewState extends State<CreateGroupView> {
|
||||
ScaffoldMessenger.of(context).showSnackBar(
|
||||
SnackBar(
|
||||
backgroundColor: CustomTheme.boxColor,
|
||||
content: const Center(
|
||||
content: Center(
|
||||
child: Text(
|
||||
'Error while creating group, please try again',
|
||||
style: TextStyle(color: Colors.white),
|
||||
AppLocalizations.of(
|
||||
context,
|
||||
)!.error_while_creating_group_please_try_again,
|
||||
|
sneeex marked this conversation as resolved
Outdated
flixcoo
commented
Abkürzen für etwas generelles, z.B. Abkürzen für etwas generelles, z.B. `creating_group_error` oder `creating_group_error_message`
|
||||
style: const TextStyle(color: Colors.white),
|
||||
),
|
||||
),
|
||||
),
|
||||
|
||||
@@ -4,6 +4,7 @@ import 'package:game_tracker/core/custom_theme.dart';
|
||||
import 'package:game_tracker/data/db/database.dart';
|
||||
import 'package:game_tracker/data/dto/group.dart';
|
||||
import 'package:game_tracker/data/dto/player.dart';
|
||||
import 'package:game_tracker/l10n/generated/app_localizations.dart';
|
||||
import 'package:game_tracker/presentation/views/main_menu/group_view/create_group_view.dart';
|
||||
import 'package:game_tracker/presentation/widgets/app_skeleton.dart';
|
||||
import 'package:game_tracker/presentation/widgets/buttons/custom_width_button.dart';
|
||||
@@ -49,11 +50,11 @@ class _GroupsViewState extends State<GroupsView> {
|
||||
enabled: isLoading,
|
||||
child: Visibility(
|
||||
visible: groups.isNotEmpty,
|
||||
replacement: const Center(
|
||||
replacement: Center(
|
||||
child: TopCenteredMessage(
|
||||
icon: Icons.info,
|
||||
title: 'Info',
|
||||
message: 'No groups created yet',
|
||||
title: AppLocalizations.of(context)!.info,
|
||||
message: AppLocalizations.of(context)!.no_groups_created_yet,
|
||||
),
|
||||
),
|
||||
child: ListView.builder(
|
||||
@@ -73,7 +74,7 @@ class _GroupsViewState extends State<GroupsView> {
|
||||
Positioned(
|
||||
bottom: MediaQuery.paddingOf(context).bottom,
|
||||
child: CustomWidthButton(
|
||||
text: 'Create Group',
|
||||
text: AppLocalizations.of(context)!.create_group,
|
||||
sizeRelativeToWidth: 0.90,
|
||||
onPressed: () async {
|
||||
await Navigator.push(
|
||||
|
||||
@@ -4,6 +4,7 @@ import 'package:game_tracker/data/db/database.dart';
|
||||
import 'package:game_tracker/data/dto/group.dart';
|
||||
import 'package:game_tracker/data/dto/match.dart';
|
||||
import 'package:game_tracker/data/dto/player.dart';
|
||||
import 'package:game_tracker/l10n/generated/app_localizations.dart';
|
||||
import 'package:game_tracker/presentation/widgets/app_skeleton.dart';
|
||||
import 'package:game_tracker/presentation/widgets/buttons/quick_create_button.dart';
|
||||
import 'package:game_tracker/presentation/widgets/tiles/game_tile.dart';
|
||||
@@ -86,7 +87,7 @@ class _HomeViewState extends State<HomeView> {
|
||||
QuickInfoTile(
|
||||
width: constraints.maxWidth * 0.45,
|
||||
height: constraints.maxHeight * 0.15,
|
||||
title: 'Matches',
|
||||
title: AppLocalizations.of(context)!.matches,
|
||||
icon: Icons.groups_rounded,
|
||||
value: matchCount,
|
||||
),
|
||||
@@ -94,7 +95,7 @@ class _HomeViewState extends State<HomeView> {
|
||||
QuickInfoTile(
|
||||
width: constraints.maxWidth * 0.45,
|
||||
height: constraints.maxHeight * 0.15,
|
||||
title: 'Groups',
|
||||
title: AppLocalizations.of(context)!.groups,
|
||||
icon: Icons.groups_rounded,
|
||||
value: groupCount,
|
||||
),
|
||||
@@ -104,15 +105,19 @@ class _HomeViewState extends State<HomeView> {
|
||||
padding: const EdgeInsets.symmetric(vertical: 16.0),
|
||||
child: InfoTile(
|
||||
width: constraints.maxWidth * 0.95,
|
||||
title: 'Recent Matches',
|
||||
title: AppLocalizations.of(context)!.recent_matches,
|
||||
icon: Icons.timer,
|
||||
content: Padding(
|
||||
padding: const EdgeInsets.symmetric(horizontal: 40.0),
|
||||
child: Visibility(
|
||||
visible: !isLoading && loadedRecentMatches.isNotEmpty,
|
||||
replacement: const Center(
|
||||
replacement: Center(
|
||||
heightFactor: 12,
|
||||
child: Text('No recent games available'),
|
||||
child: Text(
|
||||
AppLocalizations.of(
|
||||
context,
|
||||
)!.no_recent_matches_available,
|
||||
|
flixcoo marked this conversation as resolved
Outdated
flixcoo
commented
Idee: Generell alle Info-Messages auch als solche bennenen z.B. Idee: Generell alle Info-Messages auch als solche bennenen z.B. `info_no_recent_matches`
sneeex
commented
finde ich eigentlich unnötig finde ich eigentlich unnötig
sneeex
commented
weil eigentlich kann man die messages ja auch anders benutzen und es ist ja eigentlich egal obs ne info ist weil eigentlich kann man die messages ja auch anders benutzen und es ist ja eigentlich egal obs ne info ist
|
||||
),
|
||||
),
|
||||
child: Column(
|
||||
mainAxisAlignment: MainAxisAlignment.start,
|
||||
@@ -120,11 +125,15 @@ class _HomeViewState extends State<HomeView> {
|
||||
children: [
|
||||
MatchTile(
|
||||
matchTitle: recentMatches[0].name,
|
||||
game: 'Winner',
|
||||
ruleset: 'Ruleset',
|
||||
game: AppLocalizations.of(context)!.winner_label,
|
||||
ruleset: AppLocalizations.of(
|
||||
context,
|
||||
)!.ruleset_label,
|
||||
|
sneeex marked this conversation as resolved
Outdated
flixcoo
commented
Wenn 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
|
||||
players: _getPlayerText(recentMatches[0]),
|
||||
winner: recentMatches[0].winner == null
|
||||
? 'Match in progress...'
|
||||
? AppLocalizations.of(
|
||||
context,
|
||||
)!.match_in_progress
|
||||
: recentMatches[0].winner!.name,
|
||||
),
|
||||
const Padding(
|
||||
@@ -134,18 +143,28 @@ class _HomeViewState extends State<HomeView> {
|
||||
if (loadedRecentMatches.length > 1) ...[
|
||||
MatchTile(
|
||||
matchTitle: recentMatches[1].name,
|
||||
game: 'Winner',
|
||||
ruleset: 'Ruleset',
|
||||
game: AppLocalizations.of(
|
||||
context,
|
||||
)!.winner_label,
|
||||
ruleset: AppLocalizations.of(
|
||||
context,
|
||||
)!.ruleset_label,
|
||||
players: _getPlayerText(recentMatches[1]),
|
||||
winner: recentMatches[1].winner == null
|
||||
? 'Game in progress...'
|
||||
? AppLocalizations.of(
|
||||
context,
|
||||
)!.match_in_progress
|
||||
: recentMatches[1].winner!.name,
|
||||
),
|
||||
const SizedBox(height: 8),
|
||||
] else ...[
|
||||
const Center(
|
||||
Center(
|
||||
heightFactor: 5.35,
|
||||
child: Text('No second game available'),
|
||||
child: Text(
|
||||
AppLocalizations.of(
|
||||
context,
|
||||
)!.no_second_match_available,
|
||||
),
|
||||
),
|
||||
],
|
||||
],
|
||||
@@ -156,7 +175,7 @@ class _HomeViewState extends State<HomeView> {
|
||||
),
|
||||
InfoTile(
|
||||
width: constraints.maxWidth * 0.95,
|
||||
title: 'Quick Create',
|
||||
title: AppLocalizations.of(context)!.quick_create,
|
||||
icon: Icons.add_box_rounded,
|
||||
content: Column(
|
||||
children: [
|
||||
@@ -213,7 +232,7 @@ class _HomeViewState extends State<HomeView> {
|
||||
String _getPlayerText(Match game) {
|
||||
if (game.group == null) {
|
||||
final playerCount = game.players?.length ?? 0;
|
||||
return '$playerCount Players';
|
||||
return AppLocalizations.of(context)!.players_count(playerCount);
|
||||
}
|
||||
if (game.players == null || game.players!.isEmpty) {
|
||||
return game.group!.name;
|
||||
|
||||
@@ -1,6 +1,7 @@
|
||||
import 'package:flutter/material.dart';
|
||||
import 'package:game_tracker/core/custom_theme.dart';
|
||||
import 'package:game_tracker/core/enums.dart';
|
||||
import 'package:game_tracker/l10n/generated/app_localizations.dart';
|
||||
import 'package:game_tracker/presentation/widgets/text_input/custom_search_bar.dart';
|
||||
import 'package:game_tracker/presentation/widgets/tiles/title_description_list_tile.dart';
|
||||
|
||||
@@ -41,8 +42,8 @@ class _ChooseGameViewState extends State<ChooseGameView> {
|
||||
Navigator.of(context).pop(selectedGameIndex);
|
||||
},
|
||||
),
|
||||
title: const Text(
|
||||
'Choose Game',
|
||||
title: Text(
|
||||
AppLocalizations.of(context)!.choose_game,
|
||||
style: TextStyle(fontSize: 20, fontWeight: FontWeight.bold),
|
||||
),
|
||||
centerTitle: true,
|
||||
@@ -53,7 +54,7 @@ class _ChooseGameViewState extends State<ChooseGameView> {
|
||||
padding: const EdgeInsets.symmetric(horizontal: 10),
|
||||
child: CustomSearchBar(
|
||||
controller: searchBarController,
|
||||
hintText: 'Game Name',
|
||||
hintText: AppLocalizations.of(context)!.game_name,
|
||||
),
|
||||
),
|
||||
const SizedBox(height: 5),
|
||||
@@ -64,8 +65,10 @@ class _ChooseGameViewState extends State<ChooseGameView> {
|
||||
return TitleDescriptionListTile(
|
||||
title: widget.games[index].$1,
|
||||
description: widget.games[index].$2,
|
||||
badgeText: translateRulesetToString(widget.games[index].$3),
|
||||
isHighlighted: selectedGameIndex == index,
|
||||
badgeText: translateRulesetToString(
|
||||
widget.games[index].$3,
|
||||
context,
|
||||
),
|
||||
onPressed: () async {
|
||||
setState(() {
|
||||
if (selectedGameIndex == index) {
|
||||
|
||||
@@ -1,6 +1,7 @@
|
||||
import 'package:flutter/material.dart';
|
||||
import 'package:game_tracker/core/custom_theme.dart';
|
||||
import 'package:game_tracker/data/dto/group.dart';
|
||||
import 'package:game_tracker/l10n/generated/app_localizations.dart';
|
||||
import 'package:game_tracker/presentation/widgets/text_input/custom_search_bar.dart';
|
||||
import 'package:game_tracker/presentation/widgets/tiles/group_tile.dart';
|
||||
import 'package:game_tracker/presentation/widgets/top_centered_message.dart';
|
||||
@@ -22,7 +23,6 @@ class ChooseGroupView extends StatefulWidget {
|
||||
class _ChooseGroupViewState extends State<ChooseGroupView> {
|
||||
late String selectedGroupId;
|
||||
final TextEditingController controller = TextEditingController();
|
||||
final String hintText = 'Group Name';
|
||||
late final List<Group> filteredGroups;
|
||||
|
||||
@override
|
||||
@@ -51,8 +51,8 @@ class _ChooseGroupViewState extends State<ChooseGroupView> {
|
||||
);
|
||||
},
|
||||
),
|
||||
title: const Text(
|
||||
'Choose Group',
|
||||
title: Text(
|
||||
AppLocalizations.of(context)!.choose_group,
|
||||
style: TextStyle(fontSize: 20, fontWeight: FontWeight.bold),
|
||||
),
|
||||
centerTitle: true,
|
||||
@@ -63,7 +63,7 @@ class _ChooseGroupViewState extends State<ChooseGroupView> {
|
||||
padding: const EdgeInsets.symmetric(horizontal: 10),
|
||||
child: CustomSearchBar(
|
||||
controller: controller,
|
||||
hintText: hintText,
|
||||
hintText: AppLocalizations.of(context)!.group_name,
|
||||
onChanged: (value) {
|
||||
setState(() {
|
||||
filterGroups(value);
|
||||
@@ -76,15 +76,17 @@ class _ChooseGroupViewState extends State<ChooseGroupView> {
|
||||
visible: filteredGroups.isNotEmpty,
|
||||
replacement: Visibility(
|
||||
visible: widget.groups.isNotEmpty,
|
||||
replacement: const TopCenteredMessage(
|
||||
replacement: TopCenteredMessage(
|
||||
icon: Icons.info,
|
||||
title: 'Info',
|
||||
message: 'You have no groups created yet',
|
||||
title: AppLocalizations.of(context)!.info,
|
||||
message: AppLocalizations.of(context)!.no_groups_created_yet,
|
||||
),
|
||||
child: const TopCenteredMessage(
|
||||
child: TopCenteredMessage(
|
||||
icon: Icons.info,
|
||||
title: 'Info',
|
||||
message: 'There is no group matching your search',
|
||||
title: AppLocalizations.of(context)!.info,
|
||||
message: AppLocalizations.of(
|
||||
context,
|
||||
)!.there_is_no_group_matching_your_search,
|
||||
),
|
||||
),
|
||||
child: ListView.builder(
|
||||
|
||||
@@ -1,6 +1,7 @@
|
||||
import 'package:flutter/material.dart';
|
||||
import 'package:game_tracker/core/custom_theme.dart';
|
||||
import 'package:game_tracker/core/enums.dart';
|
||||
import 'package:game_tracker/l10n/generated/app_localizations.dart';
|
||||
import 'package:game_tracker/presentation/widgets/tiles/title_description_list_tile.dart';
|
||||
|
||||
class ChooseRulesetView extends StatefulWidget {
|
||||
@@ -46,8 +47,8 @@ class _ChooseRulesetViewState extends State<ChooseRulesetView> {
|
||||
);
|
||||
},
|
||||
),
|
||||
title: const Text(
|
||||
'Choose Ruleset',
|
||||
title: Text(
|
||||
AppLocalizations.of(context)!.choose_ruleset,
|
||||
style: TextStyle(fontSize: 20, fontWeight: FontWeight.bold),
|
||||
),
|
||||
centerTitle: true,
|
||||
@@ -66,7 +67,10 @@ class _ChooseRulesetViewState extends State<ChooseRulesetView> {
|
||||
}
|
||||
});
|
||||
},
|
||||
title: translateRulesetToString(widget.rulesets[index].$1),
|
||||
title: translateRulesetToString(
|
||||
widget.rulesets[index].$1,
|
||||
context,
|
||||
),
|
||||
description: widget.rulesets[index].$2,
|
||||
isHighlighted: selectedRulesetIndex == index,
|
||||
);
|
||||
|
||||
@@ -6,6 +6,7 @@ import 'package:game_tracker/data/db/database.dart';
|
||||
import 'package:game_tracker/data/dto/group.dart';
|
||||
import 'package:game_tracker/data/dto/match.dart';
|
||||
import 'package:game_tracker/data/dto/player.dart';
|
||||
import 'package:game_tracker/l10n/generated/app_localizations.dart';
|
||||
import 'package:game_tracker/presentation/views/main_menu/match_view/create_match/choose_game_view.dart';
|
||||
import 'package:game_tracker/presentation/views/main_menu/match_view/create_match/choose_group_view.dart';
|
||||
import 'package:game_tracker/presentation/views/main_menu/match_view/create_match/choose_ruleset_view.dart';
|
||||
@@ -64,34 +65,6 @@ class _CreateMatchViewState extends State<CreateMatchView> {
|
||||
/// The currently selected players
|
||||
List<Player>? selectedPlayers;
|
||||
|
||||
/// List of available rulesets with their descriptions
|
||||
/// as tuples of (Ruleset, String)
|
||||
/// TODO: Replace when rulesets are implemented
|
||||
List<(Ruleset, String)> rulesets = [
|
||||
(
|
||||
Ruleset.singleWinner,
|
||||
'Exactly one winner is chosen; ties are resolved by a predefined tiebreaker.',
|
||||
),
|
||||
(
|
||||
Ruleset.singleLoser,
|
||||
'Exactly one loser is determined; last place receives the penalty or consequence.',
|
||||
),
|
||||
(
|
||||
Ruleset.mostPoints,
|
||||
'Traditional ruleset: the player with the most points wins.',
|
||||
),
|
||||
(
|
||||
Ruleset.leastPoints,
|
||||
'Inverse scoring: the player with the fewest points wins.',
|
||||
),
|
||||
];
|
||||
|
||||
// TODO: Replace when games are implemented
|
||||
List<(String, String, Ruleset)> games = [
|
||||
('Example Game 1', 'This is a discription', Ruleset.leastPoints),
|
||||
('Example Game 2', '', Ruleset.singleWinner),
|
||||
];
|
||||
|
||||
@override
|
||||
void initState() {
|
||||
super.initState();
|
||||
@@ -111,6 +84,33 @@ class _CreateMatchViewState extends State<CreateMatchView> {
|
||||
filteredPlayerList = List.from(playerList);
|
||||
}
|
||||
|
||||
List<(Ruleset, String)> _getRulesets(BuildContext context) {
|
||||
return [
|
||||
(
|
||||
Ruleset.singleWinner,
|
||||
AppLocalizations.of(context)!.ruleset_single_winner_desc,
|
||||
),
|
||||
(
|
||||
Ruleset.singleLoser,
|
||||
AppLocalizations.of(context)!.ruleset_single_loser_desc,
|
||||
),
|
||||
|
sneeex marked this conversation as resolved
Outdated
flixcoo
commented
Warum Warum `_desc`?
|
||||
(
|
||||
Ruleset.mostPoints,
|
||||
AppLocalizations.of(context)!.ruleset_most_points_desc,
|
||||
),
|
||||
(
|
||||
Ruleset.leastPoints,
|
||||
AppLocalizations.of(context)!.ruleset_least_points_desc,
|
||||
),
|
||||
];
|
||||
}
|
||||
|
||||
// TODO: Replace when games are implemented
|
||||
List<(String, String, Ruleset)> games = [
|
||||
('Example Game 1', 'This is a description', Ruleset.leastPoints),
|
||||
('Example Game 2', '', Ruleset.singleWinner),
|
||||
];
|
||||
|
||||
@override
|
||||
Widget build(BuildContext context) {
|
||||
return Scaffold(
|
||||
@@ -118,8 +118,8 @@ class _CreateMatchViewState extends State<CreateMatchView> {
|
||||
appBar: AppBar(
|
||||
backgroundColor: CustomTheme.backgroundColor,
|
||||
scrolledUnderElevation: 0,
|
||||
title: const Text(
|
||||
'Create new match',
|
||||
title: Text(
|
||||
AppLocalizations.of(context)!.create_new_match,
|
||||
style: TextStyle(fontSize: 20, fontWeight: FontWeight.bold),
|
||||
),
|
||||
centerTitle: true,
|
||||
@@ -132,13 +132,13 @@ class _CreateMatchViewState extends State<CreateMatchView> {
|
||||
margin: const EdgeInsets.symmetric(horizontal: 12, vertical: 5),
|
||||
child: TextInputField(
|
||||
controller: _matchNameController,
|
||||
hintText: 'Match name',
|
||||
hintText: AppLocalizations.of(context)!.match_name,
|
||||
),
|
||||
),
|
||||
ChooseTile(
|
||||
title: 'Game',
|
||||
title: AppLocalizations.of(context)!.game,
|
||||
trailingText: selectedGameIndex == -1
|
||||
? 'None'
|
||||
? AppLocalizations.of(context)!.none
|
||||
: games[selectedGameIndex].$1,
|
||||
onPressed: () async {
|
||||
selectedGameIndex = await Navigator.of(context).push(
|
||||
@@ -152,9 +152,9 @@ class _CreateMatchViewState extends State<CreateMatchView> {
|
||||
setState(() {
|
||||
if (selectedGameIndex != -1) {
|
||||
selectedRuleset = games[selectedGameIndex].$3;
|
||||
selectedRulesetIndex = rulesets.indexWhere(
|
||||
(r) => r.$1 == selectedRuleset,
|
||||
);
|
||||
selectedRulesetIndex = _getRulesets(
|
||||
context,
|
||||
).indexWhere((r) => r.$1 == selectedRuleset);
|
||||
} else {
|
||||
selectedRuleset = null;
|
||||
}
|
||||
@@ -162,30 +162,30 @@ class _CreateMatchViewState extends State<CreateMatchView> {
|
||||
},
|
||||
),
|
||||
ChooseTile(
|
||||
title: 'Ruleset',
|
||||
title: AppLocalizations.of(context)!.ruleset,
|
||||
trailingText: selectedRuleset == null
|
||||
? 'None'
|
||||
: translateRulesetToString(selectedRuleset!),
|
||||
? AppLocalizations.of(context)!.none
|
||||
: translateRulesetToString(selectedRuleset!, context),
|
||||
onPressed: () async {
|
||||
selectedRuleset = await Navigator.of(context).push(
|
||||
MaterialPageRoute(
|
||||
builder: (context) => ChooseRulesetView(
|
||||
rulesets: rulesets,
|
||||
rulesets: _getRulesets(context),
|
||||
initialRulesetIndex: selectedRulesetIndex,
|
||||
),
|
||||
),
|
||||
);
|
||||
selectedRulesetIndex = rulesets.indexWhere(
|
||||
(r) => r.$1 == selectedRuleset,
|
||||
);
|
||||
selectedRulesetIndex = _getRulesets(
|
||||
context,
|
||||
).indexWhere((r) => r.$1 == selectedRuleset);
|
||||
selectedGameIndex = -1;
|
||||
setState(() {});
|
||||
},
|
||||
),
|
||||
ChooseTile(
|
||||
title: 'Group',
|
||||
title: AppLocalizations.of(context)!.group,
|
||||
trailingText: selectedGroup == null
|
||||
? 'None'
|
||||
? AppLocalizations.of(context)!.none
|
||||
: selectedGroup!.name,
|
||||
onPressed: () async {
|
||||
selectedGroup = await Navigator.of(context).push(
|
||||
@@ -222,7 +222,7 @@ class _CreateMatchViewState extends State<CreateMatchView> {
|
||||
),
|
||||
),
|
||||
CustomWidthButton(
|
||||
text: 'Create match',
|
||||
text: AppLocalizations.of(context)!.create_match,
|
||||
sizeRelativeToWidth: 0.95,
|
||||
buttonType: ButtonType.primary,
|
||||
onPressed: _enableCreateGameButton()
|
||||
|
||||
@@ -3,6 +3,7 @@ import 'package:game_tracker/core/custom_theme.dart';
|
||||
import 'package:game_tracker/data/db/database.dart';
|
||||
import 'package:game_tracker/data/dto/match.dart';
|
||||
import 'package:game_tracker/data/dto/player.dart';
|
||||
import 'package:game_tracker/l10n/generated/app_localizations.dart';
|
||||
import 'package:game_tracker/presentation/widgets/tiles/custom_radio_list_tile.dart';
|
||||
import 'package:provider/provider.dart';
|
||||
|
||||
@@ -79,8 +80,8 @@ class _MatchResultViewState extends State<MatchResultView> {
|
||||
mainAxisAlignment: MainAxisAlignment.start,
|
||||
crossAxisAlignment: CrossAxisAlignment.start,
|
||||
children: [
|
||||
const Text(
|
||||
'Select Winner:',
|
||||
Text(
|
||||
AppLocalizations.of(context)!.select_winner,
|
||||
style: TextStyle(
|
||||
fontSize: 18,
|
||||
fontWeight: FontWeight.bold,
|
||||
|
||||
@@ -8,6 +8,7 @@ import 'package:game_tracker/data/db/database.dart';
|
||||
import 'package:game_tracker/data/dto/group.dart';
|
||||
import 'package:game_tracker/data/dto/match.dart';
|
||||
import 'package:game_tracker/data/dto/player.dart';
|
||||
import 'package:game_tracker/l10n/generated/app_localizations.dart';
|
||||
import 'package:game_tracker/presentation/views/main_menu/match_view/create_match/create_match_view.dart';
|
||||
import 'package:game_tracker/presentation/views/main_menu/match_view/match_result_view.dart';
|
||||
import 'package:game_tracker/presentation/widgets/app_skeleton.dart';
|
||||
@@ -58,11 +59,11 @@ class _MatchViewState extends State<MatchView> {
|
||||
enabled: isLoading,
|
||||
child: Visibility(
|
||||
visible: matches.isNotEmpty,
|
||||
replacement: const Center(
|
||||
replacement: Center(
|
||||
child: TopCenteredMessage(
|
||||
icon: Icons.report,
|
||||
title: 'Info',
|
||||
message: 'No games created yet',
|
||||
title: AppLocalizations.of(context)!.info,
|
||||
message: AppLocalizations.of(context)!.no_matches_created_yet,
|
||||
),
|
||||
),
|
||||
child: ListView.builder(
|
||||
@@ -96,7 +97,7 @@ class _MatchViewState extends State<MatchView> {
|
||||
Positioned(
|
||||
bottom: MediaQuery.paddingOf(context).bottom,
|
||||
child: CustomWidthButton(
|
||||
text: 'Create Game',
|
||||
text: AppLocalizations.of(context)!.create_match,
|
||||
sizeRelativeToWidth: 0.90,
|
||||
onPressed: () async {
|
||||
Navigator.push(
|
||||
|
||||
@@ -1,6 +1,7 @@
|
||||
import 'package:flutter/material.dart';
|
||||
import 'package:game_tracker/core/custom_theme.dart';
|
||||
import 'package:game_tracker/core/enums.dart';
|
||||
import 'package:game_tracker/l10n/generated/app_localizations.dart';
|
||||
import 'package:game_tracker/presentation/widgets/tiles/settings_list_tile.dart';
|
||||
import 'package:game_tracker/services/data_transfer_service.dart';
|
||||
|
||||
@@ -24,30 +25,33 @@ class _SettingsViewState extends State<SettingsView> {
|
||||
mainAxisAlignment: MainAxisAlignment.start,
|
||||
crossAxisAlignment: CrossAxisAlignment.start,
|
||||
children: [
|
||||
const Padding(
|
||||
padding: EdgeInsets.fromLTRB(24, 0, 24, 10),
|
||||
Padding(
|
||||
padding: const EdgeInsets.fromLTRB(24, 0, 24, 10),
|
||||
child: Text(
|
||||
textAlign: TextAlign.start,
|
||||
'Menu',
|
||||
style: TextStyle(
|
||||
AppLocalizations.of(context)!.menu,
|
||||
style: const TextStyle(
|
||||
fontSize: 28,
|
||||
fontWeight: FontWeight.bold,
|
||||
),
|
||||
),
|
||||
),
|
||||
const Padding(
|
||||
padding: EdgeInsets.symmetric(horizontal: 24, vertical: 10),
|
||||
Padding(
|
||||
padding: const EdgeInsets.symmetric(
|
||||
horizontal: 24,
|
||||
vertical: 10,
|
||||
),
|
||||
child: Text(
|
||||
textAlign: TextAlign.start,
|
||||
'Settings',
|
||||
style: TextStyle(
|
||||
AppLocalizations.of(context)!.settings,
|
||||
style: const TextStyle(
|
||||
fontSize: 22,
|
||||
fontWeight: FontWeight.bold,
|
||||
),
|
||||
),
|
||||
),
|
||||
SettingsListTile(
|
||||
title: 'Export data',
|
||||
title: AppLocalizations.of(context)!.export_data,
|
||||
icon: Icons.upload_outlined,
|
||||
suffixWidget: const Icon(Icons.arrow_forward_ios, size: 16),
|
||||
onPressed: () async {
|
||||
@@ -62,7 +66,7 @@ class _SettingsViewState extends State<SettingsView> {
|
||||
},
|
||||
),
|
||||
SettingsListTile(
|
||||
title: 'Import data',
|
||||
title: AppLocalizations.of(context)!.import_data,
|
||||
icon: Icons.download_outlined,
|
||||
suffixWidget: const Icon(Icons.arrow_forward_ios, size: 16),
|
||||
onPressed: () async {
|
||||
@@ -74,23 +78,27 @@ class _SettingsViewState extends State<SettingsView> {
|
||||
},
|
||||
),
|
||||
SettingsListTile(
|
||||
title: 'Delete all data',
|
||||
title: AppLocalizations.of(context)!.delete_all_data,
|
||||
icon: Icons.download_outlined,
|
||||
suffixWidget: const Icon(Icons.arrow_forward_ios, size: 16),
|
||||
onPressed: () {
|
||||
showDialog<bool>(
|
||||
context: context,
|
||||
builder: (context) => AlertDialog(
|
||||
title: const Text('Delete all data?'),
|
||||
content: const Text('This can\'t be undone'),
|
||||
title: Text(
|
||||
AppLocalizations.of(context)!.delete_all_data,
|
||||
),
|
||||
content: Text(
|
||||
AppLocalizations.of(context)!.this_cannot_be_undone,
|
||||
|
flixcoo marked this conversation as resolved
Outdated
flixcoo
commented
Hier auch sowas wie Hier auch sowas wie `popup` oder so mit einbauen, dass klar wird, wozu dieser text ist
sneeex
commented
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.
|
||||
),
|
||||
actions: [
|
||||
TextButton(
|
||||
onPressed: () => Navigator.of(context).pop(false),
|
||||
child: const Text('Abbrechen'),
|
||||
child: Text(AppLocalizations.of(context)!.cancel),
|
||||
),
|
||||
TextButton(
|
||||
onPressed: () => Navigator.of(context).pop(true),
|
||||
child: const Text('Löschen'),
|
||||
child: Text(AppLocalizations.of(context)!.delete),
|
||||
),
|
||||
],
|
||||
),
|
||||
@@ -99,7 +107,9 @@ class _SettingsViewState extends State<SettingsView> {
|
||||
DataTransferService.deleteAllData(context);
|
||||
showSnackbar(
|
||||
context: context,
|
||||
message: 'Daten erfolgreich gelöscht',
|
||||
message: AppLocalizations.of(
|
||||
context,
|
||||
)!.data_successfully_deleted,
|
||||
);
|
||||
}
|
||||
});
|
||||
@@ -122,22 +132,34 @@ class _SettingsViewState extends State<SettingsView> {
|
||||
}) {
|
||||
switch (result) {
|
||||
case ImportResult.success:
|
||||
showSnackbar(context: context, message: 'Data successfully imported');
|
||||
showSnackbar(
|
||||
context: context,
|
||||
message: AppLocalizations.of(context)!.data_successfully_imported,
|
||||
|
flixcoo marked this conversation as resolved
Outdated
flixcoo
commented
hier sowas wie hier sowas wie `snackbar`?
sneeex
commented
auch nicht relevant m. M. n. auch nicht relevant m. M. n.
|
||||
);
|
||||
case ImportResult.invalidSchema:
|
||||
showSnackbar(context: context, message: 'Invalid Schema');
|
||||
showSnackbar(
|
||||
context: context,
|
||||
message: AppLocalizations.of(context)!.invalid_schema,
|
||||
);
|
||||
case ImportResult.fileReadError:
|
||||
showSnackbar(context: context, message: 'Error reading file');
|
||||
showSnackbar(
|
||||
context: context,
|
||||
message: AppLocalizations.of(context)!.error_reading_file,
|
||||
);
|
||||
case ImportResult.canceled:
|
||||
showSnackbar(context: context, message: 'Import canceled');
|
||||
showSnackbar(
|
||||
context: context,
|
||||
message: AppLocalizations.of(context)!.import_canceled,
|
||||
);
|
||||
case ImportResult.formatException:
|
||||
showSnackbar(
|
||||
context: context,
|
||||
message: 'Format Exception (see console)',
|
||||
message: AppLocalizations.of(context)!.format_exception,
|
||||
);
|
||||
case ImportResult.unknownException:
|
||||
showSnackbar(
|
||||
context: context,
|
||||
message: 'Unknown Exception (see console)',
|
||||
message: AppLocalizations.of(context)!.unknown_exception,
|
||||
);
|
||||
}
|
||||
}
|
||||
@@ -152,13 +174,19 @@ class _SettingsViewState extends State<SettingsView> {
|
||||
}) {
|
||||
switch (result) {
|
||||
case ExportResult.success:
|
||||
showSnackbar(context: context, message: 'Data successfully exported');
|
||||
showSnackbar(
|
||||
context: context,
|
||||
message: AppLocalizations.of(context)!.data_successfully_exported,
|
||||
);
|
||||
case ExportResult.canceled:
|
||||
showSnackbar(context: context, message: 'Export canceled');
|
||||
showSnackbar(
|
||||
context: context,
|
||||
message: AppLocalizations.of(context)!.export_canceled,
|
||||
);
|
||||
case ExportResult.unknownException:
|
||||
showSnackbar(
|
||||
context: context,
|
||||
message: 'Unknown Exception (see console)',
|
||||
message: AppLocalizations.of(context)!.unknown_exception,
|
||||
);
|
||||
}
|
||||
}
|
||||
@@ -183,7 +211,10 @@ class _SettingsViewState extends State<SettingsView> {
|
||||
backgroundColor: CustomTheme.onBoxColor,
|
||||
duration: duration,
|
||||
action: action != null
|
||||
? SnackBarAction(label: 'Rückgängig', onPressed: action)
|
||||
? SnackBarAction(
|
||||
label: AppLocalizations.of(context)!.undo,
|
||||
onPressed: action,
|
||||
)
|
||||
: null,
|
||||
),
|
||||
);
|
||||
|
||||
@@ -3,6 +3,7 @@ import 'package:game_tracker/core/constants.dart';
|
||||
import 'package:game_tracker/data/db/database.dart';
|
||||
import 'package:game_tracker/data/dto/match.dart';
|
||||
import 'package:game_tracker/data/dto/player.dart';
|
||||
import 'package:game_tracker/l10n/generated/app_localizations.dart';
|
||||
import 'package:game_tracker/presentation/widgets/app_skeleton.dart';
|
||||
import 'package:game_tracker/presentation/widgets/tiles/statistics_tile.dart';
|
||||
import 'package:provider/provider.dart';
|
||||
@@ -60,7 +61,7 @@ class _StatisticsViewState extends State<StatisticsView> {
|
||||
SizedBox(height: constraints.maxHeight * 0.01),
|
||||
StatisticsTile(
|
||||
icon: Icons.sports_score,
|
||||
title: 'Wins',
|
||||
title: AppLocalizations.of(context)!.wins,
|
||||
width: constraints.maxWidth * 0.95,
|
||||
values: winCounts,
|
||||
itemCount: 3,
|
||||
@@ -69,7 +70,7 @@ class _StatisticsViewState extends State<StatisticsView> {
|
||||
SizedBox(height: constraints.maxHeight * 0.02),
|
||||
StatisticsTile(
|
||||
icon: Icons.percent,
|
||||
title: 'Winrate',
|
||||
title: AppLocalizations.of(context)!.winrate,
|
||||
width: constraints.maxWidth * 0.95,
|
||||
values: winRates,
|
||||
itemCount: 5,
|
||||
@@ -78,7 +79,7 @@ class _StatisticsViewState extends State<StatisticsView> {
|
||||
SizedBox(height: constraints.maxHeight * 0.02),
|
||||
StatisticsTile(
|
||||
icon: Icons.casino,
|
||||
title: 'Amount of Matches',
|
||||
title: AppLocalizations.of(context)!.amount_of_matches,
|
||||
width: constraints.maxWidth * 0.95,
|
||||
values: matchCounts,
|
||||
itemCount: 10,
|
||||
|
||||
@@ -3,6 +3,7 @@ import 'package:game_tracker/core/constants.dart';
|
||||
import 'package:game_tracker/core/custom_theme.dart';
|
||||
import 'package:game_tracker/data/db/database.dart';
|
||||
import 'package:game_tracker/data/dto/player.dart';
|
||||
import 'package:game_tracker/l10n/generated/app_localizations.dart';
|
||||
import 'package:game_tracker/presentation/widgets/app_skeleton.dart';
|
||||
import 'package:game_tracker/presentation/widgets/text_input/custom_search_bar.dart';
|
||||
import 'package:game_tracker/presentation/widgets/tiles/text_icon_list_tile.dart';
|
||||
@@ -129,14 +130,20 @@ class _PlayerSelectionState extends State<PlayerSelection> {
|
||||
),
|
||||
const SizedBox(height: 10),
|
||||
Text(
|
||||
'Selected players: (${selectedPlayers.length})',
|
||||
AppLocalizations.of(
|
||||
context,
|
||||
)!.selected_players(selectedPlayers.length),
|
||||
style: const TextStyle(fontSize: 16, fontWeight: FontWeight.bold),
|
||||
),
|
||||
const SizedBox(height: 10),
|
||||
SizedBox(
|
||||
height: 50,
|
||||
child: selectedPlayers.isEmpty
|
||||
? const Center(child: Text('No players selected'))
|
||||
? Center(
|
||||
child: Text(
|
||||
AppLocalizations.of(context)!.no_players_selected,
|
||||
),
|
||||
)
|
||||
: SingleChildScrollView(
|
||||
scrollDirection: Axis.horizontal,
|
||||
child: Row(
|
||||
@@ -171,8 +178,8 @@ class _PlayerSelectionState extends State<PlayerSelection> {
|
||||
),
|
||||
),
|
||||
const SizedBox(height: 10),
|
||||
const Text(
|
||||
'All players:',
|
||||
Text(
|
||||
AppLocalizations.of(context)!.all_players,
|
||||
style: TextStyle(fontSize: 16, fontWeight: FontWeight.bold),
|
||||
),
|
||||
const SizedBox(height: 10),
|
||||
@@ -186,12 +193,14 @@ class _PlayerSelectionState extends State<PlayerSelection> {
|
||||
visible: suggestedPlayers.isNotEmpty,
|
||||
replacement: TopCenteredMessage(
|
||||
icon: Icons.info,
|
||||
title: 'Info',
|
||||
title: AppLocalizations.of(context)!.info,
|
||||
message: allPlayers.isEmpty
|
||||
? 'No players created yet'
|
||||
? AppLocalizations.of(context)!.no_players_created_yet
|
||||
: (selectedPlayers.length == allPlayers.length)
|
||||
? 'No more players to add'
|
||||
: 'No players found with that name',
|
||||
? AppLocalizations.of(context)!.all_players_selected
|
||||
: AppLocalizations.of(
|
||||
context,
|
||||
)!.no_players_found_with_that_name,
|
||||
),
|
||||
child: ListView.builder(
|
||||
itemCount: suggestedPlayers.length,
|
||||
@@ -243,7 +252,9 @@ class _PlayerSelectionState extends State<PlayerSelection> {
|
||||
backgroundColor: CustomTheme.boxColor,
|
||||
content: Center(
|
||||
child: Text(
|
||||
'Successfully added player $playerName.',
|
||||
AppLocalizations.of(
|
||||
context,
|
||||
)!.successfully_added_player(playerName),
|
||||
style: const TextStyle(color: Colors.white),
|
||||
),
|
||||
),
|
||||
@@ -255,7 +266,7 @@ class _PlayerSelectionState extends State<PlayerSelection> {
|
||||
backgroundColor: CustomTheme.boxColor,
|
||||
content: Center(
|
||||
child: Text(
|
||||
'Could not add player $playerName.',
|
||||
AppLocalizations.of(context)!.could_not_add_player(playerName),
|
||||
style: const TextStyle(color: Colors.white),
|
||||
),
|
||||
),
|
||||
|
||||
@@ -1,6 +1,7 @@
|
||||
import 'package:flutter/material.dart';
|
||||
import 'package:game_tracker/core/custom_theme.dart';
|
||||
import 'package:game_tracker/data/dto/match.dart';
|
||||
import 'package:game_tracker/l10n/generated/app_localizations.dart';
|
||||
import 'package:game_tracker/presentation/widgets/tiles/text_icon_tile.dart';
|
||||
import 'package:intl/intl.dart';
|
||||
|
||||
@@ -97,7 +98,7 @@ class _GameHistoryTileState extends State<GameHistoryTile> {
|
||||
const SizedBox(width: 8),
|
||||
Expanded(
|
||||
child: Text(
|
||||
'Winner: ${winner.name}',
|
||||
AppLocalizations.of(context)!.winner(winner.name),
|
||||
style: const TextStyle(
|
||||
fontSize: 14,
|
||||
fontWeight: FontWeight.w600,
|
||||
@@ -113,8 +114,8 @@ class _GameHistoryTileState extends State<GameHistoryTile> {
|
||||
],
|
||||
|
||||
if (allPlayers.isNotEmpty) ...[
|
||||
const Text(
|
||||
'Players',
|
||||
Text(
|
||||
AppLocalizations.of(context)!.players,
|
||||
style: TextStyle(
|
||||
fontSize: 13,
|
||||
color: Colors.grey,
|
||||
@@ -141,11 +142,15 @@ class _GameHistoryTileState extends State<GameHistoryTile> {
|
||||
final difference = now.difference(dateTime);
|
||||
|
||||
if (difference.inDays == 0) {
|
||||
return 'Today at ${DateFormat('HH:mm').format(dateTime)}';
|
||||
return AppLocalizations.of(
|
||||
context,
|
||||
)!.today_at(DateFormat('HH:mm').format(dateTime));
|
||||
} else if (difference.inDays == 1) {
|
||||
return 'Yesterday at ${DateFormat('HH:mm').format(dateTime)}';
|
||||
return AppLocalizations.of(
|
||||
context,
|
||||
)!.yesterday_at(DateFormat('HH:mm').format(dateTime));
|
||||
} else if (difference.inDays < 7) {
|
||||
return '${difference.inDays} days ago';
|
||||
return AppLocalizations.of(context)!.days_ago(difference.inDays);
|
||||
} else {
|
||||
return DateFormat('MMM d, yyyy').format(dateTime);
|
||||
}
|
||||
|
||||
@@ -1,6 +1,7 @@
|
||||
import 'dart:math';
|
||||
|
||||
import 'package:flutter/material.dart';
|
||||
import 'package:game_tracker/l10n/generated/app_localizations.dart';
|
||||
import 'package:game_tracker/presentation/widgets/tiles/info_tile.dart';
|
||||
|
||||
class StatisticsTile extends StatelessWidget {
|
||||
@@ -33,9 +34,9 @@ class StatisticsTile extends StatelessWidget {
|
||||
padding: const EdgeInsets.symmetric(horizontal: 20.0),
|
||||
child: Visibility(
|
||||
visible: values.isNotEmpty,
|
||||
replacement: const Center(
|
||||
replacement: Center(
|
||||
heightFactor: 4,
|
||||
child: Text('No data available.'),
|
||||
child: Text(AppLocalizations.of(context)!.no_data_available),
|
||||
),
|
||||
child: Column(
|
||||
children: List.generate(min(values.length, itemCount), (index) {
|
||||
|
||||
Reference in New Issue
Block a user
Debug-Print entfernen