Added nameCount to statistic tiles
All checks were successful
Pull Request Pipeline / test (pull_request) Successful in 43s
Pull Request Pipeline / lint (pull_request) Successful in 50s

This commit is contained in:
2026-04-20 16:39:33 +02:00
parent 9a0386f22d
commit 4e97f6723a
2 changed files with 82 additions and 59 deletions

View File

@@ -18,9 +18,18 @@ class StatisticsView extends StatefulWidget {
} }
class _StatisticsViewState extends State<StatisticsView> { class _StatisticsViewState extends State<StatisticsView> {
List<(String, int)> winCounts = List.filled(6, ('Skeleton Player', 1)); List<(Player, int)> winCounts = List.filled(6, (
List<(String, int)> matchCounts = List.filled(6, ('Skeleton Player', 1)); Player(name: 'Skeleton Player'),
List<(String, double)> winRates = List.filled(6, ('Skeleton Player', 1)); 1,
));
List<(Player, int)> matchCounts = List.filled(6, (
Player(name: 'Skeleton Player'),
1,
));
List<(Player, double)> winRates = List.filled(6, (
Player(name: 'Skeleton Player'),
1,
));
bool isLoading = true; bool isLoading = true;
@override @override
@@ -121,7 +130,10 @@ class _StatisticsViewState extends State<StatisticsView> {
players: players, players: players,
context: context, context: context,
); );
winRates = computeWinRatePercent(wins: winCounts, matches: matchCounts); winRates = computeWinRatePercent(
winCounts: winCounts,
matchCounts: matchCounts,
);
setState(() { setState(() {
isLoading = false; isLoading = false;
}); });
@@ -130,47 +142,47 @@ class _StatisticsViewState extends State<StatisticsView> {
/// Calculates the number of wins for each player /// Calculates the number of wins for each player
/// and returns a sorted list of tuples (playerName, winCount) /// and returns a sorted list of tuples (playerName, winCount)
List<(String, int)> _calculateWinsForAllPlayers({ List<(Player, int)> _calculateWinsForAllPlayers({
required List<Match> matches, required List<Match> matches,
required List<Player> players, required List<Player> players,
required BuildContext context, required BuildContext context,
}) { }) {
List<(String, int)> winCounts = []; List<(Player, int)> winCounts = [];
final loc = AppLocalizations.of(context); final loc = AppLocalizations.of(context);
// Getting the winners // Getting the winners
for (var match in matches) { for (var match in matches) {
final winner = match.winner; final winner = match.winner;
if (winner != null) { if (winner != null) {
final index = winCounts.indexWhere((entry) => entry.$1 == winner.id); final index = winCounts.indexWhere((entry) => entry.$1.id == winner.id);
// -1 means winner not found in winCounts // -1 means winner not found in winCounts
if (index != -1) { if (index != -1) {
final current = winCounts[index].$2; final current = winCounts[index].$2;
winCounts[index] = (winner.id, current + 1); winCounts[index] = (winner, current + 1);
} else { } else {
winCounts.add((winner.id, 1)); winCounts.add((winner, 1));
} }
} }
} }
// Adding all players with zero wins // Adding all players with zero wins
for (var player in players) { for (var player in players) {
final index = winCounts.indexWhere((entry) => entry.$1 == player.id); final index = winCounts.indexWhere((entry) => entry.$1.id == player.id);
// -1 means player not found in winCounts // -1 means player not found in winCounts
if (index == -1) { if (index == -1) {
winCounts.add((player.id, 0)); winCounts.add((player, 0));
} }
} }
// Replace player IDs with names // Replace player IDs with names
for (int i = 0; i < winCounts.length; i++) { for (int i = 0; i < winCounts.length; i++) {
final playerId = winCounts[i].$1; final playerId = winCounts[i].$1.id;
final player = players.firstWhere( final player = players.firstWhere(
(p) => p.id == playerId, (p) => p.id == playerId,
orElse: () => orElse: () =>
Player(id: playerId, name: loc.not_available, description: ''), Player(id: playerId, name: loc.not_available, description: ''),
); );
winCounts[i] = (player.name, winCounts[i].$2); winCounts[i] = (player, winCounts[i].$2);
} }
winCounts.sort((a, b) => b.$2.compareTo(a.$2)); winCounts.sort((a, b) => b.$2.compareTo(a.$2));
@@ -180,60 +192,51 @@ class _StatisticsViewState extends State<StatisticsView> {
/// Calculates the number of matches played for each player /// Calculates the number of matches played for each player
/// and returns a sorted list of tuples (playerName, matchCount) /// and returns a sorted list of tuples (playerName, matchCount)
List<(String, int)> _calculateMatchAmountsForAllPlayers({ List<(Player, int)> _calculateMatchAmountsForAllPlayers({
required List<Match> matches, required List<Match> matches,
required List<Player> players, required List<Player> players,
required BuildContext context, required BuildContext context,
}) { }) {
List<(String, int)> matchCounts = []; List<(Player, int)> matchCounts = [];
final loc = AppLocalizations.of(context); final loc = AppLocalizations.of(context);
// Counting matches for each player // Counting matches for each player
for (var match in matches) { for (var match in matches) {
if (match.group != null) { for (Player player in match.players) {
final members = match.group!.members.map((p) => p.id).toList(); // Check if the player is already in matchCounts
for (var playerId in members) { final index = matchCounts.indexWhere(
final index = matchCounts.indexWhere((entry) => entry.$1 == playerId); (entry) => entry.$1.id == player.id,
// -1 means player not found in matchCounts );
if (index != -1) {
final current = matchCounts[index].$2; // -1 -> not found
matchCounts[index] = (playerId, current + 1); if (index == -1) {
} else { // Add new entry
matchCounts.add((playerId, 1)); matchCounts.add((player, 1));
}
}
}
final members = match.players.map((p) => p.id).toList();
for (var playerId in members) {
final index = matchCounts.indexWhere((entry) => entry.$1 == playerId);
// -1 means player not found in matchCounts
if (index != -1) {
final current = matchCounts[index].$2;
matchCounts[index] = (playerId, current + 1);
} else { } else {
matchCounts.add((playerId, 1)); // Update existing entry
final currentMatchAmount = matchCounts[index].$2;
matchCounts[index] = (player, currentMatchAmount + 1);
} }
} }
} }
// Adding all players with zero matches // Adding all players with zero matches
for (var player in players) { for (var player in players) {
final index = matchCounts.indexWhere((entry) => entry.$1 == player.id); final index = matchCounts.indexWhere((entry) => entry.$1.id == player.id);
// -1 means player not found in matchCounts // -1 means player not found in matchCounts
if (index == -1) { if (index == -1) {
matchCounts.add((player.id, 0)); matchCounts.add((player, 0));
} }
} }
// Replace player IDs with names // Replace player IDs with names
for (int i = 0; i < matchCounts.length; i++) { for (int i = 0; i < matchCounts.length; i++) {
final playerId = matchCounts[i].$1; final playerId = matchCounts[i].$1.id;
final player = players.firstWhere( final player = players.firstWhere(
(p) => p.id == playerId, (p) => p.id == playerId,
orElse: () => orElse: () => Player(id: playerId, name: loc.not_available),
Player(id: playerId, name: loc.not_available, description: ''),
); );
matchCounts[i] = (player.name, matchCounts[i].$2); matchCounts[i] = (player, matchCounts[i].$2);
} }
matchCounts.sort((a, b) => b.$2.compareTo(a.$2)); matchCounts.sort((a, b) => b.$2.compareTo(a.$2));
@@ -241,25 +244,24 @@ class _StatisticsViewState extends State<StatisticsView> {
return matchCounts; return matchCounts;
} }
// dart List<(Player, double)> computeWinRatePercent({
List<(String, double)> computeWinRatePercent({ required List<(Player, int)> winCounts,
required List<(String, int)> wins, required List<(Player, int)> matchCounts,
required List<(String, int)> matches,
}) { }) {
final Map<String, int> winsMap = {for (var e in wins) e.$1: e.$2}; final Map<Player, int> winsMap = {for (var e in winCounts) e.$1: e.$2};
final Map<String, int> matchesMap = {for (var e in matches) e.$1: e.$2}; final Map<Player, int> matchesMap = {for (var e in matchCounts) e.$1: e.$2};
// Get all unique player names // Get all unique player names
final names = {...winsMap.keys, ...matchesMap.keys}; final player = {...matchesMap.keys};
// Calculate win rates // Calculate win rates
final result = names.map((name) { final result = player.map((name) {
final int w = winsMap[name] ?? 0; final int w = winsMap[name] ?? 0;
final int g = matchesMap[name] ?? 0; final int m = matchesMap[name] ?? 0;
// Calculate percentage and round to 2 decimal places // Calculate percentage and round to 2 decimal places
// Avoid division by zero // Avoid division by zero
final double percent = (g > 0) final double percent = (m > 0)
? double.parse(((w / g)).toStringAsFixed(2)) ? double.parse(((w / m)).toStringAsFixed(2))
: 0; : 0;
return (name, percent); return (name, percent);
}).toList(); }).toList();

View File

@@ -1,6 +1,9 @@
import 'dart:math'; import 'dart:math';
import 'package:flutter/material.dart'; import 'package:flutter/material.dart';
import 'package:tallee/core/common.dart';
import 'package:tallee/core/custom_theme.dart';
import 'package:tallee/data/models/player.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';
@@ -32,7 +35,7 @@ class StatisticsTile extends StatelessWidget {
final double width; final double width;
/// A list of tuples containing labels and their corresponding numeric values. /// A list of tuples containing labels and their corresponding numeric values.
final List<(String, num)> values; final List<(Player, num)> values;
/// The maximum number of items to display. /// The maximum number of items to display.
final int itemCount; final int itemCount;
@@ -89,11 +92,29 @@ class StatisticsTile extends StatelessWidget {
), ),
Padding( Padding(
padding: const EdgeInsets.only(left: 4.0), padding: const EdgeInsets.only(left: 4.0),
child: Text( child: RichText(
values[index].$1, overflow: TextOverflow.ellipsis,
style: const TextStyle( text: TextSpan(
fontSize: 16, style: DefaultTextStyle.of(context).style,
fontWeight: FontWeight.bold, children: [
TextSpan(
text: values[index].$1.name,
style: const TextStyle(
fontSize: 16,
fontWeight: FontWeight.bold,
),
),
TextSpan(
text: getNameCountText(values[index].$1),
style: TextStyle(
fontSize: 14,
fontWeight: FontWeight.bold,
color: CustomTheme.textColor.withAlpha(
150,
),
),
),
],
), ),
), ),
), ),