feat: statistic detail view
This commit is contained in:
@@ -80,12 +80,13 @@ class StatisticDao extends DatabaseAccessor<AppDatabase>
|
|||||||
result.map((row) async {
|
result.map((row) async {
|
||||||
final groups = await db.statisticGroupDao.getGroupsForStatistic(row.id);
|
final groups = await db.statisticGroupDao.getGroupsForStatistic(row.id);
|
||||||
final games = await db.statisticGameDao.getGamesForStatistic(row.id);
|
final games = await db.statisticGameDao.getGamesForStatistic(row.id);
|
||||||
|
final scopes = await db.statisticScopeDao.getScopeForStatistic(row.id);
|
||||||
|
|
||||||
return Statistic(
|
return Statistic(
|
||||||
type: StatisticType.values.firstWhere(
|
type: StatisticType.values.firstWhere(
|
||||||
(type) => type.name == row.type,
|
(type) => type.name == row.type,
|
||||||
),
|
),
|
||||||
scopes: [],
|
scopes: scopes,
|
||||||
timeframe: Timeframe.values.firstWhereOrNull(
|
timeframe: Timeframe.values.firstWhereOrNull(
|
||||||
(t) => t.name == row.timeframe,
|
(t) => t.name == row.timeframe,
|
||||||
),
|
),
|
||||||
|
|||||||
@@ -12,12 +12,13 @@ class StatisticGameDao extends DatabaseAccessor<AppDatabase>
|
|||||||
StatisticGameDao(super.db);
|
StatisticGameDao(super.db);
|
||||||
|
|
||||||
/// Retrieves a list of games associated with a specific statistic.
|
/// Retrieves a list of games associated with a specific statistic.
|
||||||
Future<List<Game>> getGamesForStatistic(String statisticId) async {
|
Future<List<Game>?> getGamesForStatistic(String statisticId) async {
|
||||||
final query = select(statisticGameTable).join([
|
final query = select(statisticGameTable).join([
|
||||||
innerJoin(gameTable, gameTable.id.equalsExp(statisticGameTable.gameId)),
|
innerJoin(gameTable, gameTable.id.equalsExp(statisticGameTable.gameId)),
|
||||||
])..where(statisticGameTable.statisticId.equals(statisticId));
|
])..where(statisticGameTable.statisticId.equals(statisticId));
|
||||||
|
|
||||||
final results = await query.map((row) => row.readTable(gameTable)).get();
|
final results = await query.map((row) => row.readTable(gameTable)).get();
|
||||||
|
if (results.isEmpty) return null;
|
||||||
return results
|
return results
|
||||||
.map(
|
.map(
|
||||||
(row) => Game(
|
(row) => Game(
|
||||||
|
|||||||
@@ -12,7 +12,7 @@ class StatisticGroupDao extends DatabaseAccessor<AppDatabase>
|
|||||||
StatisticGroupDao(super.db);
|
StatisticGroupDao(super.db);
|
||||||
|
|
||||||
/// Retrieves a list of groups associated with a specific statistic.
|
/// Retrieves a list of groups associated with a specific statistic.
|
||||||
Future<List<Group>> getGroupsForStatistic(String statisticId) async {
|
Future<List<Group>?> getGroupsForStatistic(String statisticId) async {
|
||||||
final query = select(statisticGroupTable).join([
|
final query = select(statisticGroupTable).join([
|
||||||
innerJoin(
|
innerJoin(
|
||||||
groupTable,
|
groupTable,
|
||||||
@@ -21,6 +21,7 @@ class StatisticGroupDao extends DatabaseAccessor<AppDatabase>
|
|||||||
])..where(statisticGroupTable.statisticId.equals(statisticId));
|
])..where(statisticGroupTable.statisticId.equals(statisticId));
|
||||||
|
|
||||||
final results = await query.map((row) => row.readTable(groupTable)).get();
|
final results = await query.map((row) => row.readTable(groupTable)).get();
|
||||||
|
if (results.isEmpty) return null;
|
||||||
final groups = await Future.wait(
|
final groups = await Future.wait(
|
||||||
results.map((result) async {
|
results.map((result) async {
|
||||||
final groupMembers = await db.playerGroupDao.getPlayersOfGroup(
|
final groupMembers = await db.playerGroupDao.getPlayersOfGroup(
|
||||||
|
|||||||
@@ -15,8 +15,8 @@ class StatisticScopeDao extends DatabaseAccessor<AppDatabase>
|
|||||||
final query = select(statisticScopeTable)
|
final query = select(statisticScopeTable)
|
||||||
..where((tbl) => tbl.statisticId.equals(statisticId));
|
..where((tbl) => tbl.statisticId.equals(statisticId));
|
||||||
|
|
||||||
final results = await query.get();
|
final result = await query.get();
|
||||||
return results
|
return result
|
||||||
.map(
|
.map(
|
||||||
(row) => StatisticScope.values.firstWhere(
|
(row) => StatisticScope.values.firstWhere(
|
||||||
(e) => e.name == row.scope,
|
(e) => e.name == row.scope,
|
||||||
|
|||||||
@@ -21,6 +21,13 @@
|
|||||||
"color_yellow": "Gelb",
|
"color_yellow": "Gelb",
|
||||||
"confirm": "Bestätigen",
|
"confirm": "Bestätigen",
|
||||||
"could_not_add_player": "Spieler:in {playerName} konnte nicht hinzugefügt werden",
|
"could_not_add_player": "Spieler:in {playerName} konnte nicht hinzugefügt werden",
|
||||||
|
"@could_not_add_player": {
|
||||||
|
"placeholders": {
|
||||||
|
"playerName": {
|
||||||
|
"type": "String"
|
||||||
|
}
|
||||||
|
}
|
||||||
|
},
|
||||||
"create_game": "Spielvorlage erstellen",
|
"create_game": "Spielvorlage erstellen",
|
||||||
"create_group": "Gruppe erstellen",
|
"create_group": "Gruppe erstellen",
|
||||||
"create_match": "Spiel erstellen",
|
"create_match": "Spiel erstellen",
|
||||||
|
|||||||
@@ -20,23 +20,29 @@
|
|||||||
"color_teal": "Teal",
|
"color_teal": "Teal",
|
||||||
"color_yellow": "Yellow",
|
"color_yellow": "Yellow",
|
||||||
"confirm": "Confirm",
|
"confirm": "Confirm",
|
||||||
"could_not_add_player": "Could not add player",
|
"could_not_add_player": "Could not add player {playerName}",
|
||||||
|
"@could_not_add_player": {
|
||||||
|
"placeholders": {
|
||||||
|
"playerName": {
|
||||||
|
"type": "String"
|
||||||
|
}
|
||||||
|
}
|
||||||
|
},
|
||||||
"create_game": "Create Game",
|
"create_game": "Create Game",
|
||||||
"create_group": "Create Group",
|
"create_group": "Create Group",
|
||||||
"create_match": "Create match",
|
"create_match": "Create match",
|
||||||
"create_new_group": "Create new group",
|
"create_new_group": "Create new group",
|
||||||
"create_new_match": "Create new match",
|
"create_new_match": "Create new match",
|
||||||
"create_statistic": "Create statistic",
|
"create_statistic": "Create statistic",
|
||||||
"create_statistic_classifier_subtitle": "Select which key metric you want to display",
|
"which_key_metric": "Select which key metric you want to display",
|
||||||
"create_statistic_classifier_title": "Classifier",
|
"classifier": "Classifier",
|
||||||
"create_statistic_games_subtitle": "Select the filtered games",
|
"select_the_filtered_games": "Select the filtered games",
|
||||||
"create_statistic_games_title": "Games",
|
"games": "Games",
|
||||||
"create_statistic_groups_subtitle": "Select the filtered groups",
|
"select_the_filtered_groups": "Select the filtered groups",
|
||||||
"create_statistic_groups_title": "Groups",
|
"select_main_filter": "Select the main filter for your statistic. This will determine which data is used to calculate the selected classifier.",
|
||||||
"create_statistic_scope_subtitle": "Select the main filter for your statistic. This will determine which data is used to calculate the selected classifier.",
|
"scope": "Scope",
|
||||||
"create_statistic_scope_title": "Scope",
|
"select_a_timeframe_for_which_data_will_be_filtered": "Select a timeframe for which the data will be filtered. Only matches that ended within the selected timeframe will be included in the statistic.",
|
||||||
"create_statistic_timeframe_subtitle": "Select a timeframe for which the data will be filtered. Only matches that ended within the selected timeframe will be included in the statistic.",
|
"timeframe": "Timeframe",
|
||||||
"create_statistic_timeframe_title": "Timeframe",
|
|
||||||
"created_on": "Created on",
|
"created_on": "Created on",
|
||||||
"data": "Data",
|
"data": "Data",
|
||||||
"data_successfully_deleted": "Data successfully deleted",
|
"data_successfully_deleted": "Data successfully deleted",
|
||||||
@@ -54,6 +60,7 @@
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
"filter": "Filter",
|
||||||
"delete_group": "Delete Group",
|
"delete_group": "Delete Group",
|
||||||
"delete_match": "Delete Match",
|
"delete_match": "Delete Match",
|
||||||
"delete_player": "Delete player?",
|
"delete_player": "Delete player?",
|
||||||
@@ -120,6 +127,7 @@
|
|||||||
"no_results_entered_yet": "No results entered yet",
|
"no_results_entered_yet": "No results entered yet",
|
||||||
"no_second_match_available": "No second match available",
|
"no_second_match_available": "No second match available",
|
||||||
"no_statistics_available": "No statistics available",
|
"no_statistics_available": "No statistics available",
|
||||||
|
"no_statistics_created_yet": "No statistics created yet",
|
||||||
"none": "None",
|
"none": "None",
|
||||||
"none_group": "None",
|
"none_group": "None",
|
||||||
"not_available": "Not available",
|
"not_available": "Not available",
|
||||||
|
|||||||
@@ -221,8 +221,8 @@ abstract class AppLocalizations {
|
|||||||
/// No description provided for @could_not_add_player.
|
/// No description provided for @could_not_add_player.
|
||||||
///
|
///
|
||||||
/// In en, this message translates to:
|
/// In en, this message translates to:
|
||||||
/// **'Could not add player'**
|
/// **'Could not add player {playerName}'**
|
||||||
String could_not_add_player(Object playerName);
|
String could_not_add_player(String playerName);
|
||||||
|
|
||||||
/// No description provided for @create_game.
|
/// No description provided for @create_game.
|
||||||
///
|
///
|
||||||
@@ -260,65 +260,59 @@ abstract class AppLocalizations {
|
|||||||
/// **'Create statistic'**
|
/// **'Create statistic'**
|
||||||
String get create_statistic;
|
String get create_statistic;
|
||||||
|
|
||||||
/// No description provided for @create_statistic_classifier_subtitle.
|
/// No description provided for @which_key_metric.
|
||||||
///
|
///
|
||||||
/// In en, this message translates to:
|
/// In en, this message translates to:
|
||||||
/// **'Select which key metric you want to display'**
|
/// **'Select which key metric you want to display'**
|
||||||
String get create_statistic_classifier_subtitle;
|
String get which_key_metric;
|
||||||
|
|
||||||
/// No description provided for @create_statistic_classifier_title.
|
/// No description provided for @classifier.
|
||||||
///
|
///
|
||||||
/// In en, this message translates to:
|
/// In en, this message translates to:
|
||||||
/// **'Classifier'**
|
/// **'Classifier'**
|
||||||
String get create_statistic_classifier_title;
|
String get classifier;
|
||||||
|
|
||||||
/// No description provided for @create_statistic_games_subtitle.
|
/// No description provided for @select_the_filtered_games.
|
||||||
///
|
///
|
||||||
/// In en, this message translates to:
|
/// In en, this message translates to:
|
||||||
/// **'Select the filtered games'**
|
/// **'Select the filtered games'**
|
||||||
String get create_statistic_games_subtitle;
|
String get select_the_filtered_games;
|
||||||
|
|
||||||
/// No description provided for @create_statistic_games_title.
|
/// No description provided for @games.
|
||||||
///
|
///
|
||||||
/// In en, this message translates to:
|
/// In en, this message translates to:
|
||||||
/// **'Games'**
|
/// **'Games'**
|
||||||
String get create_statistic_games_title;
|
String get games;
|
||||||
|
|
||||||
/// No description provided for @create_statistic_groups_subtitle.
|
/// No description provided for @select_the_filtered_groups.
|
||||||
///
|
///
|
||||||
/// In en, this message translates to:
|
/// In en, this message translates to:
|
||||||
/// **'Select the filtered groups'**
|
/// **'Select the filtered groups'**
|
||||||
String get create_statistic_groups_subtitle;
|
String get select_the_filtered_groups;
|
||||||
|
|
||||||
/// No description provided for @create_statistic_groups_title.
|
/// No description provided for @select_main_filter.
|
||||||
///
|
|
||||||
/// In en, this message translates to:
|
|
||||||
/// **'Groups'**
|
|
||||||
String get create_statistic_groups_title;
|
|
||||||
|
|
||||||
/// No description provided for @create_statistic_scope_subtitle.
|
|
||||||
///
|
///
|
||||||
/// In en, this message translates to:
|
/// In en, this message translates to:
|
||||||
/// **'Select the main filter for your statistic. This will determine which data is used to calculate the selected classifier.'**
|
/// **'Select the main filter for your statistic. This will determine which data is used to calculate the selected classifier.'**
|
||||||
String get create_statistic_scope_subtitle;
|
String get select_main_filter;
|
||||||
|
|
||||||
/// No description provided for @create_statistic_scope_title.
|
/// No description provided for @scope.
|
||||||
///
|
///
|
||||||
/// In en, this message translates to:
|
/// In en, this message translates to:
|
||||||
/// **'Scope'**
|
/// **'Scope'**
|
||||||
String get create_statistic_scope_title;
|
String get scope;
|
||||||
|
|
||||||
/// No description provided for @create_statistic_timeframe_subtitle.
|
/// No description provided for @select_a_timeframe_for_which_data_will_be_filtered.
|
||||||
///
|
///
|
||||||
/// In en, this message translates to:
|
/// In en, this message translates to:
|
||||||
/// **'Select a timeframe for which the data will be filtered. Only matches that ended within the selected timeframe will be included in the statistic.'**
|
/// **'Select a timeframe for which the data will be filtered. Only matches that ended within the selected timeframe will be included in the statistic.'**
|
||||||
String get create_statistic_timeframe_subtitle;
|
String get select_a_timeframe_for_which_data_will_be_filtered;
|
||||||
|
|
||||||
/// No description provided for @create_statistic_timeframe_title.
|
/// No description provided for @timeframe.
|
||||||
///
|
///
|
||||||
/// In en, this message translates to:
|
/// In en, this message translates to:
|
||||||
/// **'Timeframe'**
|
/// **'Timeframe'**
|
||||||
String get create_statistic_timeframe_title;
|
String get timeframe;
|
||||||
|
|
||||||
/// No description provided for @created_on.
|
/// No description provided for @created_on.
|
||||||
///
|
///
|
||||||
@@ -380,6 +374,12 @@ abstract class AppLocalizations {
|
|||||||
/// **'If you delete this game template, {count, plural, =1{1 match} other{{count} matches}} using this game template will also be deleted.'**
|
/// **'If you delete this game template, {count, plural, =1{1 match} other{{count} matches}} using this game template will also be deleted.'**
|
||||||
String delete_game_with_matches_warning(int count);
|
String delete_game_with_matches_warning(int count);
|
||||||
|
|
||||||
|
/// No description provided for @filter.
|
||||||
|
///
|
||||||
|
/// In en, this message translates to:
|
||||||
|
/// **'Filter'**
|
||||||
|
String get filter;
|
||||||
|
|
||||||
/// No description provided for @delete_group.
|
/// No description provided for @delete_group.
|
||||||
///
|
///
|
||||||
/// In en, this message translates to:
|
/// In en, this message translates to:
|
||||||
@@ -776,6 +776,12 @@ abstract class AppLocalizations {
|
|||||||
/// **'No statistics available'**
|
/// **'No statistics available'**
|
||||||
String get no_statistics_available;
|
String get no_statistics_available;
|
||||||
|
|
||||||
|
/// No description provided for @no_statistics_created_yet.
|
||||||
|
///
|
||||||
|
/// In en, this message translates to:
|
||||||
|
/// **'No statistics created yet'**
|
||||||
|
String get no_statistics_created_yet;
|
||||||
|
|
||||||
/// No description provided for @none.
|
/// No description provided for @none.
|
||||||
///
|
///
|
||||||
/// In en, this message translates to:
|
/// In en, this message translates to:
|
||||||
|
|||||||
@@ -69,7 +69,7 @@ class AppLocalizationsDe extends AppLocalizations {
|
|||||||
String get confirm => 'Bestätigen';
|
String get confirm => 'Bestätigen';
|
||||||
|
|
||||||
@override
|
@override
|
||||||
String could_not_add_player(Object playerName) {
|
String could_not_add_player(String playerName) {
|
||||||
return 'Spieler:in $playerName konnte nicht hinzugefügt werden';
|
return 'Spieler:in $playerName konnte nicht hinzugefügt werden';
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -92,39 +92,33 @@ class AppLocalizationsDe extends AppLocalizations {
|
|||||||
String get create_statistic => 'Statistik erstellen';
|
String get create_statistic => 'Statistik erstellen';
|
||||||
|
|
||||||
@override
|
@override
|
||||||
String get create_statistic_classifier_subtitle =>
|
String get which_key_metric => 'Select which key metric you want to display';
|
||||||
'Wähle die anzuzeigende Hauptmetrik aus';
|
|
||||||
|
|
||||||
@override
|
@override
|
||||||
String get create_statistic_classifier_title => 'Klassifikator';
|
String get classifier => 'Classifier';
|
||||||
|
|
||||||
@override
|
@override
|
||||||
String get create_statistic_games_subtitle =>
|
String get select_the_filtered_games => 'Select the filtered games';
|
||||||
'Wähle die gefilterten Spielvorlagen';
|
|
||||||
|
|
||||||
@override
|
@override
|
||||||
String get create_statistic_games_title => 'Spielvorlagen';
|
String get games => 'Games';
|
||||||
|
|
||||||
@override
|
@override
|
||||||
String get create_statistic_groups_subtitle =>
|
String get select_the_filtered_groups => 'Select the filtered groups';
|
||||||
'Wähle die gefilterten Gruppen';
|
|
||||||
|
|
||||||
@override
|
@override
|
||||||
String get create_statistic_groups_title => 'Gruppen';
|
String get select_main_filter =>
|
||||||
|
'Select the main filter for your statistic. This will determine which data is used to calculate the selected classifier.';
|
||||||
|
|
||||||
@override
|
@override
|
||||||
String get create_statistic_scope_subtitle =>
|
String get scope => 'Scope';
|
||||||
'Wähle den Hauptfilter für deine Statistik. Er bestimmt, welche Daten zur Berechnung des Klassifikators verwendet werden.';
|
|
||||||
|
|
||||||
@override
|
@override
|
||||||
String get create_statistic_scope_title => 'Bereich';
|
String get select_a_timeframe_for_which_data_will_be_filtered =>
|
||||||
|
'Select a timeframe for which the data will be filtered. Only matches that ended within the selected timeframe will be included in the statistic.';
|
||||||
|
|
||||||
@override
|
@override
|
||||||
String get create_statistic_timeframe_subtitle =>
|
String get timeframe => 'Timeframe';
|
||||||
'Wähle einen Zeitraum, nach dem die Daten gefiltert werden. Nur Spiele, die innerhalb des Zeitraums beendet wurden, fließen in die Statistik ein.';
|
|
||||||
|
|
||||||
@override
|
|
||||||
String get create_statistic_timeframe_title => 'Zeitraum';
|
|
||||||
|
|
||||||
@override
|
@override
|
||||||
String get created_on => 'Erstellt am';
|
String get created_on => 'Erstellt am';
|
||||||
@@ -166,6 +160,9 @@ class AppLocalizationsDe extends AppLocalizations {
|
|||||||
return 'Wenn du diese Spielvorlage löschst, $_temp0 mit dieser Spielvorlage ebenfalls gelöscht.';
|
return 'Wenn du diese Spielvorlage löschst, $_temp0 mit dieser Spielvorlage ebenfalls gelöscht.';
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@override
|
||||||
|
String get filter => 'Filter';
|
||||||
|
|
||||||
@override
|
@override
|
||||||
String get delete_group => 'Gruppe löschen';
|
String get delete_group => 'Gruppe löschen';
|
||||||
|
|
||||||
@@ -369,6 +366,9 @@ class AppLocalizationsDe extends AppLocalizations {
|
|||||||
@override
|
@override
|
||||||
String get no_statistics_available => 'Keine Statistiken verfügbar';
|
String get no_statistics_available => 'Keine Statistiken verfügbar';
|
||||||
|
|
||||||
|
@override
|
||||||
|
String get no_statistics_created_yet => 'No statistics created yet';
|
||||||
|
|
||||||
@override
|
@override
|
||||||
String get none => 'Kein';
|
String get none => 'Kein';
|
||||||
|
|
||||||
|
|||||||
@@ -69,8 +69,8 @@ class AppLocalizationsEn extends AppLocalizations {
|
|||||||
String get confirm => 'Confirm';
|
String get confirm => 'Confirm';
|
||||||
|
|
||||||
@override
|
@override
|
||||||
String could_not_add_player(Object playerName) {
|
String could_not_add_player(String playerName) {
|
||||||
return 'Could not add player';
|
return 'Could not add player $playerName';
|
||||||
}
|
}
|
||||||
|
|
||||||
@override
|
@override
|
||||||
@@ -92,37 +92,33 @@ class AppLocalizationsEn extends AppLocalizations {
|
|||||||
String get create_statistic => 'Create statistic';
|
String get create_statistic => 'Create statistic';
|
||||||
|
|
||||||
@override
|
@override
|
||||||
String get create_statistic_classifier_subtitle =>
|
String get which_key_metric => 'Select which key metric you want to display';
|
||||||
'Select which key metric you want to display';
|
|
||||||
|
|
||||||
@override
|
@override
|
||||||
String get create_statistic_classifier_title => 'Classifier';
|
String get classifier => 'Classifier';
|
||||||
|
|
||||||
@override
|
@override
|
||||||
String get create_statistic_games_subtitle => 'Select the filtered games';
|
String get select_the_filtered_games => 'Select the filtered games';
|
||||||
|
|
||||||
@override
|
@override
|
||||||
String get create_statistic_games_title => 'Games';
|
String get games => 'Games';
|
||||||
|
|
||||||
@override
|
@override
|
||||||
String get create_statistic_groups_subtitle => 'Select the filtered groups';
|
String get select_the_filtered_groups => 'Select the filtered groups';
|
||||||
|
|
||||||
@override
|
@override
|
||||||
String get create_statistic_groups_title => 'Groups';
|
String get select_main_filter =>
|
||||||
|
|
||||||
@override
|
|
||||||
String get create_statistic_scope_subtitle =>
|
|
||||||
'Select the main filter for your statistic. This will determine which data is used to calculate the selected classifier.';
|
'Select the main filter for your statistic. This will determine which data is used to calculate the selected classifier.';
|
||||||
|
|
||||||
@override
|
@override
|
||||||
String get create_statistic_scope_title => 'Scope';
|
String get scope => 'Scope';
|
||||||
|
|
||||||
@override
|
@override
|
||||||
String get create_statistic_timeframe_subtitle =>
|
String get select_a_timeframe_for_which_data_will_be_filtered =>
|
||||||
'Select a timeframe for which the data will be filtered. Only matches that ended within the selected timeframe will be included in the statistic.';
|
'Select a timeframe for which the data will be filtered. Only matches that ended within the selected timeframe will be included in the statistic.';
|
||||||
|
|
||||||
@override
|
@override
|
||||||
String get create_statistic_timeframe_title => 'Timeframe';
|
String get timeframe => 'Timeframe';
|
||||||
|
|
||||||
@override
|
@override
|
||||||
String get created_on => 'Created on';
|
String get created_on => 'Created on';
|
||||||
@@ -164,6 +160,9 @@ class AppLocalizationsEn extends AppLocalizations {
|
|||||||
return 'If you delete this game template, $_temp0 using this game template will also be deleted.';
|
return 'If you delete this game template, $_temp0 using this game template will also be deleted.';
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@override
|
||||||
|
String get filter => 'Filter';
|
||||||
|
|
||||||
@override
|
@override
|
||||||
String get delete_group => 'Delete Group';
|
String get delete_group => 'Delete Group';
|
||||||
|
|
||||||
@@ -367,6 +366,9 @@ class AppLocalizationsEn extends AppLocalizations {
|
|||||||
@override
|
@override
|
||||||
String get no_statistics_available => 'No statistics available';
|
String get no_statistics_available => 'No statistics available';
|
||||||
|
|
||||||
|
@override
|
||||||
|
String get no_statistics_created_yet => 'No statistics created yet';
|
||||||
|
|
||||||
@override
|
@override
|
||||||
String get none => 'None';
|
String get none => 'None';
|
||||||
|
|
||||||
|
|||||||
@@ -79,7 +79,7 @@ class _MatchViewState extends State<MatchView> {
|
|||||||
visible: matches.isNotEmpty,
|
visible: matches.isNotEmpty,
|
||||||
replacement: Center(
|
replacement: Center(
|
||||||
child: TopCenteredMessage(
|
child: TopCenteredMessage(
|
||||||
icon: Icons.report,
|
icon: Icons.info,
|
||||||
title: loc.info,
|
title: loc.info,
|
||||||
message: loc.no_matches_created_yet,
|
message: loc.no_matches_created_yet,
|
||||||
),
|
),
|
||||||
|
|||||||
@@ -68,7 +68,7 @@ class _CreateStatisticViewState extends State<CreateStatisticView> {
|
|||||||
crossAxisAlignment: CrossAxisAlignment.start,
|
crossAxisAlignment: CrossAxisAlignment.start,
|
||||||
children: [
|
children: [
|
||||||
Text(
|
Text(
|
||||||
loc.create_statistic_classifier_title,
|
loc.classifier,
|
||||||
textAlign: TextAlign.start,
|
textAlign: TextAlign.start,
|
||||||
style: const TextStyle(
|
style: const TextStyle(
|
||||||
color: CustomTheme.textColor,
|
color: CustomTheme.textColor,
|
||||||
@@ -77,7 +77,7 @@ class _CreateStatisticViewState extends State<CreateStatisticView> {
|
|||||||
),
|
),
|
||||||
),
|
),
|
||||||
Text(
|
Text(
|
||||||
loc.create_statistic_classifier_subtitle,
|
loc.select_a_classifier,
|
||||||
textAlign: TextAlign.start,
|
textAlign: TextAlign.start,
|
||||||
style: const TextStyle(
|
style: const TextStyle(
|
||||||
color: CustomTheme.textColor,
|
color: CustomTheme.textColor,
|
||||||
@@ -139,7 +139,7 @@ class _CreateStatisticViewState extends State<CreateStatisticView> {
|
|||||||
crossAxisAlignment: CrossAxisAlignment.start,
|
crossAxisAlignment: CrossAxisAlignment.start,
|
||||||
children: [
|
children: [
|
||||||
Text(
|
Text(
|
||||||
loc.create_statistic_scope_title,
|
loc.scope,
|
||||||
textAlign: TextAlign.start,
|
textAlign: TextAlign.start,
|
||||||
style: const TextStyle(
|
style: const TextStyle(
|
||||||
color: CustomTheme.textColor,
|
color: CustomTheme.textColor,
|
||||||
@@ -148,7 +148,7 @@ class _CreateStatisticViewState extends State<CreateStatisticView> {
|
|||||||
),
|
),
|
||||||
),
|
),
|
||||||
Text(
|
Text(
|
||||||
loc.create_statistic_scope_subtitle,
|
loc.select_a_scope,
|
||||||
textAlign: TextAlign.start,
|
textAlign: TextAlign.start,
|
||||||
style: const TextStyle(
|
style: const TextStyle(
|
||||||
color: CustomTheme.textColor,
|
color: CustomTheme.textColor,
|
||||||
@@ -214,7 +214,7 @@ class _CreateStatisticViewState extends State<CreateStatisticView> {
|
|||||||
crossAxisAlignment: CrossAxisAlignment.start,
|
crossAxisAlignment: CrossAxisAlignment.start,
|
||||||
children: [
|
children: [
|
||||||
Text(
|
Text(
|
||||||
loc.create_statistic_games_title,
|
loc.games,
|
||||||
textAlign: TextAlign.start,
|
textAlign: TextAlign.start,
|
||||||
style: const TextStyle(
|
style: const TextStyle(
|
||||||
color: CustomTheme.textColor,
|
color: CustomTheme.textColor,
|
||||||
@@ -223,7 +223,7 @@ class _CreateStatisticViewState extends State<CreateStatisticView> {
|
|||||||
),
|
),
|
||||||
),
|
),
|
||||||
Text(
|
Text(
|
||||||
loc.create_statistic_games_subtitle,
|
loc.select_the_filtered_games,
|
||||||
textAlign: TextAlign.start,
|
textAlign: TextAlign.start,
|
||||||
style: const TextStyle(
|
style: const TextStyle(
|
||||||
color: CustomTheme.textColor,
|
color: CustomTheme.textColor,
|
||||||
@@ -310,7 +310,7 @@ class _CreateStatisticViewState extends State<CreateStatisticView> {
|
|||||||
crossAxisAlignment: CrossAxisAlignment.start,
|
crossAxisAlignment: CrossAxisAlignment.start,
|
||||||
children: [
|
children: [
|
||||||
Text(
|
Text(
|
||||||
loc.create_statistic_groups_title,
|
loc.groups,
|
||||||
textAlign: TextAlign.start,
|
textAlign: TextAlign.start,
|
||||||
style: const TextStyle(
|
style: const TextStyle(
|
||||||
color: CustomTheme.textColor,
|
color: CustomTheme.textColor,
|
||||||
@@ -319,7 +319,7 @@ class _CreateStatisticViewState extends State<CreateStatisticView> {
|
|||||||
),
|
),
|
||||||
),
|
),
|
||||||
Text(
|
Text(
|
||||||
loc.create_statistic_groups_subtitle,
|
loc.select_the_filtered_groups,
|
||||||
textAlign: TextAlign.start,
|
textAlign: TextAlign.start,
|
||||||
style: const TextStyle(
|
style: const TextStyle(
|
||||||
color: CustomTheme.textColor,
|
color: CustomTheme.textColor,
|
||||||
@@ -396,7 +396,7 @@ class _CreateStatisticViewState extends State<CreateStatisticView> {
|
|||||||
crossAxisAlignment: CrossAxisAlignment.start,
|
crossAxisAlignment: CrossAxisAlignment.start,
|
||||||
children: [
|
children: [
|
||||||
Text(
|
Text(
|
||||||
loc.create_statistic_timeframe_title,
|
loc.timeframe,
|
||||||
textAlign: TextAlign.start,
|
textAlign: TextAlign.start,
|
||||||
style: const TextStyle(
|
style: const TextStyle(
|
||||||
color: CustomTheme.textColor,
|
color: CustomTheme.textColor,
|
||||||
@@ -405,7 +405,7 @@ class _CreateStatisticViewState extends State<CreateStatisticView> {
|
|||||||
),
|
),
|
||||||
),
|
),
|
||||||
Text(
|
Text(
|
||||||
loc.create_statistic_timeframe_subtitle,
|
loc.select_a_timeframe_for_which_data_will_be_filtered,
|
||||||
textAlign: TextAlign.start,
|
textAlign: TextAlign.start,
|
||||||
style: const TextStyle(
|
style: const TextStyle(
|
||||||
color: CustomTheme.textColor,
|
color: CustomTheme.textColor,
|
||||||
|
|||||||
@@ -0,0 +1,178 @@
|
|||||||
|
import 'package:flutter/material.dart';
|
||||||
|
import 'package:tallee/data/models/player.dart';
|
||||||
|
import 'package:tallee/data/models/statistic.dart';
|
||||||
|
import 'package:tallee/l10n/generated/app_localizations.dart';
|
||||||
|
import 'package:tallee/presentation/views/main_menu/statistics_view/create_statistic_view.dart'
|
||||||
|
show
|
||||||
|
translateScopeToString,
|
||||||
|
translateStatisticTypeToString,
|
||||||
|
translateTimeframeToString;
|
||||||
|
import 'package:tallee/presentation/widgets/buttons/haptic_icon_button.dart';
|
||||||
|
import 'package:tallee/presentation/widgets/tiles/info_tile.dart';
|
||||||
|
import 'package:tallee/presentation/widgets/tiles/statistics_tile.dart';
|
||||||
|
|
||||||
|
class StatisticDetailView extends StatefulWidget {
|
||||||
|
const StatisticDetailView({
|
||||||
|
super.key,
|
||||||
|
required this.statistic,
|
||||||
|
required this.values,
|
||||||
|
required this.icon,
|
||||||
|
required this.barColor,
|
||||||
|
});
|
||||||
|
|
||||||
|
final Statistic statistic;
|
||||||
|
final List<(Player, num)> values;
|
||||||
|
final IconData icon;
|
||||||
|
final Color barColor;
|
||||||
|
|
||||||
|
@override
|
||||||
|
State<StatisticDetailView> createState() => _StatisticDetailViewState();
|
||||||
|
}
|
||||||
|
|
||||||
|
class _StatisticDetailViewState extends State<StatisticDetailView> {
|
||||||
|
int displayCount = 0;
|
||||||
|
|
||||||
|
@override
|
||||||
|
void initState() {
|
||||||
|
super.initState();
|
||||||
|
displayCount = widget.statistic.displayCount;
|
||||||
|
}
|
||||||
|
|
||||||
|
@override
|
||||||
|
Widget build(BuildContext context) {
|
||||||
|
final loc = AppLocalizations.of(context);
|
||||||
|
final title = translateStatisticTypeToString(
|
||||||
|
widget.statistic.type,
|
||||||
|
context,
|
||||||
|
);
|
||||||
|
const style = TextStyle(fontWeight: FontWeight.bold);
|
||||||
|
|
||||||
|
return Scaffold(
|
||||||
|
appBar: AppBar(title: Text(title)),
|
||||||
|
body: SingleChildScrollView(
|
||||||
|
padding: const EdgeInsets.all(12.0),
|
||||||
|
child: Column(
|
||||||
|
children: [
|
||||||
|
StatisticsTile(
|
||||||
|
icon: widget.icon,
|
||||||
|
title: title,
|
||||||
|
width: MediaQuery.sizeOf(context).width * 0.95,
|
||||||
|
values: widget.values,
|
||||||
|
barColor: widget.barColor,
|
||||||
|
selectedGroups: widget.statistic.selectedGroups,
|
||||||
|
selectedGames: widget.statistic.selectedGames,
|
||||||
|
),
|
||||||
|
const SizedBox(height: 12),
|
||||||
|
|
||||||
|
InfoTile(
|
||||||
|
icon: Icons.filter_alt,
|
||||||
|
title: loc.filter,
|
||||||
|
content: Column(
|
||||||
|
spacing: 12,
|
||||||
|
|
||||||
|
children: [
|
||||||
|
// Scopes
|
||||||
|
Row(
|
||||||
|
crossAxisAlignment: CrossAxisAlignment.start,
|
||||||
|
mainAxisAlignment: MainAxisAlignment.spaceBetween,
|
||||||
|
children: [
|
||||||
|
Text(loc.scope, style: style),
|
||||||
|
Text(
|
||||||
|
widget.statistic.scopes
|
||||||
|
.map(
|
||||||
|
(scope) => translateScopeToString(scope, context),
|
||||||
|
)
|
||||||
|
.join('\n'),
|
||||||
|
textAlign: TextAlign.end,
|
||||||
|
),
|
||||||
|
],
|
||||||
|
),
|
||||||
|
|
||||||
|
// Timeframe
|
||||||
|
if (widget.statistic.timeframe != null)
|
||||||
|
Row(
|
||||||
|
crossAxisAlignment: CrossAxisAlignment.start,
|
||||||
|
mainAxisAlignment: MainAxisAlignment.spaceBetween,
|
||||||
|
children: [
|
||||||
|
Text(loc.timeframe, style: style),
|
||||||
|
Text(
|
||||||
|
translateTimeframeToString(
|
||||||
|
widget.statistic.timeframe!,
|
||||||
|
context,
|
||||||
|
),
|
||||||
|
textAlign: TextAlign.end,
|
||||||
|
),
|
||||||
|
],
|
||||||
|
),
|
||||||
|
|
||||||
|
// Groups
|
||||||
|
if (widget.statistic.selectedGroups != null)
|
||||||
|
Row(
|
||||||
|
crossAxisAlignment: CrossAxisAlignment.start,
|
||||||
|
mainAxisAlignment: MainAxisAlignment.spaceBetween,
|
||||||
|
children: [
|
||||||
|
Text(loc.groups, style: style),
|
||||||
|
Text(
|
||||||
|
widget.statistic.selectedGroups!
|
||||||
|
.map((group) => group.name)
|
||||||
|
.join('\n'),
|
||||||
|
textAlign: TextAlign.end,
|
||||||
|
),
|
||||||
|
],
|
||||||
|
),
|
||||||
|
|
||||||
|
// Games
|
||||||
|
if (widget.statistic.selectedGames != null)
|
||||||
|
Row(
|
||||||
|
crossAxisAlignment: CrossAxisAlignment.start,
|
||||||
|
mainAxisAlignment: MainAxisAlignment.spaceBetween,
|
||||||
|
children: [
|
||||||
|
Text(loc.games, style: style),
|
||||||
|
Text(
|
||||||
|
widget.statistic.selectedGames!
|
||||||
|
.map((game) => game.name)
|
||||||
|
.join('\n'),
|
||||||
|
textAlign: TextAlign.end,
|
||||||
|
),
|
||||||
|
],
|
||||||
|
),
|
||||||
|
|
||||||
|
if (widget.values.isNotEmpty)
|
||||||
|
Row(
|
||||||
|
mainAxisAlignment: MainAxisAlignment.spaceBetween,
|
||||||
|
children: [
|
||||||
|
const Text('Display count', style: style),
|
||||||
|
Row(
|
||||||
|
children: [
|
||||||
|
HapticIconButton(
|
||||||
|
icon: const Icon(Icons.remove),
|
||||||
|
onPressed: displayCount <= 1
|
||||||
|
? null
|
||||||
|
: () => setState(() => displayCount -= 1),
|
||||||
|
),
|
||||||
|
SizedBox(
|
||||||
|
width: 30,
|
||||||
|
child: Text(
|
||||||
|
'$displayCount',
|
||||||
|
textAlign: TextAlign.center,
|
||||||
|
),
|
||||||
|
),
|
||||||
|
HapticIconButton(
|
||||||
|
icon: const Icon(Icons.add),
|
||||||
|
onPressed: displayCount >= widget.values.length
|
||||||
|
? null
|
||||||
|
: () => setState(() => displayCount += 1),
|
||||||
|
),
|
||||||
|
],
|
||||||
|
),
|
||||||
|
],
|
||||||
|
),
|
||||||
|
],
|
||||||
|
),
|
||||||
|
),
|
||||||
|
],
|
||||||
|
),
|
||||||
|
),
|
||||||
|
);
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -3,6 +3,8 @@ import 'dart:math';
|
|||||||
import 'package:flutter/material.dart';
|
import 'package:flutter/material.dart';
|
||||||
import 'package:tallee/core/common.dart';
|
import 'package:tallee/core/common.dart';
|
||||||
import 'package:tallee/core/enums.dart';
|
import 'package:tallee/core/enums.dart';
|
||||||
|
import 'package:tallee/data/models/game.dart';
|
||||||
|
import 'package:tallee/data/models/group.dart';
|
||||||
import 'package:tallee/data/models/match.dart';
|
import 'package:tallee/data/models/match.dart';
|
||||||
import 'package:tallee/data/models/player.dart';
|
import 'package:tallee/data/models/player.dart';
|
||||||
import 'package:tallee/data/models/statistic.dart';
|
import 'package:tallee/data/models/statistic.dart';
|
||||||
@@ -14,13 +16,18 @@ List<Color> _colorPalette = AppColor.values
|
|||||||
.map((c) => getColorFromAppColor(c))
|
.map((c) => getColorFromAppColor(c))
|
||||||
.toList();
|
.toList();
|
||||||
|
|
||||||
/// Build the [StatisticsTile] for a given [Statistic].
|
/// Returns the icon for the given statistic type.
|
||||||
Widget buildStatisticTile({
|
IconData getStatisticIconForType(StatisticType type) =>
|
||||||
|
_getStatisticIcon(type: type);
|
||||||
|
|
||||||
|
/// Returns a color from the palette based on the statistic's ID.
|
||||||
|
Color getStatisticColorForStatistic(Statistic stat) => _getStatisticColor(stat);
|
||||||
|
|
||||||
|
/// Computes the statistic values for a given [Statistic].
|
||||||
|
List<(Player, num)> computeStatisticValues({
|
||||||
required Statistic statistic,
|
required Statistic statistic,
|
||||||
required List<Match> matches,
|
required List<Match> matches,
|
||||||
required List<Player> players,
|
required List<Player> players,
|
||||||
required BuildContext context,
|
|
||||||
double? width,
|
|
||||||
}) {
|
}) {
|
||||||
final filteredMatches = _getFilterMatches(statistic, matches);
|
final filteredMatches = _getFilterMatches(statistic, matches);
|
||||||
final filteredPlayers = _getFilteredPlayers(
|
final filteredPlayers = _getFilteredPlayers(
|
||||||
@@ -29,16 +36,26 @@ Widget buildStatisticTile({
|
|||||||
filteredMatches,
|
filteredMatches,
|
||||||
);
|
);
|
||||||
|
|
||||||
print('Building tile for statistic: $statistic');
|
return _computeValuesForType(
|
||||||
print('Filtered matches count: ${filteredMatches.length}');
|
|
||||||
print('Filtered players count: ${filteredPlayers.length}');
|
|
||||||
|
|
||||||
final values = _computeValuesForType(
|
|
||||||
type: statistic.type,
|
type: statistic.type,
|
||||||
matches: filteredMatches,
|
matches: filteredMatches,
|
||||||
players: filteredPlayers,
|
players: filteredPlayers,
|
||||||
);
|
);
|
||||||
print(values);
|
}
|
||||||
|
|
||||||
|
/// Build the [StatisticsTile] for a given [Statistic].
|
||||||
|
Widget buildStatisticTile({
|
||||||
|
required Statistic statistic,
|
||||||
|
required List<Match> matches,
|
||||||
|
required List<Player> players,
|
||||||
|
required BuildContext context,
|
||||||
|
double? width,
|
||||||
|
}) {
|
||||||
|
final values = computeStatisticValues(
|
||||||
|
statistic: statistic,
|
||||||
|
matches: matches,
|
||||||
|
players: players,
|
||||||
|
);
|
||||||
|
|
||||||
return StatisticsTile(
|
return StatisticsTile(
|
||||||
icon: _getStatisticIcon(type: statistic.type),
|
icon: _getStatisticIcon(type: statistic.type),
|
||||||
@@ -46,7 +63,9 @@ Widget buildStatisticTile({
|
|||||||
width: width ?? MediaQuery.sizeOf(context).width * 0.95,
|
width: width ?? MediaQuery.sizeOf(context).width * 0.95,
|
||||||
values: values,
|
values: values,
|
||||||
barColor: _getStatisticColor(statistic),
|
barColor: _getStatisticColor(statistic),
|
||||||
statistic: statistic,
|
displayCount: statistic.displayCount,
|
||||||
|
selectedGroups: statistic.selectedGroups,
|
||||||
|
selectedGames: statistic.selectedGames,
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -296,10 +315,8 @@ Widget buildSkeletonStatisticTile({required BuildContext context}) {
|
|||||||
width: MediaQuery.sizeOf(context).width * 0.95,
|
width: MediaQuery.sizeOf(context).width * 0.95,
|
||||||
values: values,
|
values: values,
|
||||||
barColor: _colorPalette[Random().nextInt(_colorPalette.length)],
|
barColor: _colorPalette[Random().nextInt(_colorPalette.length)],
|
||||||
statistic: Statistic(
|
selectedGames: [Game(name: 'Game 1', ruleset: Ruleset.highestScore)],
|
||||||
type: StatisticType.totalMatches,
|
selectedGroups: [Group(name: 'Group 1', members: [])],
|
||||||
scopes: [StatisticScope.allPlayers],
|
displayCount: 5,
|
||||||
timeframe: Timeframe.last7Days,
|
|
||||||
),
|
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -8,9 +8,11 @@ import 'package:tallee/data/models/player.dart';
|
|||||||
import 'package:tallee/data/models/statistic.dart';
|
import 'package:tallee/data/models/statistic.dart';
|
||||||
import 'package:tallee/l10n/generated/app_localizations.dart';
|
import 'package:tallee/l10n/generated/app_localizations.dart';
|
||||||
import 'package:tallee/presentation/views/main_menu/statistics_view/create_statistic_view.dart';
|
import 'package:tallee/presentation/views/main_menu/statistics_view/create_statistic_view.dart';
|
||||||
|
import 'package:tallee/presentation/views/main_menu/statistics_view/statistic_detail_view.dart';
|
||||||
import 'package:tallee/presentation/views/main_menu/statistics_view/statistic_tile_factory.dart';
|
import 'package:tallee/presentation/views/main_menu/statistics_view/statistic_tile_factory.dart';
|
||||||
import 'package:tallee/presentation/widgets/app_skeleton.dart';
|
import 'package:tallee/presentation/widgets/app_skeleton.dart';
|
||||||
import 'package:tallee/presentation/widgets/buttons/main_menu_button.dart';
|
import 'package:tallee/presentation/widgets/buttons/main_menu_button.dart';
|
||||||
|
import 'package:tallee/presentation/widgets/top_centered_message.dart';
|
||||||
|
|
||||||
class StatisticsView extends StatefulWidget {
|
class StatisticsView extends StatefulWidget {
|
||||||
/// A view that displays player statistics
|
/// A view that displays player statistics
|
||||||
@@ -45,18 +47,30 @@ class _StatisticsViewState extends State<StatisticsView> {
|
|||||||
alignment: AlignmentDirectional.bottomCenter,
|
alignment: AlignmentDirectional.bottomCenter,
|
||||||
fit: StackFit.expand,
|
fit: StackFit.expand,
|
||||||
children: [
|
children: [
|
||||||
SingleChildScrollView(
|
Visibility(
|
||||||
child: AppSkeleton(
|
visible: statisticTiles.isNotEmpty,
|
||||||
enabled: isLoading,
|
replacement: Center(
|
||||||
fixLayoutBuilder: true,
|
child: TopCenteredMessage(
|
||||||
child: Column(
|
icon: Icons.info,
|
||||||
spacing: 12,
|
title: loc.info,
|
||||||
mainAxisAlignment: MainAxisAlignment.start,
|
message: loc.no_statistics_created_yet,
|
||||||
crossAxisAlignment: CrossAxisAlignment.center,
|
),
|
||||||
children: [
|
),
|
||||||
...statisticTiles,
|
child: SingleChildScrollView(
|
||||||
SizedBox(height: MediaQuery.paddingOf(context).bottom + 80),
|
child: AppSkeleton(
|
||||||
],
|
enabled: isLoading,
|
||||||
|
fixLayoutBuilder: true,
|
||||||
|
child: Column(
|
||||||
|
spacing: 12,
|
||||||
|
mainAxisAlignment: MainAxisAlignment.start,
|
||||||
|
crossAxisAlignment: CrossAxisAlignment.center,
|
||||||
|
children: [
|
||||||
|
...statisticTiles,
|
||||||
|
SizedBox(
|
||||||
|
height: MediaQuery.paddingOf(context).bottom + 80,
|
||||||
|
),
|
||||||
|
],
|
||||||
|
),
|
||||||
),
|
),
|
||||||
),
|
),
|
||||||
),
|
),
|
||||||
@@ -75,12 +89,7 @@ class _StatisticsViewState extends State<StatisticsView> {
|
|||||||
),
|
),
|
||||||
);
|
);
|
||||||
if (!context.mounted) return;
|
if (!context.mounted) return;
|
||||||
final newTile = buildStatisticTile(
|
final newTile = _buildStatisticTile(context, newStatistic);
|
||||||
statistic: newStatistic,
|
|
||||||
matches: _allMatches,
|
|
||||||
players: _allPlayers,
|
|
||||||
context: context,
|
|
||||||
);
|
|
||||||
|
|
||||||
setState(() {
|
setState(() {
|
||||||
statisticTiles.add(newTile);
|
statisticTiles.add(newTile);
|
||||||
@@ -126,15 +135,40 @@ class _StatisticsViewState extends State<StatisticsView> {
|
|||||||
setState(() {
|
setState(() {
|
||||||
statisticTiles = [
|
statisticTiles = [
|
||||||
for (final statistic in statistics) ...[
|
for (final statistic in statistics) ...[
|
||||||
buildStatisticTile(
|
_buildStatisticTile(context, statistic),
|
||||||
statistic: statistic,
|
|
||||||
matches: _allMatches,
|
|
||||||
players: _allPlayers,
|
|
||||||
context: context,
|
|
||||||
),
|
|
||||||
],
|
],
|
||||||
];
|
];
|
||||||
isLoading = false;
|
isLoading = false;
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
|
Widget _buildStatisticTile(BuildContext context, Statistic statistic) {
|
||||||
|
return GestureDetector(
|
||||||
|
onTap: () {
|
||||||
|
final values = computeStatisticValues(
|
||||||
|
statistic: statistic,
|
||||||
|
matches: _allMatches,
|
||||||
|
players: _allPlayers,
|
||||||
|
);
|
||||||
|
|
||||||
|
Navigator.push(
|
||||||
|
context,
|
||||||
|
adaptivePageRoute(
|
||||||
|
builder: (context) => StatisticDetailView(
|
||||||
|
statistic: statistic,
|
||||||
|
values: values,
|
||||||
|
icon: getStatisticIconForType(statistic.type),
|
||||||
|
barColor: getStatisticColorForStatistic(statistic),
|
||||||
|
),
|
||||||
|
),
|
||||||
|
);
|
||||||
|
},
|
||||||
|
child: buildStatisticTile(
|
||||||
|
statistic: statistic,
|
||||||
|
matches: _allMatches,
|
||||||
|
players: _allPlayers,
|
||||||
|
context: context,
|
||||||
|
),
|
||||||
|
);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -8,7 +8,6 @@ import 'package:tallee/core/enums.dart';
|
|||||||
import 'package:tallee/data/models/game.dart';
|
import 'package:tallee/data/models/game.dart';
|
||||||
import 'package:tallee/data/models/group.dart';
|
import 'package:tallee/data/models/group.dart';
|
||||||
import 'package:tallee/data/models/player.dart';
|
import 'package:tallee/data/models/player.dart';
|
||||||
import 'package:tallee/data/models/statistic.dart';
|
|
||||||
import 'package:tallee/l10n/generated/app_localizations.dart';
|
import 'package:tallee/l10n/generated/app_localizations.dart';
|
||||||
import 'package:tallee/presentation/widgets/tiles/info_tile.dart';
|
import 'package:tallee/presentation/widgets/tiles/info_tile.dart';
|
||||||
|
|
||||||
@@ -27,7 +26,9 @@ class StatisticsTile extends StatelessWidget {
|
|||||||
required this.width,
|
required this.width,
|
||||||
required this.values,
|
required this.values,
|
||||||
required this.barColor,
|
required this.barColor,
|
||||||
required this.statistic,
|
this.displayCount,
|
||||||
|
this.selectedGroups,
|
||||||
|
this.selectedGames,
|
||||||
});
|
});
|
||||||
|
|
||||||
/// The icon displayed next to the title.
|
/// The icon displayed next to the title.
|
||||||
@@ -45,7 +46,10 @@ class StatisticsTile extends StatelessWidget {
|
|||||||
/// The color of the bars representing the values.
|
/// The color of the bars representing the values.
|
||||||
final Color barColor;
|
final Color barColor;
|
||||||
|
|
||||||
final Statistic statistic;
|
final int? displayCount;
|
||||||
|
|
||||||
|
final List<Group>? selectedGroups;
|
||||||
|
final List<Game>? selectedGames;
|
||||||
|
|
||||||
@override
|
@override
|
||||||
Widget build(BuildContext context) {
|
Widget build(BuildContext context) {
|
||||||
@@ -70,8 +74,12 @@ class StatisticsTile extends StatelessWidget {
|
|||||||
child: LayoutBuilder(
|
child: LayoutBuilder(
|
||||||
builder: (context, constraints) {
|
builder: (context, constraints) {
|
||||||
final maxBarWidth = constraints.maxWidth * 0.8;
|
final maxBarWidth = constraints.maxWidth * 0.8;
|
||||||
final displayCount = min(values.length, statistic.displayCount);
|
|
||||||
final displayValues = values.take(displayCount).toList();
|
// If displayCount wasnt provided, take all values
|
||||||
|
final valuesShown = displayCount == null
|
||||||
|
? values.length
|
||||||
|
: min(values.length, displayCount!);
|
||||||
|
final displayValues = values.take(valuesShown).toList();
|
||||||
final maxVal = displayValues.isNotEmpty
|
final maxVal = displayValues.isNotEmpty
|
||||||
? displayValues.fold<num>(
|
? displayValues.fold<num>(
|
||||||
0,
|
0,
|
||||||
@@ -83,7 +91,7 @@ class StatisticsTile extends StatelessWidget {
|
|||||||
return Column(
|
return Column(
|
||||||
children: [
|
children: [
|
||||||
// Bars
|
// Bars
|
||||||
...List.generate(displayCount, (index) {
|
...List.generate(valuesShown, (index) {
|
||||||
/// Fraction of wins
|
/// Fraction of wins
|
||||||
final double fraction = (maxVal > 0)
|
final double fraction = (maxVal > 0)
|
||||||
? (displayValues[index].$2 / maxVal)
|
? (displayValues[index].$2 / maxVal)
|
||||||
@@ -187,12 +195,14 @@ class StatisticsTile extends StatelessWidget {
|
|||||||
}),
|
}),
|
||||||
|
|
||||||
// Group & Game info
|
// Group & Game info
|
||||||
if (statistic.selectedGames != null ||
|
if (hasGame || hasGroup)
|
||||||
statistic.selectedGroups != null)
|
|
||||||
Padding(
|
Padding(
|
||||||
padding: const EdgeInsets.only(top: 8.0),
|
padding: const EdgeInsets.only(top: 8.0),
|
||||||
child: Row(
|
child: Wrap(
|
||||||
mainAxisAlignment: MainAxisAlignment.start,
|
alignment: WrapAlignment.start,
|
||||||
|
crossAxisAlignment: WrapCrossAlignment.center,
|
||||||
|
spacing: 4,
|
||||||
|
runSpacing: 4,
|
||||||
children: [
|
children: [
|
||||||
// Game
|
// Game
|
||||||
if (hasGroup)
|
if (hasGroup)
|
||||||
@@ -205,7 +215,7 @@ class StatisticsTile extends StatelessWidget {
|
|||||||
size: 20,
|
size: 20,
|
||||||
),
|
),
|
||||||
Text(
|
Text(
|
||||||
getGameText(statistic.selectedGames!),
|
getGameText(selectedGames!),
|
||||||
style: const TextStyle(
|
style: const TextStyle(
|
||||||
fontSize: 14,
|
fontSize: 14,
|
||||||
fontWeight: FontWeight.bold,
|
fontWeight: FontWeight.bold,
|
||||||
@@ -227,7 +237,7 @@ class StatisticsTile extends StatelessWidget {
|
|||||||
color: CustomTheme.hintColor,
|
color: CustomTheme.hintColor,
|
||||||
),
|
),
|
||||||
Text(
|
Text(
|
||||||
getGroupText(statistic.selectedGroups!),
|
getGroupText(selectedGroups!),
|
||||||
style: const TextStyle(
|
style: const TextStyle(
|
||||||
fontSize: 14,
|
fontSize: 14,
|
||||||
fontWeight: FontWeight.bold,
|
fontWeight: FontWeight.bold,
|
||||||
@@ -265,9 +275,7 @@ class StatisticsTile extends StatelessWidget {
|
|||||||
return text;
|
return text;
|
||||||
}
|
}
|
||||||
|
|
||||||
bool get hasGroup =>
|
bool get hasGroup => selectedGroups != null && selectedGroups!.isNotEmpty;
|
||||||
statistic.selectedGroups != null && statistic.selectedGroups!.isNotEmpty;
|
|
||||||
|
|
||||||
bool get hasGame =>
|
bool get hasGame => selectedGames != null && selectedGames!.isNotEmpty;
|
||||||
statistic.selectedGames != null && statistic.selectedGames!.isNotEmpty;
|
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,7 +1,7 @@
|
|||||||
name: tallee
|
name: tallee
|
||||||
description: "Tracking App for Card Games"
|
description: "Tracking App for Card Games"
|
||||||
publish_to: 'none'
|
publish_to: 'none'
|
||||||
version: 0.0.33+276
|
version: 0.0.33+280
|
||||||
|
|
||||||
environment:
|
environment:
|
||||||
sdk: ^3.8.1
|
sdk: ^3.8.1
|
||||||
|
|||||||
Reference in New Issue
Block a user