Lokalisierung implementieren #112

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

View File

@@ -1,4 +1,5 @@
arb-dir: lib/l10n/arb
template-arb-file: app_en.arb
output-localization-file: app_localizations.dart
output-dir: lib/l10n/generated
output-dir: lib/l10n/generated
nullable-getter: false

View File

@@ -37,12 +37,12 @@ enum Ruleset { singleWinner, singleLoser, mostPoints, leastPoints }
String translateRulesetToString(Ruleset ruleset, BuildContext context) {
switch (ruleset) {
case Ruleset.singleWinner:
return AppLocalizations.of(context)!.single_winner;
return AppLocalizations.of(context).single_winner;
case Ruleset.singleLoser:
return AppLocalizations.of(context)!.single_loser;
return AppLocalizations.of(context).single_loser;
case Ruleset.mostPoints:
return AppLocalizations.of(context)!.most_points;
return AppLocalizations.of(context).most_points;
case Ruleset.leastPoints:
return AppLocalizations.of(context)!.least_points;
return AppLocalizations.of(context).least_points;
}
}

View File

@@ -67,8 +67,8 @@ abstract class AppLocalizations {
final String localeName;
static AppLocalizations? of(BuildContext context) {
return Localizations.of<AppLocalizations>(context, AppLocalizations);
static AppLocalizations of(BuildContext context) {
return Localizations.of<AppLocalizations>(context, AppLocalizations)!;
}
static const LocalizationsDelegate<AppLocalizations> delegate =

View File

@@ -90,28 +90,28 @@ class _CustomNavigationBarState extends State<CustomNavigationBar>
index: 0,
isSelected: currentIndex == 0,
icon: Icons.home_rounded,
label: AppLocalizations.of(context)!.home,
label: AppLocalizations.of(context).home,
onTabTapped: onTabTapped,
),
NavbarItem(
index: 1,
isSelected: currentIndex == 1,
icon: Icons.gamepad_rounded,
label: AppLocalizations.of(context)!.matches,
label: AppLocalizations.of(context).matches,
onTabTapped: onTabTapped,
),
NavbarItem(
index: 2,
isSelected: currentIndex == 2,
icon: Icons.group_rounded,
label: AppLocalizations.of(context)!.groups,
label: AppLocalizations.of(context).groups,
onTabTapped: onTabTapped,
),
NavbarItem(
index: 3,
isSelected: currentIndex == 3,
icon: Icons.bar_chart_rounded,
label: AppLocalizations.of(context)!.statistics,
label: AppLocalizations.of(context).statistics,
onTabTapped: onTabTapped,
),
],
@@ -132,13 +132,13 @@ class _CustomNavigationBarState extends State<CustomNavigationBar>
String _currentTabTitle() {
switch (currentIndex) {
case 0:
return AppLocalizations.of(context)!.home;
return AppLocalizations.of(context).home;
case 1:
return AppLocalizations.of(context)!.matches;
return AppLocalizations.of(context).matches;
case 2:
return AppLocalizations.of(context)!.groups;
return AppLocalizations.of(context).groups;
case 3:
return AppLocalizations.of(context)!.statistics;
return AppLocalizations.of(context).statistics;
default:
return '';
}

View File

@@ -45,7 +45,7 @@ class _CreateGroupViewState extends State<CreateGroupView> {
backgroundColor: CustomTheme.backgroundColor,
scrolledUnderElevation: 0,
title: Text(
AppLocalizations.of(context)!.create_new_group,
AppLocalizations.of(context).create_new_group,
style: const TextStyle(fontSize: 20, fontWeight: FontWeight.bold),
),
centerTitle: true,
@@ -58,7 +58,7 @@ class _CreateGroupViewState extends State<CreateGroupView> {
margin: const EdgeInsets.symmetric(horizontal: 12, vertical: 10),
child: TextInputField(
controller: _groupNameController,
hintText: AppLocalizations.of(context)!.group_name,
hintText: AppLocalizations.of(context).group_name,
onChanged: (value) {
setState(() {});
},
@@ -74,7 +74,7 @@ class _CreateGroupViewState extends State<CreateGroupView> {
),
),
CustomWidthButton(
text: AppLocalizations.of(context)!.create_group,
text: AppLocalizations.of(context).create_group,
sizeRelativeToWidth: 0.95,
buttonType: ButtonType.primary,
onPressed:

View File

@@ -53,8 +53,8 @@ class _GroupsViewState extends State<GroupsView> {
replacement: Center(
child: TopCenteredMessage(
icon: Icons.info,
title: AppLocalizations.of(context)!.info,
message: AppLocalizations.of(context)!.no_groups_created_yet,
title: AppLocalizations.of(context).info,
message: AppLocalizations.of(context).no_groups_created_yet,
),
),
child: ListView.builder(
@@ -74,7 +74,7 @@ class _GroupsViewState extends State<GroupsView> {
Positioned(
bottom: MediaQuery.paddingOf(context).bottom,
child: CustomWidthButton(
text: AppLocalizations.of(context)!.create_group,
text: AppLocalizations.of(context).create_group,
sizeRelativeToWidth: 0.90,
onPressed: () async {
await Navigator.push(

View File

@@ -87,7 +87,7 @@ class _HomeViewState extends State<HomeView> {
QuickInfoTile(
width: constraints.maxWidth * 0.45,
height: constraints.maxHeight * 0.15,
title: AppLocalizations.of(context)!.matches,
title: AppLocalizations.of(context).matches,
icon: Icons.groups_rounded,
value: matchCount,
),
@@ -95,7 +95,7 @@ class _HomeViewState extends State<HomeView> {
QuickInfoTile(
width: constraints.maxWidth * 0.45,
height: constraints.maxHeight * 0.15,
title: AppLocalizations.of(context)!.groups,
title: AppLocalizations.of(context).groups,
icon: Icons.groups_rounded,
value: groupCount,
),
@@ -105,7 +105,7 @@ class _HomeViewState extends State<HomeView> {
padding: const EdgeInsets.symmetric(vertical: 16.0),
child: InfoTile(
width: constraints.maxWidth * 0.95,
title: AppLocalizations.of(context)!.recent_matches,
title: AppLocalizations.of(context).recent_matches,
icon: Icons.timer,
content: Padding(
padding: const EdgeInsets.symmetric(horizontal: 40.0),
@@ -125,7 +125,7 @@ class _HomeViewState extends State<HomeView> {
children: [
MatchSummaryTile(
matchTitle: recentMatches[0].name,
game: AppLocalizations.of(context)!.winner_label,
game: AppLocalizations.of(context).winner_label,
ruleset: AppLocalizations.of(
context,
)!.ruleset_label,
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
@@ -175,7 +175,7 @@ class _HomeViewState extends State<HomeView> {
),
InfoTile(
width: constraints.maxWidth * 0.95,
title: AppLocalizations.of(context)!.quick_create,
title: AppLocalizations.of(context).quick_create,
icon: Icons.add_box_rounded,
content: Column(
children: [
@@ -232,7 +232,7 @@ class _HomeViewState extends State<HomeView> {
String _getPlayerText(Match game) {
if (game.group == null) {
final playerCount = game.players?.length ?? 0;
return AppLocalizations.of(context)!.players_count(playerCount);
return AppLocalizations.of(context).players_count(playerCount);
}
if (game.players == null || game.players!.isEmpty) {
return game.group!.name;

View File

@@ -43,7 +43,7 @@ class _ChooseGameViewState extends State<ChooseGameView> {
},
),
title: Text(
AppLocalizations.of(context)!.choose_game,
AppLocalizations.of(context).choose_game,
style: const TextStyle(fontSize: 20, fontWeight: FontWeight.bold),
),
centerTitle: true,
@@ -54,7 +54,7 @@ class _ChooseGameViewState extends State<ChooseGameView> {
padding: const EdgeInsets.symmetric(horizontal: 10),
child: CustomSearchBar(
controller: searchBarController,
hintText: AppLocalizations.of(context)!.game_name,
hintText: AppLocalizations.of(context).game_name,
),
),
const SizedBox(height: 5),

View File

@@ -52,7 +52,7 @@ class _ChooseGroupViewState extends State<ChooseGroupView> {
},
),
title: Text(
AppLocalizations.of(context)!.choose_group,
AppLocalizations.of(context).choose_group,
style: const 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: AppLocalizations.of(context)!.search_for_groups,
hintText: AppLocalizations.of(context).search_for_groups,
onChanged: (value) {
setState(() {
filterGroups(value);
@@ -78,12 +78,12 @@ class _ChooseGroupViewState extends State<ChooseGroupView> {
visible: widget.groups.isNotEmpty,
replacement: TopCenteredMessage(
icon: Icons.info,
title: AppLocalizations.of(context)!.info,
message: AppLocalizations.of(context)!.no_groups_created_yet,
title: AppLocalizations.of(context).info,
message: AppLocalizations.of(context).no_groups_created_yet,
),
child: TopCenteredMessage(
icon: Icons.info,
title: AppLocalizations.of(context)!.info,
title: AppLocalizations.of(context).info,
message: AppLocalizations.of(
context,
)!.there_is_no_group_matching_your_search,

View File

@@ -48,7 +48,7 @@ class _ChooseRulesetViewState extends State<ChooseRulesetView> {
},
),
title: Text(
AppLocalizations.of(context)!.choose_ruleset,
AppLocalizations.of(context).choose_ruleset,
style: const TextStyle(fontSize: 20, fontWeight: FontWeight.bold),
),
centerTitle: true,

View File

@@ -91,19 +91,19 @@ class _CreateMatchViewState extends State<CreateMatchView> {
return [
(
Ruleset.singleWinner,
AppLocalizations.of(context)!.ruleset_single_winner_desc,
AppLocalizations.of(context).ruleset_single_winner_desc,
),
(
sneeex marked this conversation as resolved Outdated

Warum _desc?

Warum `_desc`?
Ruleset.singleLoser,
AppLocalizations.of(context)!.ruleset_single_loser_desc,
AppLocalizations.of(context).ruleset_single_loser_desc,
),
(
Ruleset.mostPoints,
AppLocalizations.of(context)!.ruleset_most_points_desc,
AppLocalizations.of(context).ruleset_most_points_desc,
),
(
Ruleset.leastPoints,
AppLocalizations.of(context)!.ruleset_least_points_desc,
AppLocalizations.of(context).ruleset_least_points_desc,
),
];
}
@@ -122,7 +122,7 @@ class _CreateMatchViewState extends State<CreateMatchView> {
backgroundColor: CustomTheme.backgroundColor,
scrolledUnderElevation: 0,
title: Text(
AppLocalizations.of(context)!.create_new_match,
AppLocalizations.of(context).create_new_match,
style: const TextStyle(fontSize: 20, fontWeight: FontWeight.bold),
),
centerTitle: true,
@@ -139,9 +139,9 @@ class _CreateMatchViewState extends State<CreateMatchView> {
),
),
ChooseTile(
title: AppLocalizations.of(context)!.game,
title: AppLocalizations.of(context).game,
trailingText: selectedGameIndex == -1
? AppLocalizations.of(context)!.none
? AppLocalizations.of(context).none
: games[selectedGameIndex].$1,
onPressed: () async {
selectedGameIndex = await Navigator.of(context).push(
@@ -167,9 +167,9 @@ class _CreateMatchViewState extends State<CreateMatchView> {
},
),
ChooseTile(
title: AppLocalizations.of(context)!.ruleset,
title: AppLocalizations.of(context).ruleset,
trailingText: selectedRuleset == null
? AppLocalizations.of(context)!.none
? AppLocalizations.of(context).none
: translateRulesetToString(selectedRuleset!, context),
onPressed: () async {
final rulesets = _getRulesets(context);
@@ -190,9 +190,9 @@ class _CreateMatchViewState extends State<CreateMatchView> {
},
),
ChooseTile(
title: AppLocalizations.of(context)!.group,
title: AppLocalizations.of(context).group,
trailingText: selectedGroup == null
? AppLocalizations.of(context)!.none_group
? AppLocalizations.of(context).none_group
: selectedGroup!.name,
onPressed: () async {
selectedGroup = await Navigator.of(context).push(
@@ -229,7 +229,7 @@ class _CreateMatchViewState extends State<CreateMatchView> {
),
),
CustomWidthButton(
text: AppLocalizations.of(context)!.create_match,
text: AppLocalizations.of(context).create_match,
sizeRelativeToWidth: 0.95,
buttonType: ButtonType.primary,
onPressed: _enableCreateGameButton()

View File

@@ -81,7 +81,7 @@ class _MatchResultViewState extends State<MatchResultView> {
crossAxisAlignment: CrossAxisAlignment.start,
children: [
Text(
AppLocalizations.of(context)!.select_winner,
AppLocalizations.of(context).select_winner,
style: const TextStyle(
fontSize: 18,
fontWeight: FontWeight.bold,

View File

@@ -62,8 +62,8 @@ class _MatchViewState extends State<MatchView> {
replacement: Center(
child: TopCenteredMessage(
icon: Icons.report,
title: AppLocalizations.of(context)!.info,
message: AppLocalizations.of(context)!.no_matches_created_yet,
title: AppLocalizations.of(context).info,
message: AppLocalizations.of(context).no_matches_created_yet,
),
),
child: ListView.builder(
@@ -97,7 +97,7 @@ class _MatchViewState extends State<MatchView> {
Positioned(
bottom: MediaQuery.paddingOf(context).bottom,
child: CustomWidthButton(
text: AppLocalizations.of(context)!.create_match,
text: AppLocalizations.of(context).create_match,
sizeRelativeToWidth: 0.90,
onPressed: () async {
Navigator.push(

View File

@@ -29,7 +29,7 @@ class _SettingsViewState extends State<SettingsView> {
padding: const EdgeInsets.fromLTRB(24, 0, 24, 10),
child: Text(
textAlign: TextAlign.start,
AppLocalizations.of(context)!.menu,
AppLocalizations.of(context).menu,
style: const TextStyle(
fontSize: 28,
fontWeight: FontWeight.bold,
@@ -43,7 +43,7 @@ class _SettingsViewState extends State<SettingsView> {
),
child: Text(
textAlign: TextAlign.start,
AppLocalizations.of(context)!.settings,
AppLocalizations.of(context).settings,
style: const TextStyle(
fontSize: 22,
fontWeight: FontWeight.bold,
@@ -51,7 +51,7 @@ class _SettingsViewState extends State<SettingsView> {
),
),
SettingsListTile(
title: AppLocalizations.of(context)!.export_data,
title: AppLocalizations.of(context).export_data,
icon: Icons.upload_outlined,
suffixWidget: const Icon(Icons.arrow_forward_ios, size: 16),
onPressed: () async {
@@ -66,7 +66,7 @@ class _SettingsViewState extends State<SettingsView> {
},
),
SettingsListTile(
title: AppLocalizations.of(context)!.import_data,
title: AppLocalizations.of(context).import_data,
icon: Icons.download_outlined,
suffixWidget: const Icon(Icons.arrow_forward_ios, size: 16),
onPressed: () async {
@@ -78,7 +78,7 @@ class _SettingsViewState extends State<SettingsView> {
},
),
SettingsListTile(
title: AppLocalizations.of(context)!.delete_all_data,
title: AppLocalizations.of(context).delete_all_data,
icon: Icons.download_outlined,
suffixWidget: const Icon(Icons.arrow_forward_ios, size: 16),
onPressed: () {
@@ -86,19 +86,19 @@ class _SettingsViewState extends State<SettingsView> {
context: context,
builder: (context) => AlertDialog(
title: Text(
AppLocalizations.of(context)!.delete_all_data,
AppLocalizations.of(context).delete_all_data,
),
content: Text(
AppLocalizations.of(context)!.this_cannot_be_undone,
AppLocalizations.of(context).this_cannot_be_undone,
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.
),
actions: [
TextButton(
onPressed: () => Navigator.of(context).pop(false),
child: Text(AppLocalizations.of(context)!.cancel),
child: Text(AppLocalizations.of(context).cancel),
),
TextButton(
onPressed: () => Navigator.of(context).pop(true),
child: Text(AppLocalizations.of(context)!.delete),
child: Text(AppLocalizations.of(context).delete),
),
],
),
@@ -134,32 +134,32 @@ class _SettingsViewState extends State<SettingsView> {
case ImportResult.success:
showSnackbar(
context: context,
message: AppLocalizations.of(context)!.data_successfully_imported,
message: AppLocalizations.of(context).data_successfully_imported,
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.
);
case ImportResult.invalidSchema:
showSnackbar(
context: context,
message: AppLocalizations.of(context)!.invalid_schema,
message: AppLocalizations.of(context).invalid_schema,
);
case ImportResult.fileReadError:
showSnackbar(
context: context,
message: AppLocalizations.of(context)!.error_reading_file,
message: AppLocalizations.of(context).error_reading_file,
);
case ImportResult.canceled:
showSnackbar(
context: context,
message: AppLocalizations.of(context)!.import_canceled,
message: AppLocalizations.of(context).import_canceled,
);
case ImportResult.formatException:
showSnackbar(
context: context,
message: AppLocalizations.of(context)!.format_exception,
message: AppLocalizations.of(context).format_exception,
);
case ImportResult.unknownException:
showSnackbar(
context: context,
message: AppLocalizations.of(context)!.unknown_exception,
message: AppLocalizations.of(context).unknown_exception,
);
}
}
@@ -176,17 +176,17 @@ class _SettingsViewState extends State<SettingsView> {
case ExportResult.success:
showSnackbar(
context: context,
message: AppLocalizations.of(context)!.data_successfully_exported,
message: AppLocalizations.of(context).data_successfully_exported,
);
case ExportResult.canceled:
showSnackbar(
context: context,
message: AppLocalizations.of(context)!.export_canceled,
message: AppLocalizations.of(context).export_canceled,
);
case ExportResult.unknownException:
showSnackbar(
context: context,
message: AppLocalizations.of(context)!.unknown_exception,
message: AppLocalizations.of(context).unknown_exception,
);
}
}
@@ -212,7 +212,7 @@ class _SettingsViewState extends State<SettingsView> {
duration: duration,
action: action != null
? SnackBarAction(
label: AppLocalizations.of(context)!.undo,
label: AppLocalizations.of(context).undo,
onPressed: action,
)
: null,

View File

@@ -69,7 +69,7 @@ class _StatisticsViewState extends State<StatisticsView> {
children: [
StatisticsTile(
icon: Icons.sports_score,
title: AppLocalizations.of(context)!.wins,
title: AppLocalizations.of(context).wins,
width: constraints.maxWidth * 0.95,
values: winCounts,
itemCount: 3,
@@ -78,7 +78,7 @@ class _StatisticsViewState extends State<StatisticsView> {
SizedBox(height: constraints.maxHeight * 0.02),
StatisticsTile(
icon: Icons.percent,
title: AppLocalizations.of(context)!.winrate,
title: AppLocalizations.of(context).winrate,
width: constraints.maxWidth * 0.95,
values: winRates,
itemCount: 5,
@@ -99,7 +99,7 @@ class _StatisticsViewState extends State<StatisticsView> {
),
child: TopCenteredMessage(
icon: Icons.info,
title: AppLocalizations.of(context)!.info,
title: AppLocalizations.of(context).info,
message: AppLocalizations.of(
context,
)!.no_statistics_available,
@@ -154,7 +154,7 @@ class _StatisticsViewState extends State<StatisticsView> {
(p) => p.id == playerId,
orElse: () => Player(
id: playerId,
name: AppLocalizations.of(context)!.not_available,
name: AppLocalizations.of(context).not_available,
),
);
winCounts[i] = (player.name, winCounts[i].$2);
@@ -219,7 +219,7 @@ class _StatisticsViewState extends State<StatisticsView> {
(p) => p.id == playerId,
orElse: () => Player(
id: playerId,
name: AppLocalizations.of(context)!.not_available,
name: AppLocalizations.of(context).not_available,
),
);
matchCounts[i] = (player.name, matchCounts[i].$2);

View File

@@ -97,7 +97,7 @@ class _PlayerSelectionState extends State<PlayerSelection> {
CustomSearchBar(
controller: _searchBarController,
constraints: const BoxConstraints(maxHeight: 45, minHeight: 45),
hintText: AppLocalizations.of(context)!.search_for_players,
hintText: AppLocalizations.of(context).search_for_players,
trailingButtonShown: true,
trailingButtonicon: Icons.add_circle,
trailingButtonEnabled: _searchBarController.text.trim().isNotEmpty,
@@ -141,7 +141,7 @@ class _PlayerSelectionState extends State<PlayerSelection> {
child: selectedPlayers.isEmpty
? Center(
child: Text(
AppLocalizations.of(context)!.no_players_selected,
AppLocalizations.of(context).no_players_selected,
),
)
: SingleChildScrollView(
@@ -185,7 +185,7 @@ class _PlayerSelectionState extends State<PlayerSelection> {
),
const SizedBox(height: 10),
Text(
AppLocalizations.of(context)!.all_players,
AppLocalizations.of(context).all_players,
style: const TextStyle(fontSize: 16, fontWeight: FontWeight.bold),
),
const SizedBox(height: 10),
@@ -199,11 +199,11 @@ class _PlayerSelectionState extends State<PlayerSelection> {
visible: suggestedPlayers.isNotEmpty,
replacement: TopCenteredMessage(
icon: Icons.info,
title: AppLocalizations.of(context)!.info,
title: AppLocalizations.of(context).info,
message: allPlayers.isEmpty
? AppLocalizations.of(context)!.no_players_created_yet
? AppLocalizations.of(context).no_players_created_yet
: (selectedPlayers.length == allPlayers.length)
? AppLocalizations.of(context)!.all_players_selected
? AppLocalizations.of(context).all_players_selected
: AppLocalizations.of(
context,
)!.no_players_found_with_that_name,
@@ -276,7 +276,7 @@ class _PlayerSelectionState extends State<PlayerSelection> {
backgroundColor: CustomTheme.boxColor,
content: Center(
child: Text(
AppLocalizations.of(context)!.could_not_add_player(playerName),
AppLocalizations.of(context).could_not_add_player(playerName),
style: const TextStyle(color: Colors.white),
),
),

View File

@@ -98,7 +98,7 @@ class _MatchTileState extends State<MatchTile> {
const SizedBox(width: 8),
Expanded(
child: Text(
AppLocalizations.of(context)!.winner(winner.name),
AppLocalizations.of(context).winner(winner.name),
style: const TextStyle(
fontSize: 14,
fontWeight: FontWeight.w600,
@@ -115,7 +115,7 @@ class _MatchTileState extends State<MatchTile> {
if (allPlayers.isNotEmpty) ...[
Text(
AppLocalizations.of(context)!.players,
AppLocalizations.of(context).players,
style: const TextStyle(
fontSize: 13,
color: Colors.grey,
@@ -150,7 +150,7 @@ class _MatchTileState extends State<MatchTile> {
context,
)!.yesterday_at(DateFormat('HH:mm').format(dateTime));
} else if (difference.inDays < 7) {
return AppLocalizations.of(context)!.days_ago(difference.inDays);
return AppLocalizations.of(context).days_ago(difference.inDays);
} else {
return DateFormat('MMM d, yyyy').format(dateTime);
}

View File

@@ -36,7 +36,7 @@ class StatisticsTile extends StatelessWidget {
visible: values.isNotEmpty,
replacement: Center(
heightFactor: 4,
child: Text(AppLocalizations.of(context)!.no_data_available),
child: Text(AppLocalizations.of(context).no_data_available),
),
child: Column(
children: List.generate(min(values.length, itemCount), (index) {