diff --git a/lib/presentation/views/main_menu/statistics_view.dart b/lib/presentation/views/main_menu/statistics_view.dart index fc7b262..2a8dedf 100644 --- a/lib/presentation/views/main_menu/statistics_view.dart +++ b/lib/presentation/views/main_menu/statistics_view.dart @@ -16,9 +16,9 @@ class StatisticsView extends StatefulWidget { class _StatisticsViewState extends State { late Future> _gamesFuture; late Future> _playersFuture; - List<(String, int)> winCounts = List.filled(6, ('Skeleton Player', 5)); - List<(String, int)> gameCounts = List.filled(6, ('Skeleton Player', 5)); - + List<(String, int)> winCounts = List.filled(6, ('Skeleton Player', 1)); + List<(String, int)> gameCounts = List.filled(6, ('Skeleton Player', 1)); + List<(String, double)> winRates = List.filled(6, ('Skeleton Player', 1)); bool isLoading = true; @override @@ -29,11 +29,12 @@ class _StatisticsViewState extends State { _playersFuture = db.playerDao.getAllPlayers(); Future.wait([_gamesFuture, _playersFuture]).then((results) async { - await Future.delayed(const Duration(milliseconds: 500)); + await Future.delayed(const Duration(milliseconds: 200)); final games = results[0] as List; final players = results[1] as List; winCounts = _calculateWinsForAllPlayers(games, players); gameCounts = _calculateGameAmountsForAllPlayers(games, players); + winRates = computeWinRatePercent(wins: winCounts, games: gameCounts); if (mounted) { setState(() { isLoading = false; @@ -46,22 +47,31 @@ class _StatisticsViewState extends State { Widget build(BuildContext context) { return LayoutBuilder( builder: (BuildContext context, BoxConstraints constraints) { - return Skeletonizer( - effect: PulseEffect( - from: Colors.grey[800]!, - to: Colors.grey[600]!, - duration: const Duration(milliseconds: 800), - ), - enabled: isLoading, - enableSwitchAnimation: true, - switchAnimationConfig: const SwitchAnimationConfig( - duration: Duration(milliseconds: 200), - switchInCurve: Curves.linear, - switchOutCurve: Curves.linear, - transitionBuilder: AnimatedSwitcher.defaultTransitionBuilder, - layoutBuilder: AnimatedSwitcher.defaultLayoutBuilder, - ), - child: SingleChildScrollView( + return SingleChildScrollView( + child: Skeletonizer( + effect: PulseEffect( + from: Colors.grey[800]!, + to: Colors.grey[600]!, + duration: const Duration(milliseconds: 800), + ), + enabled: isLoading, + enableSwitchAnimation: true, + switchAnimationConfig: SwitchAnimationConfig( + duration: const Duration(milliseconds: 1000), + switchInCurve: Curves.linear, + switchOutCurve: Curves.linear, + transitionBuilder: AnimatedSwitcher.defaultTransitionBuilder, + layoutBuilder: + (Widget? currentChild, List previousChildren) { + return Stack( + alignment: Alignment.topCenter, + children: [ + ...previousChildren, + if (currentChild != null) currentChild, + ], + ); + }, + ), child: ConstrainedBox( constraints: BoxConstraints(minWidth: constraints.maxWidth), child: Column( @@ -78,6 +88,15 @@ class _StatisticsViewState extends State { barColor: Colors.blue, ), SizedBox(height: constraints.maxHeight * 0.02), + StatisticsTile( + icon: Icons.casino, + title: 'Winrate per Player', + width: constraints.maxWidth * 0.95, + values: winRates, + itemCount: 6, + barColor: Colors.orange[700]!, + ), + SizedBox(height: constraints.maxHeight * 0.02), StatisticsTile( icon: Icons.casino, title: 'Games per Player', @@ -86,6 +105,7 @@ class _StatisticsViewState extends State { itemCount: 6, barColor: Colors.green, ), + SizedBox(height: MediaQuery.paddingOf(context).bottom), ], ), @@ -200,4 +220,36 @@ class _StatisticsViewState extends State { return gameCounts; } + + // dart + List<(String, double)> computeWinRatePercent({ + required List<(String, int)> wins, // [(name, wins)] + required List<(String, int)> games, // [(name, games)] + }) { + final Map winsMap = {for (var e in wins) e.$1: e.$2}; + final Map gamesMap = {for (var e in games) e.$1: e.$2}; + + final names = {...winsMap.keys, ...gamesMap.keys}; + + final result = names.map((name) { + final int w = winsMap[name] ?? 0; + final int g = gamesMap[name] ?? 0; + final double percent = (g > 0) + ? double.parse(((w / g)).toStringAsFixed(2)) + : 0; + return (name, percent); + }).toList(); + + // Sort the result: first by winrate descending, + // then by wins descending in case of a tie + result.sort((a, b) { + final cmp = b.$2.compareTo(a.$2); + if (cmp != 0) return cmp; + final wa = winsMap[a.$1] ?? 0; + final wb = winsMap[b.$1] ?? 0; + return wb.compareTo(wa); + }); + + return result; + } }