Smooth graph + unfinished reimplementation of tl progress bar

Also small UI changes
This commit is contained in:
dan63047 2024-04-21 01:37:31 +03:00
parent 3b16822c1f
commit 5c6c502a57
12 changed files with 768 additions and 554 deletions

View File

@ -17,6 +17,9 @@ const double appdspWeight = 140;
const double vsapmWeight = 60; const double vsapmWeight = 60;
const double cheeseWeight = 1.25; const double cheeseWeight = 1.25;
const double gbeWeight = 315; const double gbeWeight = 315;
const List<String> ranks = [
"d", "d+", "c-", "c", "c+", "b-", "b", "b+", "a-", "a", "a+", "s-", "s", "s+", "ss", "u", "x"
];
const Map<String, double> rankCutoffs = { const Map<String, double> rankCutoffs = {
"x": 0.01, "x": 0.01,
"u": 0.05, "u": 0.05,

View File

@ -4,9 +4,9 @@
/// To regenerate, run: `dart run slang` /// To regenerate, run: `dart run slang`
/// ///
/// Locales: 2 /// Locales: 2
/// Strings: 1120 (560 per locale) /// Strings: 1122 (561 per locale)
/// ///
/// Built on 2024-03-24 at 14:28 UTC /// Built on 2024-04-11 at 22:23 UTC
// coverage:ignore-file // coverage:ignore-file
// ignore_for_file: type=lint // ignore_for_file: type=lint
@ -216,6 +216,7 @@ class Translations implements BaseTranslations<AppLocale, Translations> {
String verdictGeneral({required Object n, required Object verdict, required Object rank}) => '${n} ${verdict} than ${rank} rank average'; String verdictGeneral({required Object n, required Object verdict, required Object rank}) => '${n} ${verdict} than ${rank} rank average';
String get verdictBetter => 'better'; String get verdictBetter => 'better';
String get verdictWorse => 'worse'; String get verdictWorse => 'worse';
String get smooth => 'Smooth';
String gamesUntilRanked({required Object left}) => '${left} games until being ranked'; String gamesUntilRanked({required Object left}) => '${left} games until being ranked';
String get nerdStats => 'Nerd Stats'; String get nerdStats => 'Nerd Stats';
String get playersYouTrack => 'Players you track'; String get playersYouTrack => 'Players you track';
@ -870,6 +871,7 @@ class _StringsRu implements Translations {
@override String verdictGeneral({required Object verdict, required Object rank, required Object n}) => '${verdict} среднего ${rank} ранга на ${n}'; @override String verdictGeneral({required Object verdict, required Object rank, required Object n}) => '${verdict} среднего ${rank} ранга на ${n}';
@override String get verdictBetter => 'Лучше'; @override String get verdictBetter => 'Лучше';
@override String get verdictWorse => 'Хуже'; @override String get verdictWorse => 'Хуже';
@override String get smooth => 'Гладкий';
@override String gamesUntilRanked({required Object left}) => '${left} матчей до получения рейтинга'; @override String gamesUntilRanked({required Object left}) => '${left} матчей до получения рейтинга';
@override String get nerdStats => 'Для задротов'; @override String get nerdStats => 'Для задротов';
@override String get playersYouTrack => 'Отслеживаемые игроки'; @override String get playersYouTrack => 'Отслеживаемые игроки';
@ -1516,6 +1518,7 @@ extension on Translations {
case 'verdictGeneral': return ({required Object n, required Object verdict, required Object rank}) => '${n} ${verdict} than ${rank} rank average'; case 'verdictGeneral': return ({required Object n, required Object verdict, required Object rank}) => '${n} ${verdict} than ${rank} rank average';
case 'verdictBetter': return 'better'; case 'verdictBetter': return 'better';
case 'verdictWorse': return 'worse'; case 'verdictWorse': return 'worse';
case 'smooth': return 'Smooth';
case 'gamesUntilRanked': return ({required Object left}) => '${left} games until being ranked'; case 'gamesUntilRanked': return ({required Object left}) => '${left} games until being ranked';
case 'nerdStats': return 'Nerd Stats'; case 'nerdStats': return 'Nerd Stats';
case 'playersYouTrack': return 'Players you track'; case 'playersYouTrack': return 'Players you track';
@ -2096,6 +2099,7 @@ extension on _StringsRu {
case 'verdictGeneral': return ({required Object verdict, required Object rank, required Object n}) => '${verdict} среднего ${rank} ранга на ${n}'; case 'verdictGeneral': return ({required Object verdict, required Object rank, required Object n}) => '${verdict} среднего ${rank} ранга на ${n}';
case 'verdictBetter': return 'Лучше'; case 'verdictBetter': return 'Лучше';
case 'verdictWorse': return 'Хуже'; case 'verdictWorse': return 'Хуже';
case 'smooth': return 'Гладкий';
case 'gamesUntilRanked': return ({required Object left}) => '${left} матчей до получения рейтинга'; case 'gamesUntilRanked': return ({required Object left}) => '${left} матчей до получения рейтинга';
case 'nerdStats': return 'Для задротов'; case 'nerdStats': return 'Для задротов';
case 'playersYouTrack': return 'Отслеживаемые игроки'; case 'playersYouTrack': return 'Отслеживаемые игроки';

View File

@ -816,21 +816,23 @@ class CompareThingy extends StatelessWidget {
child: Container( child: Container(
padding: const EdgeInsets.all(4), padding: const EdgeInsets.all(4),
decoration: BoxDecoration( decoration: BoxDecoration(
gradient: LinearGradient( gradient: LinearGradient(
colors: const [Colors.green, Colors.transparent], colors: const [Colors.green, Colors.transparent],
begin: Alignment.centerLeft, begin: Alignment.centerLeft,
end: Alignment.centerRight, end: Alignment.centerRight,
stops: [ transform: GradientRotation(0.6),
0.0, stops: [
higherIsBetter 0.0,
? greenSide > redSide higherIsBetter
? 0.6 ? greenSide > redSide
: 0 ? 0.6
: greenSide < redSide : 0
? 0.6 : greenSide < redSide
: 0 ? 0.6
], : 0
)), ],
)
),
child: Text( child: Text(
(prefix ?? "") + f.format(greenSide) + (postfix ?? ""), (prefix ?? "") + f.format(greenSide) + (postfix ?? ""),
style: const TextStyle( style: const TextStyle(
@ -838,7 +840,12 @@ class CompareThingy extends StatelessWidget {
shadows: <Shadow>[ shadows: <Shadow>[
Shadow( Shadow(
offset: Offset(0.0, 0.0), offset: Offset(0.0, 0.0),
blurRadius: 3.0, blurRadius: 1.0,
color: Colors.black,
),
Shadow(
offset: Offset(0.0, 0.0),
blurRadius: 2.0,
color: Colors.black, color: Colors.black,
), ),
Shadow( Shadow(
@ -874,6 +881,7 @@ class CompareThingy extends StatelessWidget {
colors: const [Colors.red, Colors.transparent], colors: const [Colors.red, Colors.transparent],
begin: Alignment.centerRight, begin: Alignment.centerRight,
end: Alignment.centerLeft, end: Alignment.centerLeft,
transform: GradientRotation(-0.6),
stops: [ stops: [
0.0, 0.0,
higherIsBetter higherIsBetter

View File

@ -1,5 +1,6 @@
// ignore_for_file: type_literal_in_constant_pattern // ignore_for_file: type_literal_in_constant_pattern
import 'dart:ffi';
import 'dart:io'; import 'dart:io';
import 'package:flutter/foundation.dart'; import 'package:flutter/foundation.dart';
import 'package:flutter/gestures.dart'; import 'package:flutter/gestures.dart';
@ -35,6 +36,7 @@ import 'package:go_router/go_router.dart';
final TetrioService teto = TetrioService(); // thing, that manadge our local DB final TetrioService teto = TetrioService(); // thing, that manadge our local DB
int _chartsIndex = 0; int _chartsIndex = 0;
bool _gamesPlayedInsteadOfDateAndTime = false; bool _gamesPlayedInsteadOfDateAndTime = false;
bool _smooth = false;
List _historyShortTitles = ["TR", "Glicko", "RD", "APM", "PPS", "VS", "APP", "DS/S", "DS/P", "APP + DS/P", "VS/APM", "Cheese", "GbE", "wAPP", "Area", "eTR", "±eTR", "Opener", "Plonk", "Inf. DS", "Stride"]; List _historyShortTitles = ["TR", "Glicko", "RD", "APM", "PPS", "VS", "APP", "DS/S", "DS/P", "APP + DS/P", "VS/APM", "Cheese", "GbE", "wAPP", "Area", "eTR", "±eTR", "Opener", "Plonk", "Inf. DS", "Stride"];
late ScrollController _scrollController; late ScrollController _scrollController;
final NumberFormat _timeInSec = NumberFormat("#,###.###s.", LocaleSettings.currentLocale.languageCode); final NumberFormat _timeInSec = NumberFormat("#,###.###s.", LocaleSettings.currentLocale.languageCode);
@ -81,11 +83,15 @@ class _MainState extends State<MainView> with TickerProviderStateMixin {
TetrioPlayersLeaderboard? everyone; TetrioPlayersLeaderboard? everyone;
PlayerLeaderboardPosition? meAmongEveryone; PlayerLeaderboardPosition? meAmongEveryone;
TetraLeagueAlpha? rankAverages; TetraLeagueAlpha? rankAverages;
double? thatRankCutoff;
double? nextRankCutoff;
String _searchFor = "6098518e3d5155e6ec429cdc"; // who we looking for String _searchFor = "6098518e3d5155e6ec429cdc"; // who we looking for
String _titleNickname = "dan63047"; String _titleNickname = "";
/// Each dropdown menu item contains list of dots for the graph /// Each dropdown menu item contains list of dots for the graph
var chartsData = <DropdownMenuItem<List<FlSpot>>>[]; List<DropdownMenuItem<List<FlSpot>>> chartsData = [];
var chartsDataGamesPlayed = <DropdownMenuItem<List<FlSpot>>>[]; List<DropdownMenuItem<List<FlSpot>>>? smoothChartsData;
List<DropdownMenuItem<List<FlSpot>>> chartsDataGamesPlayed = [];
List<DropdownMenuItem<List<FlSpot>>>? smoothChartsDataGamesPlayed;
//var tableData = <TableRow>[]; //var tableData = <TableRow>[];
final bodyGlobalKey = GlobalKey(); final bodyGlobalKey = GlobalKey();
bool _showSearchBar = false; bool _showSearchBar = false;
@ -108,7 +114,7 @@ class _MainState extends State<MainView> with TickerProviderStateMixin {
changePlayer(widget.player!); // it's gonna be user input changePlayer(widget.player!); // it's gonna be user input
}else{ }else{
_getPreferences() // otherwise, checking for preferences _getPreferences() // otherwise, checking for preferences
.then((value) => changePlayer(prefs.getString("player") ?? "dan63047")); // no preferences - loading me .then((value) => changePlayer(prefs.getString("player") ?? "6098518e3d5155e6ec429cdc")); // no preferences - loading me
} }
super.initState(); super.initState();
} }
@ -185,6 +191,11 @@ class _MainState extends State<MainView> with TickerProviderStateMixin {
everyone ??= await teto.fetchTLLeaderboard(); everyone ??= await teto.fetchTLLeaderboard();
meAmongEveryone = await compute(everyone!.getLeaderboardPosition, me); meAmongEveryone = await compute(everyone!.getLeaderboardPosition, me);
if (meAmongEveryone != null) teto.cacheLeaderboardPositions(me.userId, meAmongEveryone!); if (meAmongEveryone != null) teto.cacheLeaderboardPositions(me.userId, meAmongEveryone!);
if (me.tlSeason1.rank != "z") {
thatRankCutoff = everyone!.cutoffs[me.tlSeason1.rank];
nextRankCutoff = everyone!.cutoffs[ranks.indexOf(me.tlSeason1.rank)+1];
nextRankCutoff = nextRankCutoff??25000;
}
} }
if (everyone != null && me.tlSeason1.gamesPlayed > 9) rankAverages = everyone?.averages[me.tlSeason1.percentileRank]?[0]; if (everyone != null && me.tlSeason1.gamesPlayed > 9) rankAverages = everyone?.averages[me.tlSeason1.percentileRank]?[0];
@ -262,51 +273,87 @@ class _MainState extends State<MainView> with TickerProviderStateMixin {
if (uniqueTL.length >= 2){ if (uniqueTL.length >= 2){
compareWith = uniqueTL.toList().elementAtOrNull(uniqueTL.length - 2); compareWith = uniqueTL.toList().elementAtOrNull(uniqueTL.length - 2);
chartsData = <DropdownMenuItem<List<FlSpot>>>[ // Dumping charts data into dropdown menu items, while cheking if every entry is valid chartsData = <DropdownMenuItem<List<FlSpot>>>[ // Dumping charts data into dropdown menu items, while cheking if every entry is valid
DropdownMenuItem(value: [for (var tl in uniqueTL) if (tl.gamesPlayed > 9) FlSpot(tl.timestamp.millisecondsSinceEpoch.toDouble(), tl.rating)], child: Text(t.statCellNum.tr)), DropdownMenuItem(value: [for (var tl in uniqueTL) if (tl.gamesPlayed > 9) FlSpot(tl.timestamp.millisecondsSinceEpoch.toDouble(), tl.rating)], child: Text(t.statCellNum.tr)),
DropdownMenuItem(value: [for (var tl in uniqueTL) if (tl.gamesPlayed > 9) FlSpot(tl.timestamp.millisecondsSinceEpoch.toDouble(), tl.glicko!)], child: const Text("Glicko")), DropdownMenuItem(value: [for (var tl in uniqueTL) if (tl.gamesPlayed > 9) FlSpot(tl.timestamp.millisecondsSinceEpoch.toDouble(), tl.glicko!)], child: const Text("Glicko")),
DropdownMenuItem(value: [for (var tl in uniqueTL) if (tl.gamesPlayed > 9) FlSpot(tl.timestamp.millisecondsSinceEpoch.toDouble(), tl.rd!)], child: const Text("Rating Deviation")), DropdownMenuItem(value: [for (var tl in uniqueTL) if (tl.gamesPlayed > 9) FlSpot(tl.timestamp.millisecondsSinceEpoch.toDouble(), tl.rd!)], child: const Text("Rating Deviation")),
DropdownMenuItem(value: [for (var tl in uniqueTL) if (tl.apm != null) FlSpot(tl.timestamp.millisecondsSinceEpoch.toDouble(), tl.apm!)], child: Text(t.statCellNum.apm.replaceAll(RegExp(r'\n'), " "))), DropdownMenuItem(value: [for (var tl in uniqueTL) if (tl.apm != null) FlSpot(tl.timestamp.millisecondsSinceEpoch.toDouble(), tl.apm!)], child: Text(t.statCellNum.apm.replaceAll(RegExp(r'\n'), " "))),
DropdownMenuItem(value: [for (var tl in uniqueTL) if (tl.pps != null) FlSpot(tl.timestamp.millisecondsSinceEpoch.toDouble(), tl.pps!)], child: Text(t.statCellNum.pps.replaceAll(RegExp(r'\n'), " "))), DropdownMenuItem(value: [for (var tl in uniqueTL) if (tl.pps != null) FlSpot(tl.timestamp.millisecondsSinceEpoch.toDouble(), tl.pps!)], child: Text(t.statCellNum.pps.replaceAll(RegExp(r'\n'), " "))),
DropdownMenuItem(value: [for (var tl in uniqueTL) if (tl.vs != null) FlSpot(tl.timestamp.millisecondsSinceEpoch.toDouble(), tl.vs!)], child: Text(t.statCellNum.vs.replaceAll(RegExp(r'\n'), " "))), DropdownMenuItem(value: [for (var tl in uniqueTL) if (tl.vs != null) FlSpot(tl.timestamp.millisecondsSinceEpoch.toDouble(), tl.vs!)], child: Text(t.statCellNum.vs.replaceAll(RegExp(r'\n'), " "))),
DropdownMenuItem(value: [for (var tl in uniqueTL) if (tl.nerdStats != null) FlSpot(tl.timestamp.millisecondsSinceEpoch.toDouble(), tl.nerdStats!.app)], child: Text(t.statCellNum.app.replaceAll(RegExp(r'\n'), " "))), DropdownMenuItem(value: [for (var tl in uniqueTL) if (tl.nerdStats != null) FlSpot(tl.timestamp.millisecondsSinceEpoch.toDouble(), tl.nerdStats!.app)], child: Text(t.statCellNum.app.replaceAll(RegExp(r'\n'), " "))),
DropdownMenuItem(value: [for (var tl in uniqueTL) if (tl.nerdStats != null) FlSpot(tl.timestamp.millisecondsSinceEpoch.toDouble(), tl.nerdStats!.dss)], child: Text(t.statCellNum.dss.replaceAll(RegExp(r'\n'), " "))), DropdownMenuItem(value: [for (var tl in uniqueTL) if (tl.nerdStats != null) FlSpot(tl.timestamp.millisecondsSinceEpoch.toDouble(), tl.nerdStats!.dss)], child: Text(t.statCellNum.dss.replaceAll(RegExp(r'\n'), " "))),
DropdownMenuItem(value: [for (var tl in uniqueTL) if (tl.nerdStats != null) FlSpot(tl.timestamp.millisecondsSinceEpoch.toDouble(), tl.nerdStats!.dsp)], child: Text(t.statCellNum.dsp.replaceAll(RegExp(r'\n'), " "))), DropdownMenuItem(value: [for (var tl in uniqueTL) if (tl.nerdStats != null) FlSpot(tl.timestamp.millisecondsSinceEpoch.toDouble(), tl.nerdStats!.dsp)], child: Text(t.statCellNum.dsp.replaceAll(RegExp(r'\n'), " "))),
DropdownMenuItem(value: [for (var tl in uniqueTL) if (tl.nerdStats != null) FlSpot(tl.timestamp.millisecondsSinceEpoch.toDouble(), tl.nerdStats!.appdsp)], child: const Text("APP + DS/P")), DropdownMenuItem(value: [for (var tl in uniqueTL) if (tl.nerdStats != null) FlSpot(tl.timestamp.millisecondsSinceEpoch.toDouble(), tl.nerdStats!.appdsp)], child: const Text("APP + DS/P")),
DropdownMenuItem(value: [for (var tl in uniqueTL) if (tl.nerdStats != null) FlSpot(tl.timestamp.millisecondsSinceEpoch.toDouble(), tl.nerdStats!.vsapm)], child: const Text("VS/APM")), DropdownMenuItem(value: [for (var tl in uniqueTL) if (tl.nerdStats != null) FlSpot(tl.timestamp.millisecondsSinceEpoch.toDouble(), tl.nerdStats!.vsapm)], child: const Text("VS/APM")),
DropdownMenuItem(value: [for (var tl in uniqueTL) if (tl.nerdStats != null) FlSpot(tl.timestamp.millisecondsSinceEpoch.toDouble(), tl.nerdStats!.cheese)], child: Text(t.statCellNum.cheese.replaceAll(RegExp(r'\n'), " "))), DropdownMenuItem(value: [for (var tl in uniqueTL) if (tl.nerdStats != null) FlSpot(tl.timestamp.millisecondsSinceEpoch.toDouble(), tl.nerdStats!.cheese)], child: Text(t.statCellNum.cheese.replaceAll(RegExp(r'\n'), " "))),
DropdownMenuItem(value: [for (var tl in uniqueTL) if (tl.nerdStats != null) FlSpot(tl.timestamp.millisecondsSinceEpoch.toDouble(), tl.nerdStats!.gbe)], child: Text(t.statCellNum.gbe.replaceAll(RegExp(r'\n'), " "))), DropdownMenuItem(value: [for (var tl in uniqueTL) if (tl.nerdStats != null) FlSpot(tl.timestamp.millisecondsSinceEpoch.toDouble(), tl.nerdStats!.gbe)], child: Text(t.statCellNum.gbe.replaceAll(RegExp(r'\n'), " "))),
DropdownMenuItem(value: [for (var tl in uniqueTL) if (tl.nerdStats != null) FlSpot(tl.timestamp.millisecondsSinceEpoch.toDouble(), tl.nerdStats!.nyaapp)], child: Text(t.statCellNum.nyaapp.replaceAll(RegExp(r'\n'), " "))), DropdownMenuItem(value: [for (var tl in uniqueTL) if (tl.nerdStats != null) FlSpot(tl.timestamp.millisecondsSinceEpoch.toDouble(), tl.nerdStats!.nyaapp)], child: Text(t.statCellNum.nyaapp.replaceAll(RegExp(r'\n'), " "))),
DropdownMenuItem(value: [for (var tl in uniqueTL) if (tl.nerdStats != null) FlSpot(tl.timestamp.millisecondsSinceEpoch.toDouble(), tl.nerdStats!.area)], child: Text(t.statCellNum.area.replaceAll(RegExp(r'\n'), " "))), DropdownMenuItem(value: [for (var tl in uniqueTL) if (tl.nerdStats != null) FlSpot(tl.timestamp.millisecondsSinceEpoch.toDouble(), tl.nerdStats!.area)], child: Text(t.statCellNum.area.replaceAll(RegExp(r'\n'), " "))),
DropdownMenuItem(value: [for (var tl in uniqueTL) if (tl.estTr != null) FlSpot(tl.timestamp.millisecondsSinceEpoch.toDouble(), tl.estTr!.esttr)], child: Text(t.statCellNum.estOfTR.replaceAll(RegExp(r'\n'), " "))), DropdownMenuItem(value: [for (var tl in uniqueTL) if (tl.estTr != null) FlSpot(tl.timestamp.millisecondsSinceEpoch.toDouble(), tl.estTr!.esttr)], child: Text(t.statCellNum.estOfTR.replaceAll(RegExp(r'\n'), " "))),
DropdownMenuItem(value: [for (var tl in uniqueTL) if (tl.esttracc != null) FlSpot(tl.timestamp.millisecondsSinceEpoch.toDouble(), tl.esttracc!)], child: Text(t.statCellNum.accOfEst.replaceAll(RegExp(r'\n'), " "))), DropdownMenuItem(value: [for (var tl in uniqueTL) if (tl.esttracc != null) FlSpot(tl.timestamp.millisecondsSinceEpoch.toDouble(), tl.esttracc!)], child: Text(t.statCellNum.accOfEst.replaceAll(RegExp(r'\n'), " "))),
DropdownMenuItem(value: [for (var tl in uniqueTL) if (tl.playstyle != null) FlSpot(tl.timestamp.millisecondsSinceEpoch.toDouble(), tl.playstyle!.opener)], child: const Text("Opener")), DropdownMenuItem(value: [for (var tl in uniqueTL) if (tl.playstyle != null) FlSpot(tl.timestamp.millisecondsSinceEpoch.toDouble(), tl.playstyle!.opener)], child: const Text("Opener")),
DropdownMenuItem(value: [for (var tl in uniqueTL) if (tl.playstyle != null) FlSpot(tl.timestamp.millisecondsSinceEpoch.toDouble(), tl.playstyle!.plonk)], child: const Text("Plonk")), DropdownMenuItem(value: [for (var tl in uniqueTL) if (tl.playstyle != null) FlSpot(tl.timestamp.millisecondsSinceEpoch.toDouble(), tl.playstyle!.plonk)], child: const Text("Plonk")),
DropdownMenuItem(value: [for (var tl in uniqueTL) if (tl.playstyle != null) FlSpot(tl.timestamp.millisecondsSinceEpoch.toDouble(), tl.playstyle!.infds)], child: const Text("Inf. DS")), DropdownMenuItem(value: [for (var tl in uniqueTL) if (tl.playstyle != null) FlSpot(tl.timestamp.millisecondsSinceEpoch.toDouble(), tl.playstyle!.infds)], child: const Text("Inf. DS")),
DropdownMenuItem(value: [for (var tl in uniqueTL) if (tl.playstyle != null) FlSpot(tl.timestamp.millisecondsSinceEpoch.toDouble(), tl.playstyle!.stride)], child: const Text("Stride")), DropdownMenuItem(value: [for (var tl in uniqueTL) if (tl.playstyle != null) FlSpot(tl.timestamp.millisecondsSinceEpoch.toDouble(), tl.playstyle!.stride)], child: const Text("Stride")),
]; ];
chartsDataGamesPlayed = <DropdownMenuItem<List<FlSpot>>>[ // Dumping charts data into dropdown menu items, while cheking if every entry is valid chartsDataGamesPlayed = <DropdownMenuItem<List<FlSpot>>>[ // Dumping charts data into dropdown menu items, while cheking if every entry is valid
DropdownMenuItem(value: [for (var tl in uniqueTL) if (tl.gamesPlayed > 9) FlSpot(tl.gamesPlayed.toDouble(), tl.rating)], child: Text(t.statCellNum.tr)), DropdownMenuItem(value: [for (var tl in uniqueTL) if (tl.gamesPlayed > 9) FlSpot(tl.gamesPlayed.toDouble(), tl.rating)], child: Text(t.statCellNum.tr)),
DropdownMenuItem(value: [for (var tl in uniqueTL) if (tl.gamesPlayed > 9) FlSpot(tl.gamesPlayed.toDouble(), tl.glicko!)], child: const Text("Glicko")), DropdownMenuItem(value: [for (var tl in uniqueTL) if (tl.gamesPlayed > 9) FlSpot(tl.gamesPlayed.toDouble(), tl.glicko!)], child: const Text("Glicko")),
DropdownMenuItem(value: [for (var tl in uniqueTL) if (tl.gamesPlayed > 9) FlSpot(tl.gamesPlayed.toDouble(), tl.rd!)], child: const Text("Rating Deviation")), DropdownMenuItem(value: [for (var tl in uniqueTL) if (tl.gamesPlayed > 9) FlSpot(tl.gamesPlayed.toDouble(), tl.rd!)], child: const Text("Rating Deviation")),
DropdownMenuItem(value: [for (var tl in uniqueTL) if (tl.apm != null) FlSpot(tl.gamesPlayed.toDouble(), tl.apm!)], child: Text(t.statCellNum.apm.replaceAll(RegExp(r'\n'), " "))), DropdownMenuItem(value: [for (var tl in uniqueTL) if (tl.apm != null) FlSpot(tl.gamesPlayed.toDouble(), tl.apm!)], child: Text(t.statCellNum.apm.replaceAll(RegExp(r'\n'), " "))),
DropdownMenuItem(value: [for (var tl in uniqueTL) if (tl.pps != null) FlSpot(tl.gamesPlayed.toDouble(), tl.pps!)], child: Text(t.statCellNum.pps.replaceAll(RegExp(r'\n'), " "))), DropdownMenuItem(value: [for (var tl in uniqueTL) if (tl.pps != null) FlSpot(tl.gamesPlayed.toDouble(), tl.pps!)], child: Text(t.statCellNum.pps.replaceAll(RegExp(r'\n'), " "))),
DropdownMenuItem(value: [for (var tl in uniqueTL) if (tl.vs != null) FlSpot(tl.gamesPlayed.toDouble(), tl.vs!)], child: Text(t.statCellNum.vs.replaceAll(RegExp(r'\n'), " "))), DropdownMenuItem(value: [for (var tl in uniqueTL) if (tl.vs != null) FlSpot(tl.gamesPlayed.toDouble(), tl.vs!)], child: Text(t.statCellNum.vs.replaceAll(RegExp(r'\n'), " "))),
DropdownMenuItem(value: [for (var tl in uniqueTL) if (tl.nerdStats != null) FlSpot(tl.gamesPlayed.toDouble(), tl.nerdStats!.app)], child: Text(t.statCellNum.app.replaceAll(RegExp(r'\n'), " "))), DropdownMenuItem(value: [for (var tl in uniqueTL) if (tl.nerdStats != null) FlSpot(tl.gamesPlayed.toDouble(), tl.nerdStats!.app)], child: Text(t.statCellNum.app.replaceAll(RegExp(r'\n'), " "))),
DropdownMenuItem(value: [for (var tl in uniqueTL) if (tl.nerdStats != null) FlSpot(tl.gamesPlayed.toDouble(), tl.nerdStats!.dss)], child: Text(t.statCellNum.dss.replaceAll(RegExp(r'\n'), " "))), DropdownMenuItem(value: [for (var tl in uniqueTL) if (tl.nerdStats != null) FlSpot(tl.gamesPlayed.toDouble(), tl.nerdStats!.dss)], child: Text(t.statCellNum.dss.replaceAll(RegExp(r'\n'), " "))),
DropdownMenuItem(value: [for (var tl in uniqueTL) if (tl.nerdStats != null) FlSpot(tl.gamesPlayed.toDouble(), tl.nerdStats!.dsp)], child: Text(t.statCellNum.dsp.replaceAll(RegExp(r'\n'), " "))), DropdownMenuItem(value: [for (var tl in uniqueTL) if (tl.nerdStats != null) FlSpot(tl.gamesPlayed.toDouble(), tl.nerdStats!.dsp)], child: Text(t.statCellNum.dsp.replaceAll(RegExp(r'\n'), " "))),
DropdownMenuItem(value: [for (var tl in uniqueTL) if (tl.nerdStats != null) FlSpot(tl.gamesPlayed.toDouble(), tl.nerdStats!.appdsp)], child: const Text("APP + DS/P")), DropdownMenuItem(value: [for (var tl in uniqueTL) if (tl.nerdStats != null) FlSpot(tl.gamesPlayed.toDouble(), tl.nerdStats!.appdsp)], child: const Text("APP + DS/P")),
DropdownMenuItem(value: [for (var tl in uniqueTL) if (tl.nerdStats != null) FlSpot(tl.gamesPlayed.toDouble(), tl.nerdStats!.vsapm)], child: const Text("VS/APM")), DropdownMenuItem(value: [for (var tl in uniqueTL) if (tl.nerdStats != null) FlSpot(tl.gamesPlayed.toDouble(), tl.nerdStats!.vsapm)], child: const Text("VS/APM")),
DropdownMenuItem(value: [for (var tl in uniqueTL) if (tl.nerdStats != null) FlSpot(tl.gamesPlayed.toDouble(), tl.nerdStats!.cheese)], child: Text(t.statCellNum.cheese.replaceAll(RegExp(r'\n'), " "))), DropdownMenuItem(value: [for (var tl in uniqueTL) if (tl.nerdStats != null) FlSpot(tl.gamesPlayed.toDouble(), tl.nerdStats!.cheese)], child: Text(t.statCellNum.cheese.replaceAll(RegExp(r'\n'), " "))),
DropdownMenuItem(value: [for (var tl in uniqueTL) if (tl.nerdStats != null) FlSpot(tl.gamesPlayed.toDouble(), tl.nerdStats!.gbe)], child: Text(t.statCellNum.gbe.replaceAll(RegExp(r'\n'), " "))), DropdownMenuItem(value: [for (var tl in uniqueTL) if (tl.nerdStats != null) FlSpot(tl.gamesPlayed.toDouble(), tl.nerdStats!.gbe)], child: Text(t.statCellNum.gbe.replaceAll(RegExp(r'\n'), " "))),
DropdownMenuItem(value: [for (var tl in uniqueTL) if (tl.nerdStats != null) FlSpot(tl.gamesPlayed.toDouble(), tl.nerdStats!.nyaapp)], child: Text(t.statCellNum.nyaapp.replaceAll(RegExp(r'\n'), " "))), DropdownMenuItem(value: [for (var tl in uniqueTL) if (tl.nerdStats != null) FlSpot(tl.gamesPlayed.toDouble(), tl.nerdStats!.nyaapp)], child: Text(t.statCellNum.nyaapp.replaceAll(RegExp(r'\n'), " "))),
DropdownMenuItem(value: [for (var tl in uniqueTL) if (tl.nerdStats != null) FlSpot(tl.gamesPlayed.toDouble(), tl.nerdStats!.area)], child: Text(t.statCellNum.area.replaceAll(RegExp(r'\n'), " "))), DropdownMenuItem(value: [for (var tl in uniqueTL) if (tl.nerdStats != null) FlSpot(tl.gamesPlayed.toDouble(), tl.nerdStats!.area)], child: Text(t.statCellNum.area.replaceAll(RegExp(r'\n'), " "))),
DropdownMenuItem(value: [for (var tl in uniqueTL) if (tl.estTr != null) FlSpot(tl.gamesPlayed.toDouble(), tl.estTr!.esttr)], child: Text(t.statCellNum.estOfTR.replaceAll(RegExp(r'\n'), " "))), DropdownMenuItem(value: [for (var tl in uniqueTL) if (tl.estTr != null) FlSpot(tl.gamesPlayed.toDouble(), tl.estTr!.esttr)], child: Text(t.statCellNum.estOfTR.replaceAll(RegExp(r'\n'), " "))),
DropdownMenuItem(value: [for (var tl in uniqueTL) if (tl.esttracc != null) FlSpot(tl.gamesPlayed.toDouble(), tl.esttracc!)], child: Text(t.statCellNum.accOfEst.replaceAll(RegExp(r'\n'), " "))), DropdownMenuItem(value: [for (var tl in uniqueTL) if (tl.esttracc != null) FlSpot(tl.gamesPlayed.toDouble(), tl.esttracc!)], child: Text(t.statCellNum.accOfEst.replaceAll(RegExp(r'\n'), " "))),
DropdownMenuItem(value: [for (var tl in uniqueTL) if (tl.playstyle != null) FlSpot(tl.gamesPlayed.toDouble(), tl.playstyle!.opener)], child: const Text("Opener")), DropdownMenuItem(value: [for (var tl in uniqueTL) if (tl.playstyle != null) FlSpot(tl.gamesPlayed.toDouble(), tl.playstyle!.opener)], child: const Text("Opener")),
DropdownMenuItem(value: [for (var tl in uniqueTL) if (tl.playstyle != null) FlSpot(tl.gamesPlayed.toDouble(), tl.playstyle!.plonk)], child: const Text("Plonk")), DropdownMenuItem(value: [for (var tl in uniqueTL) if (tl.playstyle != null) FlSpot(tl.gamesPlayed.toDouble(), tl.playstyle!.plonk)], child: const Text("Plonk")),
DropdownMenuItem(value: [for (var tl in uniqueTL) if (tl.playstyle != null) FlSpot(tl.gamesPlayed.toDouble(), tl.playstyle!.infds)], child: const Text("Inf. DS")), DropdownMenuItem(value: [for (var tl in uniqueTL) if (tl.playstyle != null) FlSpot(tl.gamesPlayed.toDouble(), tl.playstyle!.infds)], child: const Text("Inf. DS")),
DropdownMenuItem(value: [for (var tl in uniqueTL) if (tl.playstyle != null) FlSpot(tl.gamesPlayed.toDouble(), tl.playstyle!.stride)], child: const Text("Stride")), DropdownMenuItem(value: [for (var tl in uniqueTL) if (tl.playstyle != null) FlSpot(tl.gamesPlayed.toDouble(), tl.playstyle!.stride)], child: const Text("Stride")),
]; ];
if (chartsData[0].value!.length > 200){
smoothChartsData = [];
smoothChartsDataGamesPlayed = [];
for (var chart in chartsData) {
int valuesPerDot = (chart.value!.length / 200).floor();
int lastDotEntries = chart.value!.length - (valuesPerDot * 199);
List<FlSpot> spots = [];
for (int i=0; i < 200; i++){
double avgX = 0, avgY = 0;
for (int k = i * valuesPerDot; k < (i == 199 ? chart.value!.length : i * valuesPerDot + valuesPerDot); k++) {
avgX += chart.value![k].x;
avgY += chart.value![k].y;
}
avgX /= i == 199 ? lastDotEntries : valuesPerDot;
avgY /= i == 199 ? lastDotEntries : valuesPerDot;
spots.add(FlSpot(avgX, avgY));
}
smoothChartsData!.add(DropdownMenuItem(value: spots, child: chart.child));
}
for (var chart in chartsDataGamesPlayed) {
int valuesPerDot = (chart.value!.length / 200).floor();
int lastDotEntries = chart.value!.length - (valuesPerDot * 199);
List<FlSpot> spots = [];
for (int i=0; i < 200; i++){
double avgX = 0, avgY = 0;
for (int k = i * valuesPerDot; k < (i == 199 ? chart.value!.length : i * valuesPerDot + valuesPerDot); k++) {
avgX += chart.value![k].x;
avgY += chart.value![k].y;
}
avgX /= i == 199 ? lastDotEntries : valuesPerDot;
avgY /= i == 199 ? lastDotEntries : valuesPerDot;
spots.add(FlSpot(avgX, avgY));
}
smoothChartsDataGamesPlayed!.add(DropdownMenuItem(value: spots, child: chart.child));
}
}
}else{ }else{
compareWith = null; compareWith = null;
chartsData = []; chartsData = [];
@ -465,6 +512,10 @@ class _MainState extends State<MainView> with TickerProviderStateMixin {
topTR: snapshot.data![7], topTR: snapshot.data![7],
bot: snapshot.data![0].role == "bot", bot: snapshot.data![0].role == "bot",
guest: snapshot.data![0].role == "anon", guest: snapshot.data![0].role == "anon",
thatRankCutoff: thatRankCutoff,
thatRankTarget: snapshot.data![0].tlSeason1.rank != "z" ? rankTargets[snapshot.data![0].tlSeason1.rank] : null,
nextRankCutoff: nextRankCutoff,
nextRankTarget: snapshot.data![0].tlSeason1.rank != "z" || snapshot.data![0].tlSeason1.rank != "x" ? rankTargets[ranks.indexOf(snapshot.data![0].tlSeason1.rank)+1] : null,
averages: rankAverages, averages: rankAverages,
lbPositions: meAmongEveryone lbPositions: meAmongEveryone
), ),
@ -474,7 +525,7 @@ class _MainState extends State<MainView> with TickerProviderStateMixin {
child: _TLRecords(userID: snapshot.data![0].userId, changePlayer: changePlayer, data: snapshot.data![3], wasActiveInTL: snapshot.data![0].tlSeason1.gamesPlayed > 0, oldMathcesHere: _TLHistoryWasFetched, separateScrollController: true,) child: _TLRecords(userID: snapshot.data![0].userId, changePlayer: changePlayer, data: snapshot.data![3], wasActiveInTL: snapshot.data![0].tlSeason1.gamesPlayed > 0, oldMathcesHere: _TLHistoryWasFetched, separateScrollController: true,)
), ),
],), ],),
_History(chartsData: chartsData, chartsDataGamesPlayed: chartsDataGamesPlayed, changePlayer: changePlayer, userID: _searchFor, update: _justUpdate, wasActiveInTL: snapshot.data![0].tlSeason1.gamesPlayed > 0), _History(chartsData: chartsData, chartsDataGamesPlayed: chartsDataGamesPlayed, changePlayer: changePlayer, userID: _searchFor, update: _justUpdate, wasActiveInTL: snapshot.data![0].tlSeason1.gamesPlayed > 0, smoothChartsData: smoothChartsData, smoothChartsDataGamesPlayed: smoothChartsDataGamesPlayed),
_TwoRecordsThingy(sprint: snapshot.data![1]['sprint'], blitz: snapshot.data![1]['blitz'], rank: snapshot.data![0].tlSeason1.percentileRank,), _TwoRecordsThingy(sprint: snapshot.data![1]['sprint'], blitz: snapshot.data![1]['blitz'], rank: snapshot.data![0].tlSeason1.percentileRank,),
_OtherThingy(zen: snapshot.data![1]['zen'], bio: snapshot.data![0].bio, distinguishment: snapshot.data![0].distinguishment, newsletter: snapshot.data![6],) _OtherThingy(zen: snapshot.data![1]['zen'], bio: snapshot.data![0].bio, distinguishment: snapshot.data![0].distinguishment, newsletter: snapshot.data![6],)
] : [ ] : [
@ -489,7 +540,7 @@ class _MainState extends State<MainView> with TickerProviderStateMixin {
lbPositions: meAmongEveryone lbPositions: meAmongEveryone
), ),
_TLRecords(userID: snapshot.data![0].userId, changePlayer: changePlayer, data: snapshot.data![3], wasActiveInTL: snapshot.data![0].tlSeason1.gamesPlayed > 0, oldMathcesHere: _TLHistoryWasFetched), _TLRecords(userID: snapshot.data![0].userId, changePlayer: changePlayer, data: snapshot.data![3], wasActiveInTL: snapshot.data![0].tlSeason1.gamesPlayed > 0, oldMathcesHere: _TLHistoryWasFetched),
_History(chartsData: chartsData, chartsDataGamesPlayed: chartsDataGamesPlayed, changePlayer: changePlayer, userID: _searchFor, update: _justUpdate, wasActiveInTL: snapshot.data![0].tlSeason1.gamesPlayed > 0), _History(chartsData: chartsData, chartsDataGamesPlayed: chartsDataGamesPlayed, changePlayer: changePlayer, userID: _searchFor, update: _justUpdate, wasActiveInTL: snapshot.data![0].tlSeason1.gamesPlayed > 0, smoothChartsData: smoothChartsData, smoothChartsDataGamesPlayed: smoothChartsDataGamesPlayed),
_RecordThingy(record: snapshot.data![1]['sprint'], rank: snapshot.data![0].tlSeason1.percentileRank), _RecordThingy(record: snapshot.data![1]['sprint'], rank: snapshot.data![0].tlSeason1.percentileRank),
_RecordThingy(record: snapshot.data![1]['blitz'], rank: snapshot.data![0].tlSeason1.percentileRank), _RecordThingy(record: snapshot.data![1]['blitz'], rank: snapshot.data![0].tlSeason1.percentileRank),
_OtherThingy(zen: snapshot.data![1]['zen'], bio: snapshot.data![0].bio, distinguishment: snapshot.data![0].distinguishment, newsletter: snapshot.data![6],) _OtherThingy(zen: snapshot.data![1]['zen'], bio: snapshot.data![0].bio, distinguishment: snapshot.data![0].distinguishment, newsletter: snapshot.data![6],)
@ -592,7 +643,7 @@ class _NavDrawerState extends State<NavDrawer> {
homePlayerNickname = id; homePlayerNickname = id;
} }
} else { } else {
homePlayerNickname = "dan63047"; homePlayerNickname = "dan63";
} }
setState(() {}); setState(() {});
} }
@ -624,7 +675,7 @@ class _NavDrawerState extends State<NavDrawer> {
leading: const Icon(Icons.home), leading: const Icon(Icons.home),
title: Text(homePlayerNickname), title: Text(homePlayerNickname),
onTap: () { onTap: () {
widget.changePlayer(prefs.getString("player") ?? "dan63047"); // changes player on main view to the one from preferences widget.changePlayer(prefs.getString("player") ?? "6098518e3d5155e6ec429cdc"); // changes player on main view to the one from preferences
Navigator.of(context).pop(); // and then NavDrawer closes itself. Navigator.of(context).pop(); // and then NavDrawer closes itself.
}, },
), ),
@ -753,7 +804,9 @@ class _TLRecords extends StatelessWidget {
class _History extends StatelessWidget{ class _History extends StatelessWidget{
final List<DropdownMenuItem<List<FlSpot>>> chartsData; final List<DropdownMenuItem<List<FlSpot>>> chartsData;
final List<DropdownMenuItem<List<FlSpot>>>? smoothChartsData;
final List<DropdownMenuItem<List<FlSpot>>> chartsDataGamesPlayed; final List<DropdownMenuItem<List<FlSpot>>> chartsDataGamesPlayed;
final List<DropdownMenuItem<List<FlSpot>>>? smoothChartsDataGamesPlayed;
final String userID; final String userID;
final Function update; final Function update;
final Function changePlayer; final Function changePlayer;
@ -761,7 +814,7 @@ class _History extends StatelessWidget{
/// Widget, that can show history of some stat of the player on the graph. /// Widget, that can show history of some stat of the player on the graph.
/// Requires player [states], which is list of states and function [update], which rebuild widgets /// Requires player [states], which is list of states and function [update], which rebuild widgets
const _History({required this.chartsData, required this.chartsDataGamesPlayed, required this.userID, required this.changePlayer, required this.update, required this.wasActiveInTL}); const _History({required this.chartsData, required this.chartsDataGamesPlayed, required this.userID, required this.changePlayer, required this.update, required this.wasActiveInTL, this.smoothChartsData, this.smoothChartsDataGamesPlayed});
@override @override
Widget build(BuildContext context) { Widget build(BuildContext context) {
@ -776,6 +829,8 @@ class _History extends StatelessWidget{
)); ));
} }
bool bigScreen = MediaQuery.of(context).size.width > 768; bool bigScreen = MediaQuery.of(context).size.width > 768;
var selectedGraph = _gamesPlayedInsteadOfDateAndTime ? chartsDataGamesPlayed[_chartsIndex].value! : chartsData[_chartsIndex].value!;
var smoothSelectedGraph = _gamesPlayedInsteadOfDateAndTime ? (smoothChartsDataGamesPlayed?[_chartsIndex].value) : (smoothChartsData?[_chartsIndex].value);
return SingleChildScrollView( return SingleChildScrollView(
scrollDirection: Axis.vertical, scrollDirection: Axis.vertical,
child: SingleChildScrollView( child: SingleChildScrollView(
@ -786,6 +841,7 @@ class _History extends StatelessWidget{
children: [ children: [
Wrap( Wrap(
spacing: 20, spacing: 20,
crossAxisAlignment: WrapCrossAlignment.center,
children: [ children: [
Row( Row(
mainAxisSize: MainAxisSize.min, mainAxisSize: MainAxisSize.min,
@ -815,9 +871,21 @@ class _History extends StatelessWidget{
), ),
], ],
), ),
if (smoothSelectedGraph != null) Row(
mainAxisSize: MainAxisSize.min,
children: [
Checkbox(value: _smooth,
checkColor: Colors.black,
onChanged: ((value) {
_smooth = value!;
update();
})),
Text(t.smooth, style: const TextStyle(color: Colors.white, fontSize: 22))
],
)
], ],
), ),
if(chartsData[_chartsIndex].value!.length > 1) _HistoryChartThigy(data: _gamesPlayedInsteadOfDateAndTime ? chartsDataGamesPlayed[_chartsIndex].value! : chartsData[_chartsIndex].value!, yAxisTitle: _historyShortTitles[_chartsIndex], bigScreen: bigScreen, leftSpace: bigScreen? 80 : 45, yFormat: bigScreen? f2 : NumberFormat.compact(), xFormat: NumberFormat.compact()) if(chartsData[_chartsIndex].value!.length > 1) _HistoryChartThigy(data: selectedGraph, smoothData: smoothSelectedGraph, smooth: _smooth, yAxisTitle: _historyShortTitles[_chartsIndex], bigScreen: bigScreen, leftSpace: bigScreen? 80 : 45, yFormat: bigScreen? f2 : NumberFormat.compact(), xFormat: NumberFormat.compact())
else if (chartsData[_chartsIndex].value!.length <= 1) Center(child: Column( else if (chartsData[_chartsIndex].value!.length <= 1) Center(child: Column(
mainAxisSize: MainAxisSize.min, mainAxisSize: MainAxisSize.min,
children: [ children: [
@ -835,6 +903,8 @@ class _History extends StatelessWidget{
class _HistoryChartThigy extends StatefulWidget{ class _HistoryChartThigy extends StatefulWidget{
final List<FlSpot> data; final List<FlSpot> data;
final List<FlSpot>? smoothData;
final bool smooth;
final String yAxisTitle; final String yAxisTitle;
final bool bigScreen; final bool bigScreen;
final double leftSpace; final double leftSpace;
@ -844,7 +914,7 @@ class _HistoryChartThigy extends StatefulWidget{
/// Implements graph for the _History widget. Requires [data] which is a list of dots for the graph. [yAxisTitle] used to keep track of changes. /// Implements graph for the _History widget. Requires [data] which is a list of dots for the graph. [yAxisTitle] used to keep track of changes.
/// [bigScreen] tells if screen wide enough, [leftSpace] sets size, reserved for titles on the left from the graph and [yFormat] sets number format /// [bigScreen] tells if screen wide enough, [leftSpace] sets size, reserved for titles on the left from the graph and [yFormat] sets number format
/// for left titles /// for left titles
const _HistoryChartThigy({required this.data, required this.yAxisTitle, required this.bigScreen, required this.leftSpace, required this.yFormat, this.xFormat}); const _HistoryChartThigy({required this.data, this.smoothData, required this.smooth, required this.yAxisTitle, required this.bigScreen, required this.leftSpace, required this.yFormat, this.xFormat});
@override @override
State<_HistoryChartThigy> createState() => _HistoryChartThigyState(); State<_HistoryChartThigy> createState() => _HistoryChartThigyState();
@ -1050,8 +1120,26 @@ class _HistoryChartThigyState extends State<_HistoryChartThigy> {
children: [ children: [
LineChart( LineChart(
key: graphKey, key: graphKey,
curve: Curves.elasticInOut,
LineChartData( LineChartData(
lineBarsData: [LineChartBarData(spots: widget.data)], lineBarsData: [
LineChartBarData(
show: !_smooth,
spots: widget.data,
dotData: FlDotData(show: false),
isCurved: true,
curveSmoothness: 0.35,
preventCurveOverShooting: true
),
if (widget.smoothData != null) LineChartBarData(
show: _smooth,
spots: widget.smoothData!,
dotData: FlDotData(show: false),
isCurved: true,
curveSmoothness: 0.35,
preventCurveOverShooting: true,
)
],
clipData: const FlClipData.all(), clipData: const FlClipData.all(),
borderData: FlBorderData(show: false), borderData: FlBorderData(show: false),
gridData: FlGridData(verticalInterval: xInterval), gridData: FlGridData(verticalInterval: xInterval),
@ -1116,29 +1204,6 @@ class _HistoryChartThigyState extends State<_HistoryChartThigy> {
} }
} }
// class _HistoryTableThingy extends StatelessWidget{
// final List<TableRow> tableData;
// const _HistoryTableThingy(this.tableData);
// // :tf:
// @override
// Widget build(BuildContext context) {
// return LayoutBuilder(builder: (context, constraints){
// return Table(
// defaultColumnWidth: FixedColumnWidth(75),
// columnWidths: {
// 0: FixedColumnWidth(170),
// 1: FixedColumnWidth(100),
// 2: FixedColumnWidth(90),
// 18: FixedColumnWidth(100),
// 19: FixedColumnWidth(90),
// },
// children: tableData,
// );
// });
// }
// }
class _TwoRecordsThingy extends StatelessWidget { class _TwoRecordsThingy extends StatelessWidget {
final RecordSingle? sprint; final RecordSingle? sprint;
final RecordSingle? blitz; final RecordSingle? blitz;

View File

@ -15,6 +15,7 @@ var _chartsShortTitlesDropdowns = <DropdownMenuItem>[for (MapEntry e in chartsSh
Stats _chartsX = Stats.tr; Stats _chartsX = Stats.tr;
Stats _chartsY = Stats.apm; Stats _chartsY = Stats.apm;
List<DropdownMenuItem> _itemStats = [for (MapEntry e in chartsShortTitles.entries) DropdownMenuItem(value: e.key, child: Text(e.value))]; List<DropdownMenuItem> _itemStats = [for (MapEntry e in chartsShortTitles.entries) DropdownMenuItem(value: e.key, child: Text(e.value))];
List<_MyScatterSpot> _spots = [];
Stats _sortBy = Stats.tr; Stats _sortBy = Stats.tr;
late List<TetrioPlayerFromLeaderboard> they; late List<TetrioPlayerFromLeaderboard> they;
bool _reversed = false; bool _reversed = false;
@ -63,6 +64,7 @@ class RankState extends State<RankView> with SingleTickerProviderStateMixin {
super.initState(); super.initState();
previousAxisTitles = _chartsX.toString()+_chartsY.toString(); previousAxisTitles = _chartsX.toString()+_chartsY.toString();
they = TetrioPlayersLeaderboard("lol", []).getStatRanking(widget.rank[1]["entries"]!, _sortBy, reversed: _reversed, country: _country); they = TetrioPlayersLeaderboard("lol", []).getStatRanking(widget.rank[1]["entries"]!, _sortBy, reversed: _reversed, country: _country);
createSpots();
recalculateBoundaries(); recalculateBoundaries();
resetScale(); resetScale();
} }
@ -102,6 +104,19 @@ class RankState extends State<RankView> with SingleTickerProviderStateMixin {
}).getStatByEnum(_chartsY).toDouble(); }).getStatByEnum(_chartsY).toDouble();
} }
void createSpots(){
_spots = [
for (TetrioPlayerFromLeaderboard entry in widget.rank[1]["entries"])
if (entry.apm != 0.0 && entry.vs != 0.0) // prevents from ScatterChart "Offset argument contained a NaN value." exception
_MyScatterSpot(
entry.getStatByEnum(_chartsX).toDouble(),
entry.getStatByEnum(_chartsY).toDouble(),
entry.userId,
entry.username,
dotPainter: FlDotCirclePainter(color: rankColors[entry.rank]??Colors.white, radius: 3))
];
}
void resetScale(){ void resetScale(){
maxX = actualMaxX; maxX = actualMaxX;
minX = actualMinX; minX = actualMinX;
@ -161,6 +176,7 @@ class RankState extends State<RankView> with SingleTickerProviderStateMixin {
double graphStartX = padding.left; double graphStartX = padding.left;
double graphEndX = MediaQuery.sizeOf(context).width - padding.right; double graphEndX = MediaQuery.sizeOf(context).width - padding.right;
if (previousAxisTitles != _chartsX.toString()+_chartsY.toString()){ if (previousAxisTitles != _chartsX.toString()+_chartsY.toString()){
createSpots();
recalculateBoundaries(); recalculateBoundaries();
resetScale(); resetScale();
previousAxisTitles = _chartsX.toString()+_chartsY.toString(); previousAxisTitles = _chartsX.toString()+_chartsY.toString();
@ -325,16 +341,7 @@ class RankState extends State<RankView> with SingleTickerProviderStateMixin {
minY: minY, minY: minY,
maxY: maxY, maxY: maxY,
clipData: const FlClipData.all(), clipData: const FlClipData.all(),
scatterSpots: [ scatterSpots: _spots,
for (TetrioPlayerFromLeaderboard entry in widget.rank[1]["entries"])
if (entry.apm != 0.0 && entry.vs != 0.0) // prevents from ScatterChart "Offset argument contained a NaN value." exception
_MyScatterSpot(
entry.getStatByEnum(_chartsX).toDouble(),
entry.getStatByEnum(_chartsY).toDouble(),
entry.userId,
entry.username,
dotPainter: FlDotCirclePainter(color: rankColors[entry.rank]??Colors.white, radius: 3))
],
scatterTouchData: ScatterTouchData( scatterTouchData: ScatterTouchData(
handleBuiltInTouches: false, handleBuiltInTouches: false,
touchCallback:(touchEvent, touchResponse) { touchCallback:(touchEvent, touchResponse) {

View File

@ -64,7 +64,7 @@ class SettingsState extends State<SettingsView> {
defaultNickname = n; defaultNickname = n;
} }
} else { } else {
defaultNickname = "dan63047"; defaultNickname = "6098518e3d5155e6ec429cdc";
} }
setState(() {}); setState(() {});
} }
@ -76,7 +76,7 @@ class SettingsState extends State<SettingsView> {
Future<void> _removePlayer() async { Future<void> _removePlayer() async {
await prefs.remove('player'); await prefs.remove('player');
await _setDefaultNickname("dan63047"); await _setDefaultNickname("6098518e3d5155e6ec429cdc");
} }
@override @override

View File

@ -2,6 +2,8 @@
import 'dart:io'; import 'dart:io';
import 'dart:math'; import 'dart:math';
import 'package:flutter/cupertino.dart';
import 'package:flutter/widgets.dart';
import 'package:tetra_stats/data_objects/tetrio_multiplayer_replay.dart'; import 'package:tetra_stats/data_objects/tetrio_multiplayer_replay.dart';
import 'package:tetra_stats/services/crud_exceptions.dart'; import 'package:tetra_stats/services/crud_exceptions.dart';
import 'package:tetra_stats/views/compare_view.dart' show CompareThingy, CompareBoolThingy; import 'package:tetra_stats/views/compare_view.dart' show CompareThingy, CompareBoolThingy;
@ -62,422 +64,426 @@ class TlMatchResultState extends State<TlMatchResultView> {
super.dispose(); super.dispose();
} }
Widget buildComparison(bool bigScreen, bool showMobileSelector){ Widget buildComparison(double width, bool showMobileSelector){
return FutureBuilder(future: replayData, builder: (context, snapshot){ bool bigScreen = width >= 768;
late Duration time; return SizedBox(
late String readableTime; width: width,
late String reason; child: FutureBuilder(future: replayData, builder: (context, snapshot){
timeWeightedStatsAvaliable = true; late Duration time;
if (snapshot.connectionState != ConnectionState.done) return const LinearProgressIndicator(); late String readableTime;
if (!snapshot.hasError){ late String reason;
if (rounds.indexWhere((element) => element.value == -2) == -1) rounds.insert(1, DropdownMenuItem(value: -2, child: Text(t.timeWeightedmatch))); timeWeightedStatsAvaliable = true;
greenSidePlayer = snapshot.data!.endcontext.indexWhere((element) => element.userId == widget.initPlayerId); if (snapshot.connectionState != ConnectionState.done) return const LinearProgressIndicator();
redSidePlayer = snapshot.data!.endcontext.indexWhere((element) => element.userId != widget.initPlayerId); if (!snapshot.hasError){
if (roundSelector.isNegative){ if (rounds.indexWhere((element) => element.value == -2) == -1) rounds.insert(1, DropdownMenuItem(value: -2, child: Text(t.timeWeightedmatch)));
time = framesToTime(snapshot.data!.totalLength); greenSidePlayer = snapshot.data!.endcontext.indexWhere((element) => element.userId == widget.initPlayerId);
readableTime = "${t.matchLength}: ${time.inMinutes}:${secs.format(time.inMicroseconds /1000000 % 60)}"; redSidePlayer = snapshot.data!.endcontext.indexWhere((element) => element.userId != widget.initPlayerId);
if (roundSelector.isNegative){
time = framesToTime(snapshot.data!.totalLength);
readableTime = "${t.matchLength}: ${time.inMinutes}:${secs.format(time.inMicroseconds /1000000 % 60)}";
}else{
time = framesToTime(snapshot.data!.roundLengths[roundSelector]);
readableTime = "${t.roundLength}: ${time.inMinutes}:${secs.format(time.inMicroseconds /1000000 % 60)}\n${t.winner}: ${snapshot.data!.roundWinners[roundSelector][1]}";
}
}else{ }else{
time = framesToTime(snapshot.data!.roundLengths[roundSelector]); switch (snapshot.error.runtimeType){
readableTime = "${t.roundLength}: ${time.inMinutes}:${secs.format(time.inMicroseconds /1000000 % 60)}\n${t.winner}: ${snapshot.data!.roundWinners[roundSelector][1]}"; case ReplayNotAvalable:
reason = t.matchIsTooOld;
break;
case SzyNotFound:
reason = t.matchIsTooOld;
break;
case SzyForbidden:
reason = t.errors.replayRejected;
break;
case SzyTooManyRequests:
reason = t.errors.tooManyRequests;
break;
default:
reason = snapshot.error.toString();
break;
}
} }
}else{ return NestedScrollView(
switch (snapshot.error.runtimeType){ headerSliverBuilder: (context, value) {
case ReplayNotAvalable: return [
reason = t.matchIsTooOld; SliverToBoxAdapter(
break; child: Padding(
case SzyNotFound: padding: const EdgeInsets.fromLTRB(16, 16, 16, 32),
reason = t.matchIsTooOld; child: Row(
break; mainAxisAlignment: MainAxisAlignment.spaceBetween,
case SzyForbidden: crossAxisAlignment: CrossAxisAlignment.start,
reason = t.errors.replayRejected; children: [
break; Expanded(
case SzyTooManyRequests: child: Container(
reason = t.errors.tooManyRequests; decoration: BoxDecoration(
break; gradient: LinearGradient(
default: colors: const [Colors.green, Colors.transparent],
reason = snapshot.error.toString(); begin: Alignment.bottomCenter,
break; end: Alignment.topCenter,
} stops: [0.0, widget.record.endContext.firstWhere((element) => element.userId == widget.initPlayerId).success ? 0.4 : 0.0],
} )),
return NestedScrollView( child: Padding(
headerSliverBuilder: (context, value) { padding: const EdgeInsets.fromLTRB(8, 0, 8, 0),
return [ child: Column(children: [
SliverToBoxAdapter( Text(widget.record.endContext.firstWhere((element) => element.userId == widget.initPlayerId).username, style: bigScreen ? const TextStyle(
child: Padding( fontFamily: "Eurostile Round Extended",
padding: const EdgeInsets.fromLTRB(16, 16, 16, 32), fontSize: 28) : const TextStyle()),
child: Row( Text(widget.record.endContext.firstWhere((element) => element.userId == widget.initPlayerId).points.toString(), style: const TextStyle(
mainAxisAlignment: MainAxisAlignment.spaceBetween, fontFamily: "Eurostile Round Extended",
crossAxisAlignment: CrossAxisAlignment.start, fontSize: 42))
children: [ ]),
Expanded( ),
child: Container(
decoration: BoxDecoration(
gradient: LinearGradient(
colors: const [Colors.green, Colors.transparent],
begin: Alignment.bottomCenter,
end: Alignment.topCenter,
stops: [0.0, widget.record.endContext.firstWhere((element) => element.userId == widget.initPlayerId).success ? 0.4 : 0.0],
)),
child: Padding(
padding: const EdgeInsets.fromLTRB(8, 0, 8, 0),
child: Column(children: [
Text(widget.record.endContext.firstWhere((element) => element.userId == widget.initPlayerId).username, style: bigScreen ? const TextStyle(
fontFamily: "Eurostile Round Extended",
fontSize: 28) : const TextStyle()),
Text(widget.record.endContext.firstWhere((element) => element.userId == widget.initPlayerId).points.toString(), style: const TextStyle(
fontFamily: "Eurostile Round Extended",
fontSize: 42))
]),
), ),
), ),
), const Padding(
const Padding( padding: EdgeInsets.only(top: 16),
padding: EdgeInsets.only(top: 16), child: Text("VS"),
child: Text("VS"), ),
), Expanded(
Expanded( child: Container(
child: Container( decoration: BoxDecoration(
decoration: BoxDecoration( gradient: LinearGradient(
gradient: LinearGradient( colors: const [Colors.red, Colors.transparent],
colors: const [Colors.red, Colors.transparent], begin: Alignment.bottomCenter,
begin: Alignment.bottomCenter, end: Alignment.topCenter,
end: Alignment.topCenter, stops: [0.0, widget.record.endContext.firstWhere((element) => element.userId != widget.initPlayerId).success ? 0.4 : 0.0],
stops: [0.0, widget.record.endContext.firstWhere((element) => element.userId != widget.initPlayerId).success ? 0.4 : 0.0], )),
)), child: Padding(
child: Padding( padding: const EdgeInsets.fromLTRB(8, 0, 8, 0),
padding: const EdgeInsets.fromLTRB(8, 0, 8, 0), child: Column(children: [
child: Column(children: [ Text(widget.record.endContext.firstWhere((element) => element.userId != widget.initPlayerId).username, style: bigScreen ? const TextStyle(
Text(widget.record.endContext.firstWhere((element) => element.userId != widget.initPlayerId).username, style: bigScreen ? const TextStyle( fontFamily: "Eurostile Round Extended",
fontFamily: "Eurostile Round Extended", fontSize: 28) : const TextStyle()),
fontSize: 28) : const TextStyle()), Text(widget.record.endContext.firstWhere((element) => element.userId != widget.initPlayerId).points.toString(), style: const TextStyle(
Text(widget.record.endContext.firstWhere((element) => element.userId != widget.initPlayerId).points.toString(), style: const TextStyle( fontFamily: "Eurostile Round Extended",
fontFamily: "Eurostile Round Extended", fontSize: 42))
fontSize: 42)) ]),
]), ),
), ),
), ),
), ],
], ),
), ),
), ),
), if (showMobileSelector) SliverToBoxAdapter(
if (showMobileSelector) SliverToBoxAdapter( child: Center(
child: Center( child: Row(
child: Row( mainAxisSize: MainAxisSize.min,
mainAxisSize: MainAxisSize.min, crossAxisAlignment: CrossAxisAlignment.baseline,
crossAxisAlignment: CrossAxisAlignment.baseline, textBaseline: TextBaseline.alphabetic,
textBaseline: TextBaseline.alphabetic, children: [
children: [ Text("${t.statsFor}: ",
Text("${t.statsFor}: ", style: const TextStyle(color: Colors.white, fontSize: 25)),
style: const TextStyle(color: Colors.white, fontSize: 25)), DropdownButton(items: rounds, value: roundSelector, onChanged: ((value) {
DropdownButton(items: rounds, value: roundSelector, onChanged: ((value) { roundSelector = value;
roundSelector = value; setState(() {});
setState(() {}); }),),
}),), ],
], ),
), ),
), ),
), if (widget.record.ownId == widget.record.replayId && showMobileSelector) SliverToBoxAdapter(
if (widget.record.ownId == widget.record.replayId && showMobileSelector) SliverToBoxAdapter( child: Center(child: Text(t.p1nkl0bst3rAlert, textAlign: TextAlign.center)),
child: Center(child: Text(t.p1nkl0bst3rAlert, textAlign: TextAlign.center)), ),
), if (showMobileSelector) SliverToBoxAdapter(child: Center(child: Text(snapshot.hasError ? reason : readableTime, textAlign: TextAlign.center))),
if (showMobileSelector) SliverToBoxAdapter(child: Center(child: Text(snapshot.hasError ? reason : readableTime, textAlign: TextAlign.center))), const SliverToBoxAdapter(
const SliverToBoxAdapter( child: Divider(),
child: Divider(),
)
];
},
body: ListView(
children: [
Column(
children: [
CompareThingy(
label: "APM",
greenSide: (roundSelector == -2 && snapshot.hasData) ? snapshot.data!.timeWeightedStats[greenSidePlayer].apm :
roundSelector.isNegative ? widget.record.endContext.firstWhere((element) => element.userId == widget.initPlayerId).secondary : widget.record.endContext.firstWhere((element) => element.userId == widget.initPlayerId).secondaryTracking[roundSelector],
redSide: (roundSelector == -2 && snapshot.hasData) ? snapshot.data!.timeWeightedStats[redSidePlayer].apm :
roundSelector == -1 ? widget.record.endContext.firstWhere((element) => element.userId != widget.initPlayerId).secondary : widget.record.endContext.firstWhere((element) => element.userId != widget.initPlayerId).secondaryTracking[roundSelector],
fractionDigits: 2,
higherIsBetter: true,
),
CompareThingy(
label: "PPS",
greenSide: (roundSelector == -2 && snapshot.hasData) ? snapshot.data!.timeWeightedStats[greenSidePlayer].pps:
roundSelector.isNegative ? widget.record.endContext.firstWhere((element) => element.userId == widget.initPlayerId).tertiary : widget.record.endContext.firstWhere((element) => element.userId == widget.initPlayerId).tertiaryTracking[roundSelector],
redSide: (roundSelector == -2 && snapshot.hasData) ? snapshot.data!.timeWeightedStats[redSidePlayer].pps :
roundSelector.isNegative ? widget.record.endContext.firstWhere((element) => element.userId != widget.initPlayerId).tertiary: widget.record.endContext.firstWhere((element) => element.userId != widget.initPlayerId).tertiaryTracking[roundSelector],
fractionDigits: 2,
higherIsBetter: true,
),
CompareThingy(
label: "VS",
greenSide: (roundSelector == -2 && snapshot.hasData) ? snapshot.data!.timeWeightedStats[greenSidePlayer].vs :
roundSelector.isNegative ? widget.record.endContext.firstWhere((element) => element.userId == widget.initPlayerId).extra : widget.record.endContext.firstWhere((element) => element.userId == widget.initPlayerId).extraTracking[roundSelector],
redSide: (roundSelector == -2 && snapshot.hasData) ? snapshot.data!.timeWeightedStats[redSidePlayer].vs :
roundSelector.isNegative ? widget.record.endContext.firstWhere((element) => element.userId != widget.initPlayerId).extra : widget.record.endContext.firstWhere((element) => element.userId != widget.initPlayerId).extraTracking[roundSelector],
fractionDigits: 2,
higherIsBetter: true,
),
if (snapshot.hasData) Column(children: [
CompareThingy(greenSide: roundSelector.isNegative ? snapshot.data!.totalStats[greenSidePlayer].inputs : snapshot.data!.stats[roundSelector][greenSidePlayer].inputs,
redSide: roundSelector.isNegative ? snapshot.data!.totalStats[redSidePlayer].inputs : snapshot.data!.stats[roundSelector][redSidePlayer].inputs,
label: "Inputs", higherIsBetter: true),
CompareThingy(greenSide: roundSelector.isNegative ? snapshot.data!.totalStats[greenSidePlayer].piecesPlaced : snapshot.data!.stats[roundSelector][greenSidePlayer].piecesPlaced,
redSide: roundSelector.isNegative ? snapshot.data!.totalStats[redSidePlayer].piecesPlaced : snapshot.data!.stats[roundSelector][redSidePlayer].piecesPlaced,
label: "Pieces Placed", higherIsBetter: true),
CompareThingy(greenSide: (roundSelector == -2 && snapshot.hasData) ? snapshot.data!.timeWeightedStats[greenSidePlayer].kpp :
roundSelector.isNegative ? snapshot.data!.totalStats[greenSidePlayer].kpp : snapshot.data!.stats[roundSelector][greenSidePlayer].kpp,
redSide: (roundSelector == -2 && snapshot.hasData) ? snapshot.data!.timeWeightedStats[redSidePlayer].kpp :
roundSelector.isNegative ? snapshot.data!.totalStats[redSidePlayer].kpp : snapshot.data!.stats[roundSelector][redSidePlayer].kpp,
label: "KpP", higherIsBetter: false, fractionDigits: 2,),
CompareThingy(greenSide: (roundSelector == -2 && snapshot.hasData) ? snapshot.data!.timeWeightedStats[greenSidePlayer].kps :
roundSelector.isNegative ? snapshot.data!.totalStats[greenSidePlayer].kps : snapshot.data!.stats[roundSelector][greenSidePlayer].kps,
redSide: (roundSelector == -2 && snapshot.hasData) ? snapshot.data!.timeWeightedStats[redSidePlayer].kps :
roundSelector.isNegative ? snapshot.data!.totalStats[redSidePlayer].kps : snapshot.data!.stats[roundSelector][redSidePlayer].kps,
label: "KpS", higherIsBetter: true, fractionDigits: 2,),
CompareThingy(greenSide: roundSelector.isNegative ? snapshot.data!.totalStats[greenSidePlayer].linesCleared : snapshot.data!.stats[roundSelector][greenSidePlayer].linesCleared,
redSide: roundSelector.isNegative ? snapshot.data!.totalStats[redSidePlayer].linesCleared : snapshot.data!.stats[roundSelector][redSidePlayer].linesCleared,
label: "Lines Cleared", higherIsBetter: true),
CompareThingy(greenSide: roundSelector.isNegative ? snapshot.data!.totalStats[greenSidePlayer].score : snapshot.data!.stats[roundSelector][greenSidePlayer].score,
redSide: roundSelector.isNegative ? snapshot.data!.totalStats[redSidePlayer].score : snapshot.data!.stats[roundSelector][redSidePlayer].score,
label: "Score", higherIsBetter: true),
CompareThingy(greenSide: (roundSelector == -2 && snapshot.hasData) ? snapshot.data!.timeWeightedStats[greenSidePlayer].spp :
roundSelector.isNegative ? snapshot.data!.totalStats[greenSidePlayer].spp : snapshot.data!.stats[roundSelector][greenSidePlayer].spp,
redSide: (roundSelector == -2 && snapshot.hasData) ? snapshot.data!.timeWeightedStats[redSidePlayer].spp :
roundSelector.isNegative ? snapshot.data!.totalStats[redSidePlayer].spp : snapshot.data!.stats[roundSelector][redSidePlayer].spp,
label: "SpP", higherIsBetter: true, fractionDigits: 2,),
CompareThingy(greenSide: roundSelector.isNegative ? snapshot.data!.totalStats[greenSidePlayer].finessePercentage * 100 : snapshot.data!.stats[roundSelector][greenSidePlayer].finessePercentage * 100,
redSide: roundSelector.isNegative ? snapshot.data!.totalStats[redSidePlayer].finessePercentage * 100 : snapshot.data!.stats[roundSelector][redSidePlayer].finessePercentage * 100,
label: "Finnese", postfix: "%", fractionDigits: 2, higherIsBetter: true),
CompareThingy(greenSide: roundSelector.isNegative ? snapshot.data!.totalStats[greenSidePlayer].topSpike : snapshot.data!.stats[roundSelector][greenSidePlayer].topSpike,
redSide: roundSelector.isNegative ? snapshot.data!.totalStats[redSidePlayer].topSpike : snapshot.data!.stats[roundSelector][redSidePlayer].topSpike,
label: "Best Spike", higherIsBetter: true),
CompareThingy(greenSide: roundSelector.isNegative ? snapshot.data!.totalStats[greenSidePlayer].topCombo : snapshot.data!.stats[roundSelector][greenSidePlayer].topCombo,
redSide: roundSelector.isNegative ? snapshot.data!.totalStats[redSidePlayer].topCombo : snapshot.data!.stats[roundSelector][redSidePlayer].topCombo,
label: "Best Combo", higherIsBetter: true),
CompareThingy(greenSide: roundSelector.isNegative ? snapshot.data!.totalStats[greenSidePlayer].topBtB : snapshot.data!.stats[roundSelector][greenSidePlayer].topBtB,
redSide: roundSelector.isNegative ? snapshot.data!.totalStats[redSidePlayer].topBtB : snapshot.data!.stats[roundSelector][redSidePlayer].topBtB,
label: "Best BtB", higherIsBetter: true),
const Divider(),
Padding(
padding: const EdgeInsets.only(bottom: 16),
child: Text("Garbage", style: TextStyle(fontFamily: "Eurostile Round Extended", fontSize: bigScreen ? 42 : 28)),
),
CompareThingy(greenSide: roundSelector.isNegative ? snapshot.data!.totalStats[greenSidePlayer].garbage.sent : snapshot.data!.stats[roundSelector][greenSidePlayer].garbage.sent,
redSide: roundSelector.isNegative ? snapshot.data!.totalStats[redSidePlayer].garbage.sent : snapshot.data!.stats[roundSelector][redSidePlayer].garbage.sent,
label: "Sent", higherIsBetter: true),
CompareThingy(greenSide: roundSelector.isNegative ? snapshot.data!.totalStats[greenSidePlayer].garbage.recived : snapshot.data!.stats[roundSelector][greenSidePlayer].garbage.recived,
redSide: roundSelector.isNegative ? snapshot.data!.totalStats[redSidePlayer].garbage.recived : snapshot.data!.stats[roundSelector][redSidePlayer].garbage.recived,
label: "Recived", higherIsBetter: true),
CompareThingy(greenSide: roundSelector.isNegative ? snapshot.data!.totalStats[greenSidePlayer].garbage.attack : snapshot.data!.stats[roundSelector][greenSidePlayer].garbage.attack,
redSide: roundSelector.isNegative ? snapshot.data!.totalStats[redSidePlayer].garbage.attack : snapshot.data!.stats[roundSelector][redSidePlayer].garbage.attack,
label: "Attack", higherIsBetter: true),
CompareThingy(greenSide: roundSelector.isNegative ? snapshot.data!.totalStats[greenSidePlayer].garbage.cleared : snapshot.data!.stats[roundSelector][greenSidePlayer].garbage.cleared,
redSide: roundSelector.isNegative ? snapshot.data!.totalStats[redSidePlayer].garbage.cleared : snapshot.data!.stats[roundSelector][redSidePlayer].garbage.cleared,
label: "Cleared", higherIsBetter: true),
const Divider(),
Padding(
padding: const EdgeInsets.only(bottom: 16),
child: Text("Line Clears", style: TextStyle(fontFamily: "Eurostile Round Extended", fontSize: bigScreen ? 42 : 28)),
),
CompareThingy(greenSide: roundSelector.isNegative ? snapshot.data!.totalStats[greenSidePlayer].clears.allClears : snapshot.data!.stats[roundSelector][greenSidePlayer].clears.allClears,
redSide: roundSelector.isNegative ? snapshot.data!.totalStats[redSidePlayer].clears.allClears : snapshot.data!.stats[roundSelector][redSidePlayer].clears.allClears,
label: "PC", higherIsBetter: true),
CompareThingy(greenSide: roundSelector.isNegative ? snapshot.data!.totalStats[greenSidePlayer].tspins : snapshot.data!.stats[roundSelector][greenSidePlayer].tspins,
redSide: roundSelector.isNegative ? snapshot.data!.totalStats[redSidePlayer].tspins : snapshot.data!.stats[roundSelector][redSidePlayer].tspins,
label: "T-spins", higherIsBetter: true),
CompareThingy(greenSide: roundSelector.isNegative ? snapshot.data!.totalStats[greenSidePlayer].clears.quads : snapshot.data!.stats[roundSelector][greenSidePlayer].clears.quads,
redSide: roundSelector.isNegative ? snapshot.data!.totalStats[redSidePlayer].clears.quads : snapshot.data!.stats[roundSelector][redSidePlayer].clears.quads,
label: "Quads", higherIsBetter: true),
],),
],
),
const Divider(),
Column(
children: [
Padding(
padding: const EdgeInsets.only(bottom: 16),
child: Text(t.nerdStats,
style: TextStyle(
fontFamily: "Eurostile Round Extended",
fontSize: bigScreen ? 42 : 28)),
),
CompareThingy(
label: "APP",
greenSide: (roundSelector == -2 && snapshot.hasData) ? snapshot.data!.timeWeightedStats[greenSidePlayer].nerdStats.app :
roundSelector.isNegative ? widget.record.endContext.firstWhere((element) => element.userId == widget.initPlayerId).nerdStats.app : widget.record.endContext.firstWhere((element) => element.userId == widget.initPlayerId).nerdStatsTracking[roundSelector].app,
redSide: (roundSelector == -2 && snapshot.hasData) ? snapshot.data!.timeWeightedStats[redSidePlayer].nerdStats.app :
roundSelector.isNegative ? widget.record.endContext.firstWhere((element) => element.userId != widget.initPlayerId).nerdStats.app : widget.record.endContext.firstWhere((element) => element.userId != widget.initPlayerId).nerdStatsTracking[roundSelector].app,
fractionDigits: 3,
higherIsBetter: true,
),
CompareThingy(
label: "VS/APM",
greenSide: (roundSelector == -2 && snapshot.hasData) ? snapshot.data!.timeWeightedStats[greenSidePlayer].nerdStats.vsapm :
roundSelector.isNegative ? widget.record.endContext.firstWhere((element) => element.userId == widget.initPlayerId).nerdStats.vsapm : widget.record.endContext.firstWhere((element) => element.userId == widget.initPlayerId).nerdStatsTracking[roundSelector].vsapm,
redSide: (roundSelector == -2 && snapshot.hasData) ? snapshot.data!.timeWeightedStats[redSidePlayer].nerdStats.vsapm :
roundSelector.isNegative ? widget.record.endContext.firstWhere((element) => element.userId != widget.initPlayerId).nerdStats.vsapm : widget.record.endContext.firstWhere((element) => element.userId != widget.initPlayerId).nerdStatsTracking[roundSelector].vsapm,
fractionDigits: 3,
higherIsBetter: true,
),
CompareThingy(
label: "DS/S",
greenSide: (roundSelector == -2 && snapshot.hasData) ? snapshot.data!.timeWeightedStats[greenSidePlayer].nerdStats.dss :
roundSelector.isNegative ? widget.record.endContext.firstWhere((element) => element.userId == widget.initPlayerId).nerdStats.dss : widget.record.endContext.firstWhere((element) => element.userId == widget.initPlayerId).nerdStatsTracking[roundSelector].dss,
redSide: (roundSelector == -2 && snapshot.hasData) ? snapshot.data!.timeWeightedStats[redSidePlayer].nerdStats.dss :
roundSelector.isNegative ? widget.record.endContext.firstWhere((element) => element.userId != widget.initPlayerId).nerdStats.dss : widget.record.endContext.firstWhere((element) => element.userId != widget.initPlayerId).nerdStatsTracking[roundSelector].dss,
fractionDigits: 3,
higherIsBetter: true,
),
CompareThingy(
label: "DS/P",
greenSide: (roundSelector == -2 && snapshot.hasData) ? snapshot.data!.timeWeightedStats[greenSidePlayer].nerdStats.dsp :
roundSelector.isNegative ? widget.record.endContext.firstWhere((element) => element.userId == widget.initPlayerId).nerdStats.dsp : widget.record.endContext.firstWhere((element) => element.userId == widget.initPlayerId).nerdStatsTracking[roundSelector].dsp,
redSide: (roundSelector == -2 && snapshot.hasData) ? snapshot.data!.timeWeightedStats[redSidePlayer].nerdStats.dsp :
roundSelector.isNegative ? widget.record.endContext.firstWhere((element) => element.userId != widget.initPlayerId).nerdStats.dsp : widget.record.endContext.firstWhere((element) => element.userId != widget.initPlayerId).nerdStatsTracking[roundSelector].dsp,
fractionDigits: 3,
higherIsBetter: true,
),
CompareThingy(
label: "APP + DS/P",
greenSide: (roundSelector == -2 && snapshot.hasData) ? snapshot.data!.timeWeightedStats[greenSidePlayer].nerdStats.appdsp :
roundSelector.isNegative ? widget.record.endContext.firstWhere((element) => element.userId == widget.initPlayerId).nerdStats.appdsp : widget.record.endContext.firstWhere((element) => element.userId == widget.initPlayerId).nerdStatsTracking[roundSelector].appdsp,
redSide: (roundSelector == -2 && snapshot.hasData) ? snapshot.data!.timeWeightedStats[redSidePlayer].nerdStats.appdsp :
roundSelector.isNegative ? widget.record.endContext.firstWhere((element) => element.userId != widget.initPlayerId).nerdStats.appdsp : widget.record.endContext.firstWhere((element) => element.userId != widget.initPlayerId).nerdStatsTracking[roundSelector].appdsp,
fractionDigits: 3,
higherIsBetter: true,
),
CompareThingy(
label: t.statCellNum.cheese.replaceAll(RegExp(r'\n'), " "),
greenSide: (roundSelector == -2 && snapshot.hasData) ? snapshot.data!.timeWeightedStats[greenSidePlayer].nerdStats.cheese :
roundSelector.isNegative ? widget.record.endContext.firstWhere((element) => element.userId == widget.initPlayerId).nerdStats.cheese : widget.record.endContext.firstWhere((element) => element.userId == widget.initPlayerId).nerdStatsTracking[roundSelector].cheese,
redSide: (roundSelector == -2 && snapshot.hasData) ? snapshot.data!.timeWeightedStats[redSidePlayer].nerdStats.cheese :
roundSelector.isNegative ? widget.record.endContext.firstWhere((element) => element.userId != widget.initPlayerId).nerdStats.cheese : widget.record.endContext.firstWhere((element) => element.userId != widget.initPlayerId).nerdStatsTracking[roundSelector].cheese,
fractionDigits: 2,
higherIsBetter: false,
),
CompareThingy(
label: "Gb Eff.",
greenSide: (roundSelector == -2 && snapshot.hasData) ? snapshot.data!.timeWeightedStats[greenSidePlayer].nerdStats.gbe :
roundSelector.isNegative ? widget.record.endContext.firstWhere((element) => element.userId == widget.initPlayerId).nerdStats.gbe : widget.record.endContext.firstWhere((element) => element.userId == widget.initPlayerId).nerdStatsTracking[roundSelector].gbe,
redSide: (roundSelector == -2 && snapshot.hasData) ? snapshot.data!.timeWeightedStats[redSidePlayer].nerdStats.gbe :
roundSelector.isNegative ? widget.record.endContext.firstWhere((element) => element.userId != widget.initPlayerId).nerdStats.gbe : widget.record.endContext.firstWhere((element) => element.userId != widget.initPlayerId).nerdStatsTracking[roundSelector].gbe,
fractionDigits: 3,
higherIsBetter: true,
),
CompareThingy(
label: "wAPP",
greenSide: (roundSelector == -2 && snapshot.hasData) ? snapshot.data!.timeWeightedStats[greenSidePlayer].nerdStats.nyaapp :
roundSelector.isNegative ? widget.record.endContext.firstWhere((element) => element.userId == widget.initPlayerId).nerdStats.nyaapp : widget.record.endContext.firstWhere((element) => element.userId == widget.initPlayerId).nerdStatsTracking[roundSelector].nyaapp,
redSide: (roundSelector == -2 && snapshot.hasData) ? snapshot.data!.timeWeightedStats[redSidePlayer].nerdStats.nyaapp :
roundSelector.isNegative ? widget.record.endContext.firstWhere((element) => element.userId != widget.initPlayerId).nerdStats.nyaapp : widget.record.endContext.firstWhere((element) => element.userId != widget.initPlayerId).nerdStatsTracking[roundSelector].nyaapp,
fractionDigits: 3,
higherIsBetter: true,
),
CompareThingy(
label: "Area",
greenSide: (roundSelector == -2 && snapshot.hasData) ? snapshot.data!.timeWeightedStats[greenSidePlayer].nerdStats.area :
roundSelector.isNegative ? widget.record.endContext.firstWhere((element) => element.userId == widget.initPlayerId).nerdStats.area : widget.record.endContext.firstWhere((element) => element.userId == widget.initPlayerId).nerdStatsTracking[roundSelector].area,
redSide: (roundSelector == -2 && snapshot.hasData) ? snapshot.data!.timeWeightedStats[redSidePlayer].nerdStats.area :
roundSelector.isNegative ? widget.record.endContext.firstWhere((element) => element.userId != widget.initPlayerId).nerdStats.area : widget.record.endContext.firstWhere((element) => element.userId != widget.initPlayerId).nerdStatsTracking[roundSelector].area,
fractionDigits: 2,
higherIsBetter: true,
),
CompareThingy(
label: t.statCellNum.estOfTRShort,
greenSide: (roundSelector == -2 && snapshot.hasData) ? snapshot.data!.timeWeightedStats[greenSidePlayer].estTr.esttr :
roundSelector.isNegative ? widget.record.endContext.firstWhere((element) => element.userId == widget.initPlayerId).estTr.esttr : widget.record.endContext.firstWhere((element) => element.userId == widget.initPlayerId).estTrTracking[roundSelector].esttr,
redSide: (roundSelector == -2 && snapshot.hasData) ? snapshot.data!.timeWeightedStats[redSidePlayer].estTr.esttr :
roundSelector.isNegative ? widget.record.endContext.firstWhere((element) => element.userId != widget.initPlayerId).estTr.esttr : widget.record.endContext.firstWhere((element) => element.userId != widget.initPlayerId).estTrTracking[roundSelector].esttr,
fractionDigits: 2,
higherIsBetter: true,
),
CompareThingy(
label: "Opener",
greenSide: (roundSelector == -2 && snapshot.hasData) ? snapshot.data!.timeWeightedStats[greenSidePlayer].playstyle.opener :
roundSelector.isNegative ? widget.record.endContext.firstWhere((element) => element.userId == widget.initPlayerId).playstyle.opener : widget.record.endContext.firstWhere((element) => element.userId == widget.initPlayerId).playstyleTracking[roundSelector].opener,
redSide: (roundSelector == -2 && snapshot.hasData) ? snapshot.data!.timeWeightedStats[redSidePlayer].playstyle.opener :
roundSelector.isNegative ? widget.record.endContext.firstWhere((element) => element.userId != widget.initPlayerId).playstyle.opener : widget.record.endContext.firstWhere((element) => element.userId != widget.initPlayerId).playstyleTracking[roundSelector].opener,
fractionDigits: 3,
higherIsBetter: true,
),
CompareThingy(
label: "Plonk",
greenSide: (roundSelector == -2 && snapshot.hasData) ? snapshot.data!.timeWeightedStats[greenSidePlayer].playstyle.plonk :
roundSelector.isNegative ? widget.record.endContext.firstWhere((element) => element.userId == widget.initPlayerId).playstyle.plonk : widget.record.endContext.firstWhere((element) => element.userId == widget.initPlayerId).playstyleTracking[roundSelector].plonk,
redSide: (roundSelector == -2 && snapshot.hasData) ? snapshot.data!.timeWeightedStats[redSidePlayer].playstyle.plonk :
roundSelector.isNegative ? widget.record.endContext.firstWhere((element) => element.userId != widget.initPlayerId).playstyle.plonk : widget.record.endContext.firstWhere((element) => element.userId != widget.initPlayerId).playstyleTracking[roundSelector].plonk,
fractionDigits: 3,
higherIsBetter: true,
),
CompareThingy(
label: "Stride",
greenSide: (roundSelector == -2 && snapshot.hasData) ? snapshot.data!.timeWeightedStats[greenSidePlayer].playstyle.stride :
roundSelector.isNegative ? widget.record.endContext.firstWhere((element) => element.userId == widget.initPlayerId).playstyle.stride : widget.record.endContext.firstWhere((element) => element.userId == widget.initPlayerId).playstyleTracking[roundSelector].stride,
redSide: (roundSelector == -2 && snapshot.hasData) ? snapshot.data!.timeWeightedStats[redSidePlayer].playstyle.stride :
roundSelector.isNegative ? widget.record.endContext.firstWhere((element) => element.userId != widget.initPlayerId).playstyle.stride : widget.record.endContext.firstWhere((element) => element.userId != widget.initPlayerId).playstyleTracking[roundSelector].stride,
fractionDigits: 3,
higherIsBetter: true,
),
CompareThingy(
label: "Inf. DS",
greenSide: (roundSelector == -2 && snapshot.hasData) ? snapshot.data!.timeWeightedStats[greenSidePlayer].playstyle.infds :
roundSelector.isNegative ? widget.record.endContext.firstWhere((element) => element.userId == widget.initPlayerId).playstyle.infds : widget.record.endContext.firstWhere((element) => element.userId == widget.initPlayerId).playstyleTracking[roundSelector].infds,
redSide: (roundSelector == -2 && snapshot.hasData) ? snapshot.data!.timeWeightedStats[redSidePlayer].playstyle.infds :
roundSelector.isNegative ? widget.record.endContext.firstWhere((element) => element.userId != widget.initPlayerId).playstyle.infds : widget.record.endContext.firstWhere((element) => element.userId != widget.initPlayerId).playstyleTracking[roundSelector].infds,
fractionDigits: 3,
higherIsBetter: true,
),
VsGraphs(
(roundSelector == -2 && snapshot.hasData) ? snapshot.data!.timeWeightedStats[greenSidePlayer].apm : roundSelector.isNegative ? widget.record.endContext.firstWhere((element) => element.userId == widget.initPlayerId).secondary : widget.record.endContext.firstWhere((element) => element.userId == widget.initPlayerId).secondaryTracking[roundSelector],
(roundSelector == -2 && snapshot.hasData) ? snapshot.data!.timeWeightedStats[greenSidePlayer].pps : roundSelector.isNegative ? widget.record.endContext.firstWhere((element) => element.userId == widget.initPlayerId).tertiary : widget.record.endContext.firstWhere((element) => element.userId == widget.initPlayerId).tertiaryTracking[roundSelector],
(roundSelector == -2 && snapshot.hasData) ? snapshot.data!.timeWeightedStats[greenSidePlayer].vs : roundSelector.isNegative ? widget.record.endContext.firstWhere((element) => element.userId == widget.initPlayerId).extra : widget.record.endContext.firstWhere((element) => element.userId == widget.initPlayerId).extraTracking[roundSelector],
(roundSelector == -2 && snapshot.hasData) ? snapshot.data!.timeWeightedStats[greenSidePlayer].nerdStats : roundSelector.isNegative ? widget.record.endContext.firstWhere((element) => element.userId == widget.initPlayerId).nerdStats : widget.record.endContext.firstWhere((element) => element.userId == widget.initPlayerId).nerdStatsTracking[roundSelector],
(roundSelector == -2 && snapshot.hasData) ? snapshot.data!.timeWeightedStats[greenSidePlayer].playstyle : roundSelector.isNegative ? widget.record.endContext.firstWhere((element) => element.userId == widget.initPlayerId).playstyle : widget.record.endContext.firstWhere((element) => element.userId == widget.initPlayerId).playstyleTracking[roundSelector],
(roundSelector == -2 && snapshot.hasData) ? snapshot.data!.timeWeightedStats[redSidePlayer].apm : roundSelector.isNegative ? widget.record.endContext.firstWhere((element) => element.userId != widget.initPlayerId).secondary : widget.record.endContext.firstWhere((element) => element.userId != widget.initPlayerId).secondaryTracking[roundSelector],
(roundSelector == -2 && snapshot.hasData) ? snapshot.data!.timeWeightedStats[redSidePlayer].pps : roundSelector.isNegative ? widget.record.endContext.firstWhere((element) => element.userId != widget.initPlayerId).tertiary : widget.record.endContext.firstWhere((element) => element.userId != widget.initPlayerId).tertiaryTracking[roundSelector],
(roundSelector == -2 && snapshot.hasData) ? snapshot.data!.timeWeightedStats[redSidePlayer].vs : roundSelector.isNegative ? widget.record.endContext.firstWhere((element) => element.userId != widget.initPlayerId).extra : widget.record.endContext.firstWhere((element) => element.userId != widget.initPlayerId).extraTracking[roundSelector],
(roundSelector == -2 && snapshot.hasData) ? snapshot.data!.timeWeightedStats[redSidePlayer].nerdStats : roundSelector.isNegative ? widget.record.endContext.firstWhere((element) => element.userId != widget.initPlayerId).nerdStats : widget.record.endContext.firstWhere((element) => element.userId != widget.initPlayerId).nerdStatsTracking[roundSelector],
(roundSelector == -2 && snapshot.hasData) ? snapshot.data!.timeWeightedStats[redSidePlayer].playstyle : roundSelector.isNegative ? widget.record.endContext.firstWhere((element) => element.userId != widget.initPlayerId).playstyle : widget.record.endContext.firstWhere((element) => element.userId != widget.initPlayerId).playstyleTracking[roundSelector]
)
],
),
if (widget.record.ownId != widget.record.replayId) const Divider(),
if (widget.record.ownId != widget.record.replayId) Column(
children: [
Padding(
padding: const EdgeInsets.only(bottom: 16),
child: Text("Handling",
style: TextStyle(
fontFamily: "Eurostile Round Extended",
fontSize: bigScreen ? 42 : 28)),
),
CompareThingy(
greenSide: widget.record.endContext.firstWhere((element) => element.userId == widget.initPlayerId).handling.das,
redSide: widget.record.endContext.firstWhere((element) => element.userId != widget.initPlayerId).handling.das,
label: "DAS", fractionDigits: 1, postfix: "F",
higherIsBetter: false),
CompareThingy(
greenSide: widget.record.endContext.firstWhere((element) => element.userId == widget.initPlayerId).handling.arr,
redSide: widget.record.endContext.firstWhere((element) => element.userId != widget.initPlayerId).handling.arr,
label: "ARR", fractionDigits: 1, postfix: "F",
higherIsBetter: false),
CompareThingy(
greenSide: widget.record.endContext.firstWhere((element) => element.userId == widget.initPlayerId).handling.sdf,
redSide: widget.record.endContext.firstWhere((element) => element.userId != widget.initPlayerId).handling.sdf,
label: "SDF", prefix: "x",
higherIsBetter: true),
CompareBoolThingy(
greenSide: widget.record.endContext.firstWhere((element) => element.userId == widget.initPlayerId).handling.safeLock,
redSide: widget.record.endContext.firstWhere((element) => element.userId != widget.initPlayerId).handling.safeLock,
label: "Safe HD",
trueIsBetter: true)
],
)
],
) )
); ];
}); },
body: ListView(
children: [
Column(
children: [
CompareThingy(
label: "APM",
greenSide: (roundSelector == -2 && snapshot.hasData) ? snapshot.data!.timeWeightedStats[greenSidePlayer].apm :
roundSelector.isNegative ? widget.record.endContext.firstWhere((element) => element.userId == widget.initPlayerId).secondary : widget.record.endContext.firstWhere((element) => element.userId == widget.initPlayerId).secondaryTracking[roundSelector],
redSide: (roundSelector == -2 && snapshot.hasData) ? snapshot.data!.timeWeightedStats[redSidePlayer].apm :
roundSelector == -1 ? widget.record.endContext.firstWhere((element) => element.userId != widget.initPlayerId).secondary : widget.record.endContext.firstWhere((element) => element.userId != widget.initPlayerId).secondaryTracking[roundSelector],
fractionDigits: 2,
higherIsBetter: true,
),
CompareThingy(
label: "PPS",
greenSide: (roundSelector == -2 && snapshot.hasData) ? snapshot.data!.timeWeightedStats[greenSidePlayer].pps:
roundSelector.isNegative ? widget.record.endContext.firstWhere((element) => element.userId == widget.initPlayerId).tertiary : widget.record.endContext.firstWhere((element) => element.userId == widget.initPlayerId).tertiaryTracking[roundSelector],
redSide: (roundSelector == -2 && snapshot.hasData) ? snapshot.data!.timeWeightedStats[redSidePlayer].pps :
roundSelector.isNegative ? widget.record.endContext.firstWhere((element) => element.userId != widget.initPlayerId).tertiary: widget.record.endContext.firstWhere((element) => element.userId != widget.initPlayerId).tertiaryTracking[roundSelector],
fractionDigits: 2,
higherIsBetter: true,
),
CompareThingy(
label: "VS",
greenSide: (roundSelector == -2 && snapshot.hasData) ? snapshot.data!.timeWeightedStats[greenSidePlayer].vs :
roundSelector.isNegative ? widget.record.endContext.firstWhere((element) => element.userId == widget.initPlayerId).extra : widget.record.endContext.firstWhere((element) => element.userId == widget.initPlayerId).extraTracking[roundSelector],
redSide: (roundSelector == -2 && snapshot.hasData) ? snapshot.data!.timeWeightedStats[redSidePlayer].vs :
roundSelector.isNegative ? widget.record.endContext.firstWhere((element) => element.userId != widget.initPlayerId).extra : widget.record.endContext.firstWhere((element) => element.userId != widget.initPlayerId).extraTracking[roundSelector],
fractionDigits: 2,
higherIsBetter: true,
),
if (snapshot.hasData) Column(children: [
CompareThingy(greenSide: roundSelector.isNegative ? snapshot.data!.totalStats[greenSidePlayer].inputs : snapshot.data!.stats[roundSelector][greenSidePlayer].inputs,
redSide: roundSelector.isNegative ? snapshot.data!.totalStats[redSidePlayer].inputs : snapshot.data!.stats[roundSelector][redSidePlayer].inputs,
label: "Inputs", higherIsBetter: true),
CompareThingy(greenSide: roundSelector.isNegative ? snapshot.data!.totalStats[greenSidePlayer].piecesPlaced : snapshot.data!.stats[roundSelector][greenSidePlayer].piecesPlaced,
redSide: roundSelector.isNegative ? snapshot.data!.totalStats[redSidePlayer].piecesPlaced : snapshot.data!.stats[roundSelector][redSidePlayer].piecesPlaced,
label: "Pieces Placed", higherIsBetter: true),
CompareThingy(greenSide: (roundSelector == -2 && snapshot.hasData) ? snapshot.data!.timeWeightedStats[greenSidePlayer].kpp :
roundSelector.isNegative ? snapshot.data!.totalStats[greenSidePlayer].kpp : snapshot.data!.stats[roundSelector][greenSidePlayer].kpp,
redSide: (roundSelector == -2 && snapshot.hasData) ? snapshot.data!.timeWeightedStats[redSidePlayer].kpp :
roundSelector.isNegative ? snapshot.data!.totalStats[redSidePlayer].kpp : snapshot.data!.stats[roundSelector][redSidePlayer].kpp,
label: "KpP", higherIsBetter: false, fractionDigits: 2,),
CompareThingy(greenSide: (roundSelector == -2 && snapshot.hasData) ? snapshot.data!.timeWeightedStats[greenSidePlayer].kps :
roundSelector.isNegative ? snapshot.data!.totalStats[greenSidePlayer].kps : snapshot.data!.stats[roundSelector][greenSidePlayer].kps,
redSide: (roundSelector == -2 && snapshot.hasData) ? snapshot.data!.timeWeightedStats[redSidePlayer].kps :
roundSelector.isNegative ? snapshot.data!.totalStats[redSidePlayer].kps : snapshot.data!.stats[roundSelector][redSidePlayer].kps,
label: "KpS", higherIsBetter: true, fractionDigits: 2,),
CompareThingy(greenSide: roundSelector.isNegative ? snapshot.data!.totalStats[greenSidePlayer].linesCleared : snapshot.data!.stats[roundSelector][greenSidePlayer].linesCleared,
redSide: roundSelector.isNegative ? snapshot.data!.totalStats[redSidePlayer].linesCleared : snapshot.data!.stats[roundSelector][redSidePlayer].linesCleared,
label: "Lines Cleared", higherIsBetter: true),
CompareThingy(greenSide: roundSelector.isNegative ? snapshot.data!.totalStats[greenSidePlayer].score : snapshot.data!.stats[roundSelector][greenSidePlayer].score,
redSide: roundSelector.isNegative ? snapshot.data!.totalStats[redSidePlayer].score : snapshot.data!.stats[roundSelector][redSidePlayer].score,
label: "Score", higherIsBetter: true),
CompareThingy(greenSide: (roundSelector == -2 && snapshot.hasData) ? snapshot.data!.timeWeightedStats[greenSidePlayer].spp :
roundSelector.isNegative ? snapshot.data!.totalStats[greenSidePlayer].spp : snapshot.data!.stats[roundSelector][greenSidePlayer].spp,
redSide: (roundSelector == -2 && snapshot.hasData) ? snapshot.data!.timeWeightedStats[redSidePlayer].spp :
roundSelector.isNegative ? snapshot.data!.totalStats[redSidePlayer].spp : snapshot.data!.stats[roundSelector][redSidePlayer].spp,
label: "SpP", higherIsBetter: true, fractionDigits: 2,),
CompareThingy(greenSide: roundSelector.isNegative ? snapshot.data!.totalStats[greenSidePlayer].finessePercentage * 100 : snapshot.data!.stats[roundSelector][greenSidePlayer].finessePercentage * 100,
redSide: roundSelector.isNegative ? snapshot.data!.totalStats[redSidePlayer].finessePercentage * 100 : snapshot.data!.stats[roundSelector][redSidePlayer].finessePercentage * 100,
label: "Finnese", postfix: "%", fractionDigits: 2, higherIsBetter: true),
CompareThingy(greenSide: roundSelector.isNegative ? snapshot.data!.totalStats[greenSidePlayer].topSpike : snapshot.data!.stats[roundSelector][greenSidePlayer].topSpike,
redSide: roundSelector.isNegative ? snapshot.data!.totalStats[redSidePlayer].topSpike : snapshot.data!.stats[roundSelector][redSidePlayer].topSpike,
label: "Best Spike", higherIsBetter: true),
CompareThingy(greenSide: roundSelector.isNegative ? snapshot.data!.totalStats[greenSidePlayer].topCombo : snapshot.data!.stats[roundSelector][greenSidePlayer].topCombo,
redSide: roundSelector.isNegative ? snapshot.data!.totalStats[redSidePlayer].topCombo : snapshot.data!.stats[roundSelector][redSidePlayer].topCombo,
label: "Best Combo", higherIsBetter: true),
CompareThingy(greenSide: roundSelector.isNegative ? snapshot.data!.totalStats[greenSidePlayer].topBtB : snapshot.data!.stats[roundSelector][greenSidePlayer].topBtB,
redSide: roundSelector.isNegative ? snapshot.data!.totalStats[redSidePlayer].topBtB : snapshot.data!.stats[roundSelector][redSidePlayer].topBtB,
label: "Best BtB", higherIsBetter: true),
const Divider(),
Padding(
padding: const EdgeInsets.only(bottom: 16),
child: Text("Garbage", style: TextStyle(fontFamily: "Eurostile Round Extended", fontSize: bigScreen ? 42 : 28)),
),
CompareThingy(greenSide: roundSelector.isNegative ? snapshot.data!.totalStats[greenSidePlayer].garbage.sent : snapshot.data!.stats[roundSelector][greenSidePlayer].garbage.sent,
redSide: roundSelector.isNegative ? snapshot.data!.totalStats[redSidePlayer].garbage.sent : snapshot.data!.stats[roundSelector][redSidePlayer].garbage.sent,
label: "Sent", higherIsBetter: true),
CompareThingy(greenSide: roundSelector.isNegative ? snapshot.data!.totalStats[greenSidePlayer].garbage.recived : snapshot.data!.stats[roundSelector][greenSidePlayer].garbage.recived,
redSide: roundSelector.isNegative ? snapshot.data!.totalStats[redSidePlayer].garbage.recived : snapshot.data!.stats[roundSelector][redSidePlayer].garbage.recived,
label: "Recived", higherIsBetter: true),
CompareThingy(greenSide: roundSelector.isNegative ? snapshot.data!.totalStats[greenSidePlayer].garbage.attack : snapshot.data!.stats[roundSelector][greenSidePlayer].garbage.attack,
redSide: roundSelector.isNegative ? snapshot.data!.totalStats[redSidePlayer].garbage.attack : snapshot.data!.stats[roundSelector][redSidePlayer].garbage.attack,
label: "Attack", higherIsBetter: true),
CompareThingy(greenSide: roundSelector.isNegative ? snapshot.data!.totalStats[greenSidePlayer].garbage.cleared : snapshot.data!.stats[roundSelector][greenSidePlayer].garbage.cleared,
redSide: roundSelector.isNegative ? snapshot.data!.totalStats[redSidePlayer].garbage.cleared : snapshot.data!.stats[roundSelector][redSidePlayer].garbage.cleared,
label: "Cleared", higherIsBetter: true),
const Divider(),
Padding(
padding: const EdgeInsets.only(bottom: 16),
child: Text("Line Clears", style: TextStyle(fontFamily: "Eurostile Round Extended", fontSize: bigScreen ? 42 : 28)),
),
CompareThingy(greenSide: roundSelector.isNegative ? snapshot.data!.totalStats[greenSidePlayer].clears.allClears : snapshot.data!.stats[roundSelector][greenSidePlayer].clears.allClears,
redSide: roundSelector.isNegative ? snapshot.data!.totalStats[redSidePlayer].clears.allClears : snapshot.data!.stats[roundSelector][redSidePlayer].clears.allClears,
label: "PC", higherIsBetter: true),
CompareThingy(greenSide: roundSelector.isNegative ? snapshot.data!.totalStats[greenSidePlayer].tspins : snapshot.data!.stats[roundSelector][greenSidePlayer].tspins,
redSide: roundSelector.isNegative ? snapshot.data!.totalStats[redSidePlayer].tspins : snapshot.data!.stats[roundSelector][redSidePlayer].tspins,
label: "T-spins", higherIsBetter: true),
CompareThingy(greenSide: roundSelector.isNegative ? snapshot.data!.totalStats[greenSidePlayer].clears.quads : snapshot.data!.stats[roundSelector][greenSidePlayer].clears.quads,
redSide: roundSelector.isNegative ? snapshot.data!.totalStats[redSidePlayer].clears.quads : snapshot.data!.stats[roundSelector][redSidePlayer].clears.quads,
label: "Quads", higherIsBetter: true),
],),
],
),
const Divider(),
Column(
children: [
Padding(
padding: const EdgeInsets.only(bottom: 16),
child: Text(t.nerdStats,
style: TextStyle(
fontFamily: "Eurostile Round Extended",
fontSize: bigScreen ? 42 : 28)),
),
CompareThingy(
label: "APP",
greenSide: (roundSelector == -2 && snapshot.hasData) ? snapshot.data!.timeWeightedStats[greenSidePlayer].nerdStats.app :
roundSelector.isNegative ? widget.record.endContext.firstWhere((element) => element.userId == widget.initPlayerId).nerdStats.app : widget.record.endContext.firstWhere((element) => element.userId == widget.initPlayerId).nerdStatsTracking[roundSelector].app,
redSide: (roundSelector == -2 && snapshot.hasData) ? snapshot.data!.timeWeightedStats[redSidePlayer].nerdStats.app :
roundSelector.isNegative ? widget.record.endContext.firstWhere((element) => element.userId != widget.initPlayerId).nerdStats.app : widget.record.endContext.firstWhere((element) => element.userId != widget.initPlayerId).nerdStatsTracking[roundSelector].app,
fractionDigits: 3,
higherIsBetter: true,
),
CompareThingy(
label: "VS/APM",
greenSide: (roundSelector == -2 && snapshot.hasData) ? snapshot.data!.timeWeightedStats[greenSidePlayer].nerdStats.vsapm :
roundSelector.isNegative ? widget.record.endContext.firstWhere((element) => element.userId == widget.initPlayerId).nerdStats.vsapm : widget.record.endContext.firstWhere((element) => element.userId == widget.initPlayerId).nerdStatsTracking[roundSelector].vsapm,
redSide: (roundSelector == -2 && snapshot.hasData) ? snapshot.data!.timeWeightedStats[redSidePlayer].nerdStats.vsapm :
roundSelector.isNegative ? widget.record.endContext.firstWhere((element) => element.userId != widget.initPlayerId).nerdStats.vsapm : widget.record.endContext.firstWhere((element) => element.userId != widget.initPlayerId).nerdStatsTracking[roundSelector].vsapm,
fractionDigits: 3,
higherIsBetter: true,
),
CompareThingy(
label: "DS/S",
greenSide: (roundSelector == -2 && snapshot.hasData) ? snapshot.data!.timeWeightedStats[greenSidePlayer].nerdStats.dss :
roundSelector.isNegative ? widget.record.endContext.firstWhere((element) => element.userId == widget.initPlayerId).nerdStats.dss : widget.record.endContext.firstWhere((element) => element.userId == widget.initPlayerId).nerdStatsTracking[roundSelector].dss,
redSide: (roundSelector == -2 && snapshot.hasData) ? snapshot.data!.timeWeightedStats[redSidePlayer].nerdStats.dss :
roundSelector.isNegative ? widget.record.endContext.firstWhere((element) => element.userId != widget.initPlayerId).nerdStats.dss : widget.record.endContext.firstWhere((element) => element.userId != widget.initPlayerId).nerdStatsTracking[roundSelector].dss,
fractionDigits: 3,
higherIsBetter: true,
),
CompareThingy(
label: "DS/P",
greenSide: (roundSelector == -2 && snapshot.hasData) ? snapshot.data!.timeWeightedStats[greenSidePlayer].nerdStats.dsp :
roundSelector.isNegative ? widget.record.endContext.firstWhere((element) => element.userId == widget.initPlayerId).nerdStats.dsp : widget.record.endContext.firstWhere((element) => element.userId == widget.initPlayerId).nerdStatsTracking[roundSelector].dsp,
redSide: (roundSelector == -2 && snapshot.hasData) ? snapshot.data!.timeWeightedStats[redSidePlayer].nerdStats.dsp :
roundSelector.isNegative ? widget.record.endContext.firstWhere((element) => element.userId != widget.initPlayerId).nerdStats.dsp : widget.record.endContext.firstWhere((element) => element.userId != widget.initPlayerId).nerdStatsTracking[roundSelector].dsp,
fractionDigits: 3,
higherIsBetter: true,
),
CompareThingy(
label: "APP + DS/P",
greenSide: (roundSelector == -2 && snapshot.hasData) ? snapshot.data!.timeWeightedStats[greenSidePlayer].nerdStats.appdsp :
roundSelector.isNegative ? widget.record.endContext.firstWhere((element) => element.userId == widget.initPlayerId).nerdStats.appdsp : widget.record.endContext.firstWhere((element) => element.userId == widget.initPlayerId).nerdStatsTracking[roundSelector].appdsp,
redSide: (roundSelector == -2 && snapshot.hasData) ? snapshot.data!.timeWeightedStats[redSidePlayer].nerdStats.appdsp :
roundSelector.isNegative ? widget.record.endContext.firstWhere((element) => element.userId != widget.initPlayerId).nerdStats.appdsp : widget.record.endContext.firstWhere((element) => element.userId != widget.initPlayerId).nerdStatsTracking[roundSelector].appdsp,
fractionDigits: 3,
higherIsBetter: true,
),
CompareThingy(
label: t.statCellNum.cheese.replaceAll(RegExp(r'\n'), " "),
greenSide: (roundSelector == -2 && snapshot.hasData) ? snapshot.data!.timeWeightedStats[greenSidePlayer].nerdStats.cheese :
roundSelector.isNegative ? widget.record.endContext.firstWhere((element) => element.userId == widget.initPlayerId).nerdStats.cheese : widget.record.endContext.firstWhere((element) => element.userId == widget.initPlayerId).nerdStatsTracking[roundSelector].cheese,
redSide: (roundSelector == -2 && snapshot.hasData) ? snapshot.data!.timeWeightedStats[redSidePlayer].nerdStats.cheese :
roundSelector.isNegative ? widget.record.endContext.firstWhere((element) => element.userId != widget.initPlayerId).nerdStats.cheese : widget.record.endContext.firstWhere((element) => element.userId != widget.initPlayerId).nerdStatsTracking[roundSelector].cheese,
fractionDigits: 2,
higherIsBetter: false,
),
CompareThingy(
label: "Gb Eff.",
greenSide: (roundSelector == -2 && snapshot.hasData) ? snapshot.data!.timeWeightedStats[greenSidePlayer].nerdStats.gbe :
roundSelector.isNegative ? widget.record.endContext.firstWhere((element) => element.userId == widget.initPlayerId).nerdStats.gbe : widget.record.endContext.firstWhere((element) => element.userId == widget.initPlayerId).nerdStatsTracking[roundSelector].gbe,
redSide: (roundSelector == -2 && snapshot.hasData) ? snapshot.data!.timeWeightedStats[redSidePlayer].nerdStats.gbe :
roundSelector.isNegative ? widget.record.endContext.firstWhere((element) => element.userId != widget.initPlayerId).nerdStats.gbe : widget.record.endContext.firstWhere((element) => element.userId != widget.initPlayerId).nerdStatsTracking[roundSelector].gbe,
fractionDigits: 3,
higherIsBetter: true,
),
CompareThingy(
label: "wAPP",
greenSide: (roundSelector == -2 && snapshot.hasData) ? snapshot.data!.timeWeightedStats[greenSidePlayer].nerdStats.nyaapp :
roundSelector.isNegative ? widget.record.endContext.firstWhere((element) => element.userId == widget.initPlayerId).nerdStats.nyaapp : widget.record.endContext.firstWhere((element) => element.userId == widget.initPlayerId).nerdStatsTracking[roundSelector].nyaapp,
redSide: (roundSelector == -2 && snapshot.hasData) ? snapshot.data!.timeWeightedStats[redSidePlayer].nerdStats.nyaapp :
roundSelector.isNegative ? widget.record.endContext.firstWhere((element) => element.userId != widget.initPlayerId).nerdStats.nyaapp : widget.record.endContext.firstWhere((element) => element.userId != widget.initPlayerId).nerdStatsTracking[roundSelector].nyaapp,
fractionDigits: 3,
higherIsBetter: true,
),
CompareThingy(
label: "Area",
greenSide: (roundSelector == -2 && snapshot.hasData) ? snapshot.data!.timeWeightedStats[greenSidePlayer].nerdStats.area :
roundSelector.isNegative ? widget.record.endContext.firstWhere((element) => element.userId == widget.initPlayerId).nerdStats.area : widget.record.endContext.firstWhere((element) => element.userId == widget.initPlayerId).nerdStatsTracking[roundSelector].area,
redSide: (roundSelector == -2 && snapshot.hasData) ? snapshot.data!.timeWeightedStats[redSidePlayer].nerdStats.area :
roundSelector.isNegative ? widget.record.endContext.firstWhere((element) => element.userId != widget.initPlayerId).nerdStats.area : widget.record.endContext.firstWhere((element) => element.userId != widget.initPlayerId).nerdStatsTracking[roundSelector].area,
fractionDigits: 2,
higherIsBetter: true,
),
CompareThingy(
label: t.statCellNum.estOfTRShort,
greenSide: (roundSelector == -2 && snapshot.hasData) ? snapshot.data!.timeWeightedStats[greenSidePlayer].estTr.esttr :
roundSelector.isNegative ? widget.record.endContext.firstWhere((element) => element.userId == widget.initPlayerId).estTr.esttr : widget.record.endContext.firstWhere((element) => element.userId == widget.initPlayerId).estTrTracking[roundSelector].esttr,
redSide: (roundSelector == -2 && snapshot.hasData) ? snapshot.data!.timeWeightedStats[redSidePlayer].estTr.esttr :
roundSelector.isNegative ? widget.record.endContext.firstWhere((element) => element.userId != widget.initPlayerId).estTr.esttr : widget.record.endContext.firstWhere((element) => element.userId != widget.initPlayerId).estTrTracking[roundSelector].esttr,
fractionDigits: 2,
higherIsBetter: true,
),
CompareThingy(
label: "Opener",
greenSide: (roundSelector == -2 && snapshot.hasData) ? snapshot.data!.timeWeightedStats[greenSidePlayer].playstyle.opener :
roundSelector.isNegative ? widget.record.endContext.firstWhere((element) => element.userId == widget.initPlayerId).playstyle.opener : widget.record.endContext.firstWhere((element) => element.userId == widget.initPlayerId).playstyleTracking[roundSelector].opener,
redSide: (roundSelector == -2 && snapshot.hasData) ? snapshot.data!.timeWeightedStats[redSidePlayer].playstyle.opener :
roundSelector.isNegative ? widget.record.endContext.firstWhere((element) => element.userId != widget.initPlayerId).playstyle.opener : widget.record.endContext.firstWhere((element) => element.userId != widget.initPlayerId).playstyleTracking[roundSelector].opener,
fractionDigits: 3,
higherIsBetter: true,
),
CompareThingy(
label: "Plonk",
greenSide: (roundSelector == -2 && snapshot.hasData) ? snapshot.data!.timeWeightedStats[greenSidePlayer].playstyle.plonk :
roundSelector.isNegative ? widget.record.endContext.firstWhere((element) => element.userId == widget.initPlayerId).playstyle.plonk : widget.record.endContext.firstWhere((element) => element.userId == widget.initPlayerId).playstyleTracking[roundSelector].plonk,
redSide: (roundSelector == -2 && snapshot.hasData) ? snapshot.data!.timeWeightedStats[redSidePlayer].playstyle.plonk :
roundSelector.isNegative ? widget.record.endContext.firstWhere((element) => element.userId != widget.initPlayerId).playstyle.plonk : widget.record.endContext.firstWhere((element) => element.userId != widget.initPlayerId).playstyleTracking[roundSelector].plonk,
fractionDigits: 3,
higherIsBetter: true,
),
CompareThingy(
label: "Stride",
greenSide: (roundSelector == -2 && snapshot.hasData) ? snapshot.data!.timeWeightedStats[greenSidePlayer].playstyle.stride :
roundSelector.isNegative ? widget.record.endContext.firstWhere((element) => element.userId == widget.initPlayerId).playstyle.stride : widget.record.endContext.firstWhere((element) => element.userId == widget.initPlayerId).playstyleTracking[roundSelector].stride,
redSide: (roundSelector == -2 && snapshot.hasData) ? snapshot.data!.timeWeightedStats[redSidePlayer].playstyle.stride :
roundSelector.isNegative ? widget.record.endContext.firstWhere((element) => element.userId != widget.initPlayerId).playstyle.stride : widget.record.endContext.firstWhere((element) => element.userId != widget.initPlayerId).playstyleTracking[roundSelector].stride,
fractionDigits: 3,
higherIsBetter: true,
),
CompareThingy(
label: "Inf. DS",
greenSide: (roundSelector == -2 && snapshot.hasData) ? snapshot.data!.timeWeightedStats[greenSidePlayer].playstyle.infds :
roundSelector.isNegative ? widget.record.endContext.firstWhere((element) => element.userId == widget.initPlayerId).playstyle.infds : widget.record.endContext.firstWhere((element) => element.userId == widget.initPlayerId).playstyleTracking[roundSelector].infds,
redSide: (roundSelector == -2 && snapshot.hasData) ? snapshot.data!.timeWeightedStats[redSidePlayer].playstyle.infds :
roundSelector.isNegative ? widget.record.endContext.firstWhere((element) => element.userId != widget.initPlayerId).playstyle.infds : widget.record.endContext.firstWhere((element) => element.userId != widget.initPlayerId).playstyleTracking[roundSelector].infds,
fractionDigits: 3,
higherIsBetter: true,
),
VsGraphs(
(roundSelector == -2 && snapshot.hasData) ? snapshot.data!.timeWeightedStats[greenSidePlayer].apm : roundSelector.isNegative ? widget.record.endContext.firstWhere((element) => element.userId == widget.initPlayerId).secondary : widget.record.endContext.firstWhere((element) => element.userId == widget.initPlayerId).secondaryTracking[roundSelector],
(roundSelector == -2 && snapshot.hasData) ? snapshot.data!.timeWeightedStats[greenSidePlayer].pps : roundSelector.isNegative ? widget.record.endContext.firstWhere((element) => element.userId == widget.initPlayerId).tertiary : widget.record.endContext.firstWhere((element) => element.userId == widget.initPlayerId).tertiaryTracking[roundSelector],
(roundSelector == -2 && snapshot.hasData) ? snapshot.data!.timeWeightedStats[greenSidePlayer].vs : roundSelector.isNegative ? widget.record.endContext.firstWhere((element) => element.userId == widget.initPlayerId).extra : widget.record.endContext.firstWhere((element) => element.userId == widget.initPlayerId).extraTracking[roundSelector],
(roundSelector == -2 && snapshot.hasData) ? snapshot.data!.timeWeightedStats[greenSidePlayer].nerdStats : roundSelector.isNegative ? widget.record.endContext.firstWhere((element) => element.userId == widget.initPlayerId).nerdStats : widget.record.endContext.firstWhere((element) => element.userId == widget.initPlayerId).nerdStatsTracking[roundSelector],
(roundSelector == -2 && snapshot.hasData) ? snapshot.data!.timeWeightedStats[greenSidePlayer].playstyle : roundSelector.isNegative ? widget.record.endContext.firstWhere((element) => element.userId == widget.initPlayerId).playstyle : widget.record.endContext.firstWhere((element) => element.userId == widget.initPlayerId).playstyleTracking[roundSelector],
(roundSelector == -2 && snapshot.hasData) ? snapshot.data!.timeWeightedStats[redSidePlayer].apm : roundSelector.isNegative ? widget.record.endContext.firstWhere((element) => element.userId != widget.initPlayerId).secondary : widget.record.endContext.firstWhere((element) => element.userId != widget.initPlayerId).secondaryTracking[roundSelector],
(roundSelector == -2 && snapshot.hasData) ? snapshot.data!.timeWeightedStats[redSidePlayer].pps : roundSelector.isNegative ? widget.record.endContext.firstWhere((element) => element.userId != widget.initPlayerId).tertiary : widget.record.endContext.firstWhere((element) => element.userId != widget.initPlayerId).tertiaryTracking[roundSelector],
(roundSelector == -2 && snapshot.hasData) ? snapshot.data!.timeWeightedStats[redSidePlayer].vs : roundSelector.isNegative ? widget.record.endContext.firstWhere((element) => element.userId != widget.initPlayerId).extra : widget.record.endContext.firstWhere((element) => element.userId != widget.initPlayerId).extraTracking[roundSelector],
(roundSelector == -2 && snapshot.hasData) ? snapshot.data!.timeWeightedStats[redSidePlayer].nerdStats : roundSelector.isNegative ? widget.record.endContext.firstWhere((element) => element.userId != widget.initPlayerId).nerdStats : widget.record.endContext.firstWhere((element) => element.userId != widget.initPlayerId).nerdStatsTracking[roundSelector],
(roundSelector == -2 && snapshot.hasData) ? snapshot.data!.timeWeightedStats[redSidePlayer].playstyle : roundSelector.isNegative ? widget.record.endContext.firstWhere((element) => element.userId != widget.initPlayerId).playstyle : widget.record.endContext.firstWhere((element) => element.userId != widget.initPlayerId).playstyleTracking[roundSelector]
)
],
),
if (widget.record.ownId != widget.record.replayId) const Divider(),
if (widget.record.ownId != widget.record.replayId) Column(
children: [
Padding(
padding: const EdgeInsets.only(bottom: 16),
child: Text("Handling",
style: TextStyle(
fontFamily: "Eurostile Round Extended",
fontSize: bigScreen ? 42 : 28)),
),
CompareThingy(
greenSide: widget.record.endContext.firstWhere((element) => element.userId == widget.initPlayerId).handling.das,
redSide: widget.record.endContext.firstWhere((element) => element.userId != widget.initPlayerId).handling.das,
label: "DAS", fractionDigits: 1, postfix: "F",
higherIsBetter: false),
CompareThingy(
greenSide: widget.record.endContext.firstWhere((element) => element.userId == widget.initPlayerId).handling.arr,
redSide: widget.record.endContext.firstWhere((element) => element.userId != widget.initPlayerId).handling.arr,
label: "ARR", fractionDigits: 1, postfix: "F",
higherIsBetter: false),
CompareThingy(
greenSide: widget.record.endContext.firstWhere((element) => element.userId == widget.initPlayerId).handling.sdf,
redSide: widget.record.endContext.firstWhere((element) => element.userId != widget.initPlayerId).handling.sdf,
label: "SDF", prefix: "x",
higherIsBetter: true),
CompareBoolThingy(
greenSide: widget.record.endContext.firstWhere((element) => element.userId == widget.initPlayerId).handling.safeLock,
redSide: widget.record.endContext.firstWhere((element) => element.userId != widget.initPlayerId).handling.safeLock,
label: "Safe HD",
trueIsBetter: true)
],
)
],
)
);
}),
);
} }
Widget buildRoundSelector(double width){ Widget buildRoundSelector(double width){
@ -684,21 +690,17 @@ class TlMatchResultState extends State<TlMatchResultView> {
return Center( return Center(
child: Container( child: Container(
constraints: const BoxConstraints(maxWidth: 768), constraints: const BoxConstraints(maxWidth: 768),
child: buildComparison(viewportWidth > 768, true) child: buildComparison(viewportWidth, true)
), ),
); );
} else { } else {
double comparisonWidth = viewportWidth - 450 - 16;
comparisonWidth = comparisonWidth > 768 ? 768 : comparisonWidth;
return Row( return Row(
mainAxisAlignment: MainAxisAlignment.center, mainAxisAlignment: MainAxisAlignment.center,
children: [ children: [
SizedBox( buildComparison(comparisonWidth, false),
width: 768, buildRoundSelector(450)
child: buildComparison(true, false)
),
Container(
constraints: const BoxConstraints(maxWidth: 768),
child: buildRoundSelector(max(viewportWidth-768-16, 200)),
)
], ],
); );
} }

View File

@ -20,6 +20,10 @@ class Graphs extends StatelessWidget{
@override @override
Widget build(BuildContext context) { Widget build(BuildContext context) {
double attack = apm / 60 * 0.4;
double speed = pps / 3.75;
double defense = nerdStats.dss * 1.15;
double cheese = nerdStats.cheese / 110;
return Wrap( return Wrap(
direction: Axis.horizontal, direction: Axis.horizontal,
alignment: WrapAlignment.center, alignment: WrapAlignment.center,
@ -27,7 +31,7 @@ class Graphs extends StatelessWidget{
crossAxisAlignment: WrapCrossAlignment.start, crossAxisAlignment: WrapCrossAlignment.start,
clipBehavior: Clip.hardEdge, clipBehavior: Clip.hardEdge,
children: [ children: [
Padding( if (true) Padding( // vs graph
padding: const EdgeInsets.fromLTRB(18, 0, 18, 44), padding: const EdgeInsets.fromLTRB(18, 0, 18, 44),
child: SizedBox( child: SizedBox(
height: 310, height: 310,
@ -86,7 +90,7 @@ class Graphs extends StatelessWidget{
borderColor: Colors.transparent, borderColor: Colors.transparent,
dataEntries: [ dataEntries: [
const RadarEntry(value: 0), const RadarEntry(value: 0),
const RadarEntry(value: 0), const RadarEntry(value: 180),
const RadarEntry(value: 0), const RadarEntry(value: 0),
const RadarEntry(value: 0), const RadarEntry(value: 0),
const RadarEntry(value: 0), const RadarEntry(value: 0),
@ -104,7 +108,60 @@ class Graphs extends StatelessWidget{
), ),
), ),
), ),
Padding( Padding( // sq graph
padding: const EdgeInsets.fromLTRB(18, 0, 18, 44),
child: SizedBox(
height: 310,
width: 310,
child: RadarChart(
RadarChartData(
radarShape: RadarShape.polygon,
tickCount: 4,
ticksTextStyle: const TextStyle(color: Colors.white24, fontSize: 10),
radarBorderData: const BorderSide(color: Colors.transparent, width: 1),
gridBorderData: const BorderSide(color: Colors.white24, width: 1),
tickBorderData: const BorderSide(color: Colors.transparent, width: 1),
titleTextStyle: const TextStyle(height: 1.1),
radarTouchData: RadarTouchData(),
getTitle: (index, angle) {
switch (index) {
case 0:
return RadarChartTitle(text: 'Attack\n${f2.format(apm)} APM', angle: 0, positionPercentageOffset: 0.05);
case 1:
return RadarChartTitle(text: 'Speed\n${f2.format(pps)} PPS', angle: 0, positionPercentageOffset: 0.05);
case 2:
return RadarChartTitle(text: 'Defense\n${f2.format(nerdStats.dss)} DS/S', angle: angle + 180, positionPercentageOffset: 0.05);
case 3:
return RadarChartTitle(text: 'Cheese\n${f3.format(nerdStats.cheese)}', angle: 0, positionPercentageOffset: 0.05);
default:
return const RadarChartTitle(text: '');
}
},
dataSets: [
RadarDataSet(
dataEntries: [
RadarEntry(value: attack),
RadarEntry(value: speed),
RadarEntry(value: defense),
RadarEntry(value: cheese),
],
),
RadarDataSet(
fillColor: Colors.transparent,
borderColor: Colors.transparent,
dataEntries: [
const RadarEntry(value: 0),
const RadarEntry(value: 1.2),
const RadarEntry(value: 0),
const RadarEntry(value: 0),
],
)
],
)
)
)
),
Padding( // psq graph
padding: const EdgeInsets.fromLTRB(18, 0, 18, 44), padding: const EdgeInsets.fromLTRB(18, 0, 18, 44),
child: SizedBox( child: SizedBox(
height: 310, height: 310,
@ -126,7 +183,7 @@ class Graphs extends StatelessWidget{
case 1: case 1:
return RadarChartTitle(text: 'Stride\n${percentage.format(playstyle.stride)}', angle: 0, positionPercentageOffset: 0.05); return RadarChartTitle(text: 'Stride\n${percentage.format(playstyle.stride)}', angle: 0, positionPercentageOffset: 0.05);
case 2: case 2:
return RadarChartTitle(text: 'Inf Ds\n${percentage.format(playstyle.infds)}', angle: angle + 180, positionPercentageOffset: 0.05); return RadarChartTitle(text: 'Inf DS\n${percentage.format(playstyle.infds)}', angle: angle + 180, positionPercentageOffset: 0.05);
case 3: case 3:
return RadarChartTitle(text: 'Plonk\n${percentage.format(playstyle.plonk)}', angle: 0, positionPercentageOffset: 0.05); return RadarChartTitle(text: 'Plonk\n${percentage.format(playstyle.plonk)}', angle: 0, positionPercentageOffset: 0.05);
default: default:
@ -147,19 +204,9 @@ class Graphs extends StatelessWidget{
borderColor: Colors.transparent, borderColor: Colors.transparent,
dataEntries: [ dataEntries: [
const RadarEntry(value: 0), const RadarEntry(value: 0),
const RadarEntry(value: 1),
const RadarEntry(value: 0), const RadarEntry(value: 0),
const RadarEntry(value: 0), const RadarEntry(value: 0),
const RadarEntry(value: 0),
],
),
RadarDataSet(
fillColor: Colors.transparent,
borderColor: Colors.transparent,
dataEntries: [
const RadarEntry(value: 1),
const RadarEntry(value: 1),
const RadarEntry(value: 1),
const RadarEntry(value: 1),
], ],
) )
], ],

View File

@ -0,0 +1,59 @@
import 'package:flutter/material.dart';
import 'package:intl/intl.dart';
import 'package:syncfusion_flutter_gauges/gauges.dart';
import 'package:tetra_stats/data_objects/tetrio.dart';
import 'package:tetra_stats/gen/strings.g.dart';
class TLProgress extends StatelessWidget{
final double tr;
final String rank;
final int position;
final String? nextRank;
final String? previousRank;
final int nextRankPosition;
final int previousRankPosition;
final double? nextRankTRcutoff;
final double? previousRankTRcutoff;
final double? nextRankTRcutoffTarget;
final double? previousRankTRcutoffTarget;
const TLProgress({super.key, required this.tr, required this.rank, required this.position, required this.nextRankPosition, required this.previousRankPosition, this.nextRank, this.previousRank, this.nextRankTRcutoff, this.previousRankTRcutoff, this.nextRankTRcutoffTarget, this.previousRankTRcutoffTarget});
double getBarPosition(){
return 1 - (position - nextRankPosition)/(previousRankPosition - nextRankPosition);
}
double? getBarTR(){
return null;
}
@override
Widget build(BuildContext context) {
print(getBarPosition());
// return Container(
// alignment: Alignment.centerLeft,
// height: 50,
// width: MediaQuery.of(context).size.width,
// color: Colors.blue,
// child: Container(
// width: MediaQuery.of(context).size.width / 2,
// height: 50,
// color: Colors.red,
// ),
// );
return Padding(
padding: const EdgeInsets.all(8.0),
child: SfLinearGauge(
minimum: 0,
maximum: 1,
interval: 1,
ranges: [LinearGaugeRange(endValue: getBarPosition(), color: Colors.cyanAccent,)],
markerPointers: [LinearShapePointer(value: getBarPosition(), position: LinearElementPosition.inside, shapeType: LinearShapePointerType.triangle, color: Colors.white, height: 20),
LinearWidgetPointer(offset: 4, position: LinearElementPosition.outside, value: getBarPosition(), child: Text(NumberFormat.decimalPatternDigits(locale: LocaleSettings.currentLocale.languageCode, decimalDigits: 0).format(position)))],
isMirrored: true,
showTicks: true,
showLabels: true
)
);
}
}

View File

@ -9,6 +9,7 @@ import 'package:tetra_stats/utils/numers_formats.dart';
import 'package:tetra_stats/widgets/gauget_num.dart'; import 'package:tetra_stats/widgets/gauget_num.dart';
import 'package:tetra_stats/widgets/graphs.dart'; import 'package:tetra_stats/widgets/graphs.dart';
import 'package:tetra_stats/widgets/stat_sell_num.dart'; import 'package:tetra_stats/widgets/stat_sell_num.dart';
import 'package:tetra_stats/widgets/tl_progress_bar.dart';
var fDiff = NumberFormat("+#,###.###;-#,###.###"); var fDiff = NumberFormat("+#,###.###;-#,###.###");
var intFDiff = NumberFormat("+#,###;-#,###"); var intFDiff = NumberFormat("+#,###;-#,###");
@ -139,20 +140,36 @@ class _TLThingyState extends State<TLThingy> {
), ),
], ],
), ),
if (currentTl.gamesPlayed >= 10 && currentTl.rd! < 100 && currentTl.nextAt >=0 && currentTl.prevAt >= 0) Padding( if (currentTl.gamesPlayed >= 10 && currentTl.rd! < 100 && currentTl.nextAt >=0 && currentTl.prevAt >= 0)
padding: const EdgeInsets.all(8.0), // Padding(
child: SfLinearGauge( // padding: const EdgeInsets.all(8.0),
minimum: currentTl.nextAt.toDouble(), // child: SfLinearGauge(
maximum: currentTl.prevAt.toDouble(), // minimum: currentTl.nextAt.toDouble(),
interval: currentTl.prevAt.toDouble() - currentTl.nextAt.toDouble(), // maximum: currentTl.prevAt.toDouble(),
ranges: [LinearGaugeRange(startValue: currentTl.standing.toDouble() <= currentTl.prevAt.toDouble() ? currentTl.standing.toDouble() : currentTl.prevAt.toDouble(), endValue: currentTl.prevAt.toDouble(), color: Colors.cyanAccent,)], // interval: currentTl.prevAt.toDouble() - currentTl.nextAt.toDouble(),
markerPointers: [LinearShapePointer(value: currentTl.standing.toDouble() <= currentTl.prevAt.toDouble() ? currentTl.standing.toDouble() : currentTl.prevAt.toDouble(), position: LinearElementPosition.inside, shapeType: LinearShapePointerType.triangle, color: Colors.white, height: 20), // ranges: [
LinearWidgetPointer(offset: 4, position: LinearElementPosition.outside, value: currentTl.standing.toDouble() <= currentTl.prevAt.toDouble() ? currentTl.standing.toDouble() : currentTl.prevAt.toDouble(), child: Text(NumberFormat.decimalPatternDigits(locale: LocaleSettings.currentLocale.languageCode, decimalDigits: 0).format(currentTl.standing)))], // LinearGaugeRange(startValue: currentTl.standing.toDouble() <= currentTl.prevAt.toDouble() ? currentTl.standing.toDouble() : currentTl.prevAt.toDouble(), endValue: currentTl.prevAt.toDouble(), color: Colors.cyanAccent, position: LinearElementPosition.cross,),
isAxisInversed: true, // //LinearGaugeRange(startValue: currentTl.standing.toDouble() <= currentTl.prevAt.toDouble() ? currentTl.standing.toDouble() + 500.00 : currentTl.prevAt.toDouble(), endValue: currentTl.prevAt.toDouble(), color: Colors.amber, position: LinearElementPosition.inside,)
isMirrored: true, // ],
showTicks: true, // markerPointers: [LinearShapePointer(value: currentTl.standing.toDouble() <= currentTl.prevAt.toDouble() ? currentTl.standing.toDouble() : currentTl.prevAt.toDouble(), position: LinearElementPosition.inside, shapeType: LinearShapePointerType.triangle, color: Colors.white, height: 20),
showLabels: true // LinearWidgetPointer(offset: 4, position: LinearElementPosition.outside, value: currentTl.standing.toDouble() <= currentTl.prevAt.toDouble() ? currentTl.standing.toDouble() : currentTl.prevAt.toDouble(), child: Text(NumberFormat.decimalPatternDigits(locale: LocaleSettings.currentLocale.languageCode, decimalDigits: 0).format(currentTl.standing)))],
), // isAxisInversed: true,
// isMirrored: true,
// showTicks: true,
// showLabels: true
// ),
// ),
TLProgress(
tr: currentTl.rating,
rank: currentTl.rank,
position: currentTl.standing,
nextRankPosition: currentTl.nextAt,
previousRankPosition: currentTl.prevAt,
previousRankTRcutoff: widget.thatRankCutoff,
previousRankTRcutoffTarget: widget.thatRankTarget,
nextRankTRcutoff: widget.nextRankCutoff,
nextRankTRcutoffTarget: widget.nextRankTarget,
nextRank: widget.tl.nextRank
), ),
if (currentTl.gamesPlayed < 10) if (currentTl.gamesPlayed < 10)
Text(t.gamesUntilRanked(left: 10 - currentTl.gamesPlayed), Text(t.gamesUntilRanked(left: 10 - currentTl.gamesPlayed),
@ -323,7 +340,7 @@ class _TLThingyState extends State<TLThingy> {
if (oldTl?.estTr?.esttr != null) TextSpan(text: comparef.format(currentTl.estTr!.esttr - oldTl!.estTr!.esttr), style: TextStyle( if (oldTl?.estTr?.esttr != null) TextSpan(text: comparef.format(currentTl.estTr!.esttr - oldTl!.estTr!.esttr), style: TextStyle(
color: oldTl!.estTr!.esttr > currentTl.estTr!.esttr ? Colors.redAccent : Colors.greenAccent color: oldTl!.estTr!.esttr > currentTl.estTr!.esttr ? Colors.redAccent : Colors.greenAccent
),), ),),
if (oldTl?.estTr?.esttr != null && widget.lbPositions?.estTr != null) const TextSpan(text: ""), if (oldTl?.estTr?.esttr != null || widget.lbPositions?.estTr != null) const TextSpan(text: ""),
if (widget.lbPositions?.estTr != null) TextSpan(text: widget.lbPositions!.estTr!.position >= 1000 ? "${t.top} ${f2.format(widget.lbPositions!.estTr!.percentage*100)}%" : "${widget.lbPositions!.estTr!.position}", style: TextStyle(color: getColorOfRank(widget.lbPositions!.estTr!.position))), if (widget.lbPositions?.estTr != null) TextSpan(text: widget.lbPositions!.estTr!.position >= 1000 ? "${t.top} ${f2.format(widget.lbPositions!.estTr!.percentage*100)}%" : "${widget.lbPositions!.estTr!.position}", style: TextStyle(color: getColorOfRank(widget.lbPositions!.estTr!.position))),
if (widget.lbPositions?.estTr != null) const TextSpan(text: ""), if (widget.lbPositions?.estTr != null) const TextSpan(text: ""),
TextSpan(text: "Glicko: ${f2.format(currentTl.estTr!.estglicko)}") TextSpan(text: "Glicko: ${f2.format(currentTl.estTr!.estglicko)}")

View File

@ -81,6 +81,7 @@
"verdictGeneral": "$n $verdict than $rank rank average", "verdictGeneral": "$n $verdict than $rank rank average",
"verdictBetter": "better", "verdictBetter": "better",
"verdictWorse": "worse", "verdictWorse": "worse",
"smooth": "Smooth",
"gamesUntilRanked": "${left} games until being ranked", "gamesUntilRanked": "${left} games until being ranked",
"nerdStats": "Nerd Stats", "nerdStats": "Nerd Stats",
"playersYouTrack": "Players you track", "playersYouTrack": "Players you track",

View File

@ -81,6 +81,7 @@
"verdictGeneral": "$verdict среднего $rank ранга на $n", "verdictGeneral": "$verdict среднего $rank ранга на $n",
"verdictBetter": "Лучше", "verdictBetter": "Лучше",
"verdictWorse": "Хуже", "verdictWorse": "Хуже",
"smooth": "Гладкий",
"gamesUntilRanked": "${left} матчей до получения рейтинга", "gamesUntilRanked": "${left} матчей до получения рейтинга",
"nerdStats": "Для задротов", "nerdStats": "Для задротов",
"playersYouTrack": "Отслеживаемые игроки", "playersYouTrack": "Отслеживаемые игроки",