i18n are half-done

This commit is contained in:
dan63047 2024-11-28 23:37:07 +03:00
parent fd15346e97
commit 04bf77c91a
29 changed files with 2066 additions and 3908 deletions

File diff suppressed because it is too large Load Diff

View File

@ -56,7 +56,7 @@ class AboutState extends State<AboutView> {
void initState() { void initState() {
if (!kIsWeb && !Platform.isAndroid && !Platform.isIOS){ if (!kIsWeb && !Platform.isAndroid && !Platform.isIOS){
windowManager.getTitle().then((value) => oldWindowTitle = value); windowManager.getTitle().then((value) => oldWindowTitle = value);
windowManager.setTitle("Tetra Stats: ${t.settings}"); windowManager.setTitle(t.aboutView.title);
} }
super.initState(); super.initState();
} }
@ -69,15 +69,13 @@ class AboutState extends State<AboutView> {
@override @override
Widget build(BuildContext context) { Widget build(BuildContext context) {
final t = Translations.of(context);
bool bigScreen = MediaQuery.of(context).size.width >= 368;
return Scaffold( return Scaffold(
floatingActionButtonLocation: FloatingActionButtonLocation.startTop, floatingActionButtonLocation: FloatingActionButtonLocation.startTop,
floatingActionButton: Padding( floatingActionButton: Padding(
padding: const EdgeInsets.fromLTRB(0.0, 12.0, 0.0, 0.0), padding: const EdgeInsets.fromLTRB(0.0, 12.0, 0.0, 0.0),
child: FloatingActionButton( child: FloatingActionButton(
onPressed: () => Navigator.pop(context), onPressed: () => Navigator.pop(context),
tooltip: 'Fuck go back', tooltip: t.goBackButton,
child: const Icon(Icons.arrow_back), child: const Icon(Icons.arrow_back),
), ),
), ),
@ -89,7 +87,7 @@ class AboutState extends State<AboutView> {
children: [ children: [
Card(child: Center(child: Padding( Card(child: Center(child: Padding(
padding: const EdgeInsets.fromLTRB(0.0, 6.0, 0.0, 18.0), padding: const EdgeInsets.fromLTRB(0.0, 6.0, 0.0, 18.0),
child: Text("About Tetra Stats", style: Theme.of(context).textTheme.titleLarge, textAlign: TextAlign.center), child: Text(t.aboutView.title, style: Theme.of(context).textTheme.titleLarge, textAlign: TextAlign.center),
))), ))),
Column( Column(
mainAxisSize: MainAxisSize.min, mainAxisSize: MainAxisSize.min,
@ -103,41 +101,38 @@ class AboutState extends State<AboutView> {
padding: const EdgeInsets.all(8.0), padding: const EdgeInsets.all(8.0),
child: Container( child: Container(
constraints: BoxConstraints(maxWidth: 568.00), constraints: BoxConstraints(maxWidth: 568.00),
child: Text( child: Text(textAlign: TextAlign.center, t.aboutView.about),
textAlign: TextAlign.center,
"Tetra Stats is a service, that works with TETR.IO Tetra Channel API, providing data from it and calculating some addtitional metrics, based on this data. Service allows user to track their progress in Tetra League with \"Track\" function, which records every Tetra League change into local database (not automatically, you have to visit service from time to time), so these changes could be looked through graphs.\n\nBeanserver blaster is a part of a Tetra Stats, that decoupled into a serverside script. It provides full Tetra League leaderboard, allowing Tetra Stats to sort leaderboard by any metric and build scatter chart, that allows user to analyse Tetra League trends. It also provides history of Tetra League ranks cutoffs, which can be viewed by user via graph as well.\n\nThere is a plans to add replay analysis and tournaments history, so stay tuned!\n\nService is not associated with TETR.IO or osk in any capacity."
),
), ),
), ),
), ),
], ],
)), )),
AboutCard("App Version", packageInfo.version, "Build ${packageInfo.buildNumber}", [ AboutCard(t.aboutView.appVersion, packageInfo.version, t.aboutView.build(build: packageInfo.buildNumber), [
TextSpan(text: "${packageInfo.appName} (${packageInfo.packageName}) • "), TextSpan(text: "${packageInfo.appName} (${packageInfo.packageName}) • "),
TextSpan(text: "GitHub Repo", style: TextStyle(decoration: TextDecoration.underline, decorationColor: Colors.white70, decorationStyle: TextDecorationStyle.dotted, color: Theme.of(context).colorScheme.primary), recognizer: TapGestureRecognizer()..onTap = (){launchInBrowser(Uri.https("github.com", "dan63047/TetraStats"));}), TextSpan(text: t.aboutView.GHrepo, style: TextStyle(decoration: TextDecoration.underline, decorationColor: Colors.white70, decorationStyle: TextDecorationStyle.dotted, color: Theme.of(context).colorScheme.primary), recognizer: TapGestureRecognizer()..onTap = (){launchInBrowser(Uri.https("github.com", "dan63047/TetraStats"));}),
TextSpan(text: ""), TextSpan(text: ""),
TextSpan(text: "Submit an issue", style: TextStyle(decoration: TextDecoration.underline, decorationColor: Colors.white70, decorationStyle: TextDecorationStyle.dotted, color: Theme.of(context).colorScheme.primary), recognizer: TapGestureRecognizer()..onTap = (){launchInBrowser(Uri.https("github.com", "dan63047/TetraStats/issues/new/choose"));}), TextSpan(text: t.aboutView.submitAnIssue, style: TextStyle(decoration: TextDecoration.underline, decorationColor: Colors.white70, decorationStyle: TextDecorationStyle.dotted, color: Theme.of(context).colorScheme.primary), recognizer: TapGestureRecognizer()..onTap = (){launchInBrowser(Uri.https("github.com", "dan63047/TetraStats/issues/new/choose"));}),
]), ]),
Card(child: Center(child: Padding( Card(child: Center(child: Padding(
padding: const EdgeInsets.fromLTRB(0.0, 6.0, 0.0, 18.0), padding: const EdgeInsets.fromLTRB(0.0, 6.0, 0.0, 18.0),
child: Text("Credits", style: Theme.of(context).textTheme.titleLarge, textAlign: TextAlign.center), child: Text(t.aboutView.credits, style: Theme.of(context).textTheme.titleLarge, textAlign: TextAlign.center),
))), ))),
Wrap( Wrap(
direction: Axis.horizontal, direction: Axis.horizontal,
children: [ children: [
FractionallySizedBox(widthFactor: 1/((MediaQuery.of(context).size.width/600).ceil()), child: AboutCard("Autor & developer", "dan63", null, [ FractionallySizedBox(widthFactor: 1/((MediaQuery.of(context).size.width/600).ceil()), child: AboutCard(t.aboutView.authorAndDeveloper, "dan63", null, [
TextSpan(text: "Support him!", style: TextStyle(decoration: TextDecoration.underline, decorationColor: Colors.white70, decorationStyle: TextDecorationStyle.dotted, color: Theme.of(context).colorScheme.primary), recognizer: TapGestureRecognizer()..onTap = (){launchInBrowser(Uri.https("dan63.by", "donate"));}) TextSpan(text: t.aboutView.supportHim, style: TextStyle(decoration: TextDecoration.underline, decorationColor: Colors.white70, decorationStyle: TextDecorationStyle.dotted, color: Theme.of(context).colorScheme.primary), recognizer: TapGestureRecognizer()..onTap = (){launchInBrowser(Uri.https("dan63.by", "donate"));})
])), ])),
FractionallySizedBox(widthFactor: 1/((MediaQuery.of(context).size.width/600).ceil()), child: AboutCard("Provided formulas", "kerrmunism", null, [ FractionallySizedBox(widthFactor: 1/((MediaQuery.of(context).size.width/600).ceil()), child: AboutCard(t.aboutView.providedFormulas, "kerrmunism", null, [
//TextSpan(text: "Support him!", style: TextStyle(decoration: TextDecoration.underline, decorationColor: Colors.white70, decorationStyle: TextDecorationStyle.dotted, color: Theme.of(context).colorScheme.primary), recognizer: TapGestureRecognizer()..onTap = (){launchInBrowser(Uri.https("paypal.com", "paypalme/Kerrmunism"));}) //TextSpan(text: "Support him!", style: TextStyle(decoration: TextDecoration.underline, decorationColor: Colors.white70, decorationStyle: TextDecorationStyle.dotted, color: Theme.of(context).colorScheme.primary), recognizer: TapGestureRecognizer()..onTap = (){launchInBrowser(Uri.https("paypal.com", "paypalme/Kerrmunism"));})
])), ])),
FractionallySizedBox(widthFactor: 1/((MediaQuery.of(context).size.width/600).ceil()), child: AboutCard("Provided S1 history", "p1nkl0bst3r", null, [ FractionallySizedBox(widthFactor: 1/((MediaQuery.of(context).size.width/600).ceil()), child: AboutCard(t.aboutView.providedS1history, "p1nkl0bst3r", null, [
//TextSpan(text: "Support him!", style: TextStyle(decoration: TextDecoration.underline, decorationColor: Colors.white70, decorationStyle: TextDecorationStyle.dotted, color: Theme.of(context).colorScheme.primary), recognizer: TapGestureRecognizer()..onTap = (){launchInBrowser(Uri.https("paypal.com", "paypalme/Kerrmunism"));}) //TextSpan(text: "Support him!", style: TextStyle(decoration: TextDecoration.underline, decorationColor: Colors.white70, decorationStyle: TextDecorationStyle.dotted, color: Theme.of(context).colorScheme.primary), recognizer: TapGestureRecognizer()..onTap = (){launchInBrowser(Uri.https("paypal.com", "paypalme/Kerrmunism"));})
])), ])),
FractionallySizedBox(widthFactor: 1/((MediaQuery.of(context).size.width/600).ceil()), child: AboutCard("Inoue (replay grabber)", "szy", null, [ FractionallySizedBox(widthFactor: 1/((MediaQuery.of(context).size.width/600).ceil()), child: AboutCard(t.aboutView.inoue, "szy", null, [
//TextSpan(text: "Support him!", style: TextStyle(decoration: TextDecoration.underline, decorationColor: Colors.white70, decorationStyle: TextDecorationStyle.dotted, color: Theme.of(context).colorScheme.primary), recognizer: TapGestureRecognizer()..onTap = (){launchInBrowser(Uri.https("paypal.com", "paypalme/Kerrmunism"));}) //TextSpan(text: "Support him!", style: TextStyle(decoration: TextDecoration.underline, decorationColor: Colors.white70, decorationStyle: TextDecorationStyle.dotted, color: Theme.of(context).colorScheme.primary), recognizer: TapGestureRecognizer()..onTap = (){launchInBrowser(Uri.https("paypal.com", "paypalme/Kerrmunism"));})
])), ])),
FractionallySizedBox(widthFactor: 1/((MediaQuery.of(context).size.width/600).ceil()), child: AboutCard("Simplfied Chinise locale", "neko_ab4093", null, [ FractionallySizedBox(widthFactor: 1/((MediaQuery.of(context).size.width/600).ceil()), child: AboutCard(t.aboutView.zhCNlocale, "neko_ab4093", null, [
//TextSpan(text: "Support him!", style: TextStyle(decoration: TextDecoration.underline, decorationColor: Colors.white70, decorationStyle: TextDecorationStyle.dotted, color: Theme.of(context).colorScheme.primary), recognizer: TapGestureRecognizer()..onTap = (){launchInBrowser(Uri.https("paypal.com", "paypalme/Kerrmunism"));}) //TextSpan(text: "Support him!", style: TextStyle(decoration: TextDecoration.underline, decorationColor: Colors.white70, decorationStyle: TextDecorationStyle.dotted, color: Theme.of(context).colorScheme.primary), recognizer: TapGestureRecognizer()..onTap = (){launchInBrowser(Uri.https("paypal.com", "paypalme/Kerrmunism"));})
])), ])),
], ],

View File

@ -44,150 +44,150 @@ class CompareState extends State<CompareView> {
List<Summaries> summaries = []; List<Summaries> summaries = [];
List<String> nicknames = []; List<String> nicknames = [];
Map<String, List<String>> TitesForStats = { Map<String, List<String>> TitesForStats = {
"General": [ t.general: [
"Registration Date", t.stats.registrationDate,
"XP", t.stats.xp.short,
"Time Played", t.stats.gametime,
"Online Games Played", t.stats.ogp,
"Online Games Won", t.stats.ogw,
"Followers", t.stats.followers,
], ],
"Tetra League": [ t.gamemodes["league"]!: [
"Tetra Rating", t.stats.tr.full,
"Glicko", t.stats.glicko.full,
"RD", t.stats.rd.full,
"GLIXARE", t.stats.glixare.full,
"S1-like TR", t.stats.s1tr.full,
"Position", t.stats.placement,
"Games Played", t.stats.gp.full,
"Games Won", t.stats.gw.full,
"Winrate", t.stats.winrate.full,
"Attack Per Minute", t.stats.apm.full,
"Pieces Per Second", t.stats.pps.full,
"Versus Score", t.stats.vs.full,
"Nerd Stats", t.nerdStats,
"Attack Per Piece", t.stats.app.full,
"VS / APM", t.stats.vsapm.full,
"Downstack Per Second", t.stats.dss.full,
"Downstack Per Piece", t.stats.dsp.full,
"APP + DSP", t.stats.appdsp.full,
"Cheese Index", t.stats.cheese.full,
"Garbage Efficiency", t.stats.gbe.full,
"Weighted APP", t.stats.nyaapp.full,
"Area", t.stats.area.full,
"Playstyle", t.playstyles,
"Opener", t.stats.opener.full,
"Plonk", t.stats.plonk.full,
"Stride", t.stats.stride.full,
"Infinite Downstack" t.stats.infds.full
], ],
"Quick Play":[ t.gamemodes["zenith"]!:[
"Altitude", t.stats.altitude.full,
"Position", t.stats.placement,
"Attack Per Minute", t.stats.apm.full,
"Pieces Per Second", t.stats.pps.full,
"Versus Score", t.stats.vs.full,
"KO's", t.stats.kos.full,
"Top B2B", t.stats.b2b.full,
"Climb Speed", t.stats.climbSpeed.full,
"Peak Climb Speed", t.stats.peakClimbSpeed.full,
"Time Spend", t.stats.totalTime.full,
"Finesse", t.stats.finesse.full,
"Nerd Stats", t.nerdStats,
"Attack Per Piece", t.stats.app.full,
"VS / APM", t.stats.vsapm.full,
"Downstack Per Second", t.stats.dss.full,
"Downstack Per Piece", t.stats.dsp.full,
"APP + DSP", t.stats.appdsp.full,
"Cheese Index", t.stats.cheese.full,
"Garbage Efficiency", t.stats.gbe.full,
"Weighted APP", t.stats.nyaapp.full,
"Area", t.stats.area.full,
"Playstyle", t.playstyles,
"Opener", t.stats.opener.full,
"Plonk", t.stats.plonk.full,
"Stride", t.stats.stride.full,
"Infinite Downstack", t.stats.infds.full
], ],
"Quick Play Expert": [ t.gamemodes["zenithex"]!:[
"Altitude", t.stats.altitude.full,
"Position", t.stats.placement,
"Attack Per Minute", t.stats.apm.full,
"Pieces Per Second", t.stats.pps.full,
"Versus Score", t.stats.vs.full,
"KO's", t.stats.kos.full,
"Top B2B", t.stats.b2b.full,
"Climb Speed", t.stats.climbSpeed.full,
"Peak Climb Speed", t.stats.peakClimbSpeed.full,
"Time Spend", t.stats.totalTime.full,
"Finesse", t.stats.finesse.full,
"Nerd Stats", t.nerdStats,
"Attack Per Piece", t.stats.app.full,
"VS / APM", t.stats.vsapm.full,
"Downstack Per Second", t.stats.dss.full,
"Downstack Per Piece", t.stats.dsp.full,
"APP + DSP", t.stats.appdsp.full,
"Cheese Index", t.stats.cheese.full,
"Garbage Efficiency", t.stats.gbe.full,
"Weighted APP", t.stats.nyaapp.full,
"Area", t.stats.area.full,
"Playstyle", t.playstyles,
"Opener", t.stats.opener.full,
"Plonk", t.stats.plonk.full,
"Stride", t.stats.stride.full,
"Infinite Downstack", t.stats.infds.full
], ],
"40 Lines": [ t.gamemodes["40l"]!: [
"Time", t.stats.totalTime.short,
"Pieces", t.stats.pieces.full,
"Inputs", t.stats.kp.full,
"Key Presses Per Piece", t.stats.kpp.full,
"Pieces Per Second", t.stats.pps.full,
"Key Presses Per Second", t.stats.kps.full,
"Finesse", t.stats.finesse.full,
"Finesse Faults", t.stats.finesseFaults.full,
"", "",
"Quads", t.stats.lineClears.quad,
"Triples", t.stats.lineClears.triple,
"Doubles", t.stats.lineClears.double,
"Singles", t.stats.lineClears.single,
"", "",
"T-spins triples", "${t.stats.tSpins} ${t.stats.lineClears.triple}",
"T-spins doubles", "${t.stats.tSpins} ${t.stats.lineClears.double}",
"T-spins singles", "${t.stats.tSpins} ${t.stats.lineClears.single}",
"T-spins zeros", "${t.stats.tSpins} ${t.stats.lineClears.zero}",
"Mini T-spins doubles", "${t.stats.mini} ${t.stats.tSpins} ${t.stats.lineClears.double}",
"Mini T-spins singles", "${t.stats.mini} ${t.stats.tSpins} ${t.stats.lineClears.single}",
"Mini T-spins zeros" "${t.stats.mini} ${t.stats.tSpins} ${t.stats.lineClears.zero}"
], ],
"Blitz": [ t.gamemodes["blitz"]!: [
"Score", t.stats.score,
"Pieces", t.stats.pieces.full,
"Lines", t.stats.lines,
"Level", t.stats.level.full,
"Inputs", t.stats.kp.full,
"Key Presses Per Piece", t.stats.kpp.full,
"Pieces Per Second", t.stats.pps.full,
"Key Presses Per Second", t.stats.kps.full,
"Finesse", t.stats.finesse.full,
"Finesse Faults", t.stats.finesseFaults.full,
"", "",
"Quads", t.stats.lineClears.quad,
"Triples", t.stats.lineClears.triple,
"Doubles", t.stats.lineClears.double,
"Singles", t.stats.lineClears.single,
"", "",
"T-spins triples", "${t.stats.tSpins} ${t.stats.lineClears.triple}",
"T-spins doubles", "${t.stats.tSpins} ${t.stats.lineClears.double}",
"T-spins singles", "${t.stats.tSpins} ${t.stats.lineClears.single}",
"T-spins zeros", "${t.stats.tSpins} ${t.stats.lineClears.zero}",
"Mini T-spins doubles", "${t.stats.mini} ${t.stats.tSpins} ${t.stats.lineClears.double}",
"Mini T-spins singles", "${t.stats.mini} ${t.stats.tSpins} ${t.stats.lineClears.single}",
"Mini T-spins zeros" "${t.stats.mini} ${t.stats.tSpins} ${t.stats.lineClears.zero}"
], ],
"Zen": [ t.gamemodes["zen"]!: [
"Score", t.stats.score,
"Level" t.stats.level.full
] ]
}; };
List<List<List<dynamic>>> rawValues = [[],[],[],[],[],[],[]]; List<List<List<dynamic>>> rawValues = [[],[],[],[],[],[],[]];
@ -725,7 +725,7 @@ class CompareState extends State<CompareView> {
padding: const EdgeInsets.all(16.0), padding: const EdgeInsets.all(16.0),
child: FloatingActionButton( child: FloatingActionButton(
onPressed: () => Navigator.pop(context), onPressed: () => Navigator.pop(context),
tooltip: 'Fuck go back', tooltip: t.goBackButton,
child: const Icon(Icons.arrow_back), child: const Icon(Icons.arrow_back),
), ),
), ),
@ -748,7 +748,7 @@ class CompareState extends State<CompareView> {
child: Card( child: Card(
child: Padding( child: Padding(
padding: const EdgeInsets.fromLTRB(90.0, 18.0, 5.0, 0), padding: const EdgeInsets.fromLTRB(90.0, 18.0, 5.0, 0),
child: Text("Comparison", style: TextStyle(fontSize: 28)), child: Text(t.comparison, style: TextStyle(fontSize: 28)),
), ),
), ),
), ),
@ -1149,13 +1149,13 @@ class VsGraphs extends StatelessWidget{
getTitle: (index, angle) { getTitle: (index, angle) {
switch (index) { switch (index) {
case 0: case 0:
return RadarChartTitle(text: t.graphs.attack, angle: 0, positionPercentageOffset: 0.05); return RadarChartTitle(text: t.stats.graphs.attack, angle: 0, positionPercentageOffset: 0.05);
case 1: case 1:
return RadarChartTitle(text: t.graphs.speed, angle: 0, positionPercentageOffset: 0.05); return RadarChartTitle(text: t.stats.graphs.speed, angle: 0, positionPercentageOffset: 0.05);
case 2: case 2:
return RadarChartTitle(text: t.graphs.defense, angle: angle + 180, positionPercentageOffset: 0.05); return RadarChartTitle(text: t.stats.graphs.defense, angle: angle + 180, positionPercentageOffset: 0.05);
case 3: case 3:
return RadarChartTitle(text: t.graphs.cheese, angle: 0, positionPercentageOffset: 0.05); return RadarChartTitle(text: t.stats.graphs.cheese, angle: 0, positionPercentageOffset: 0.05);
default: default:
return const RadarChartTitle(text: ''); return const RadarChartTitle(text: '');
} }

View File

@ -95,25 +95,25 @@ class ClearData{
} }
Map<String, List<ClearData>> clearsExisting = { Map<String, List<ClearData>> clearsExisting = {
"No Spin Clears": [ t.calcDestination.noSpinClears: [
ClearData("No lineclear (Break Combo)", Lineclears.ZERO, 0, false, false), ClearData(t.calcDestination.noLineclear, Lineclears.ZERO, 0, false, false),
ClearData("Single", Lineclears.SINGLE, 1, false, false), ClearData(t.stats.lineClears.single, Lineclears.SINGLE, 1, false, false),
ClearData("Double", Lineclears.DOUBLE, 2, false, false), ClearData(t.stats.lineClears.double, Lineclears.DOUBLE, 2, false, false),
ClearData("Triple", Lineclears.TRIPLE, 3, false, false), ClearData(t.stats.lineClears.triple, Lineclears.TRIPLE, 3, false, false),
ClearData("Quad", Lineclears.QUAD, 4, false, false) ClearData(t.stats.lineClears.quad, Lineclears.QUAD, 4, false, false)
], ],
"Spins": [ t.stats.spins: [
ClearData("Spin Zero", Lineclears.TSPIN, 0, false, true), ClearData("${t.stats.spin} ${t.stats.lineClears.zero}", Lineclears.TSPIN, 0, false, true),
ClearData("Spin Single", Lineclears.TSPIN_SINGLE, 1, false, true), ClearData("${t.stats.spin} ${t.stats.lineClears.single}", Lineclears.TSPIN_SINGLE, 1, false, true),
ClearData("Spin Double", Lineclears.TSPIN_DOUBLE, 2, false, true), ClearData("${t.stats.spin} ${t.stats.lineClears.double}", Lineclears.TSPIN_DOUBLE, 2, false, true),
ClearData("Spin Triple", Lineclears.TSPIN_TRIPLE, 3, false, true), ClearData("${t.stats.spin} ${t.stats.lineClears.triple}", Lineclears.TSPIN_TRIPLE, 3, false, true),
ClearData("Spin Quad", Lineclears.TSPIN_QUAD, 4, false, true), ClearData("${t.stats.spin} ${t.stats.lineClears.quad}", Lineclears.TSPIN_QUAD, 4, false, true),
], ],
"Mini spins": [ "${t.stats.mini} ${t.stats.spins}": [
ClearData("Mini Spin Zero", Lineclears.TSPIN_MINI, 0, true, false), ClearData("${t.stats.mini} ${t.stats.spin} ${t.stats.lineClears.zero}", Lineclears.TSPIN_MINI, 0, true, false),
ClearData("Mini Spin Single", Lineclears.TSPIN_MINI_SINGLE, 1, true, false), ClearData("${t.stats.mini} ${t.stats.spin} ${t.stats.lineClears.single}", Lineclears.TSPIN_MINI_SINGLE, 1, true, false),
ClearData("Mini Spin Double", Lineclears.TSPIN_MINI_DOUBLE, 2, true, false), ClearData("${t.stats.mini} ${t.stats.spin} ${t.stats.lineClears.double}", Lineclears.TSPIN_MINI_DOUBLE, 2, true, false),
ClearData("Mini Spin Triple", Lineclears.TSPIN_MINI_TRIPLE, 3, true, false), ClearData("${t.stats.mini} ${t.stats.spin} ${t.stats.lineClears.triple}", Lineclears.TSPIN_MINI_TRIPLE, 3, true, false),
] ]
}; };
@ -165,8 +165,8 @@ class _DestinationCalculatorState extends State<DestinationCalculator> {
List<ClearData> clears = []; List<ClearData> clears = [];
Map<String, int> customClearsChoice = { Map<String, int> customClearsChoice = {
"No Spin Clears": 5, t.calcDestination.noSpinClears: 5,
"Spins": 5 t.calcDestination.spins: 5
}; };
int idCounter = 0; int idCounter = 0;
Rules rules = Rules(); Rules rules = Rules();
@ -204,7 +204,7 @@ class _DestinationCalculatorState extends State<DestinationCalculator> {
padding: const EdgeInsets.only(bottom: 8.0), padding: const EdgeInsets.only(bottom: 8.0),
child: Column( child: Column(
children: [ children: [
Text("Stats Calucator", style: Theme.of(context).textTheme.titleLarge), Text(t.calcNavigation.stats, style: Theme.of(context).textTheme.titleLarge),
], ],
), ),
)), )),
@ -253,7 +253,7 @@ class _DestinationCalculatorState extends State<DestinationCalculator> {
), ),
TextButton( TextButton(
onPressed: () => calc(), onPressed: () => calc(),
child: Text(t.calc), child: Text(t.calcDestination.statsCalcButton),
), ),
], ],
), ),
@ -265,7 +265,7 @@ class _DestinationCalculatorState extends State<DestinationCalculator> {
if (playstyle != null) Card( if (playstyle != null) Card(
child: Graphs(apm!, pps!, vs!, nerdStats!, playstyle!) child: Graphs(apm!, pps!, vs!, nerdStats!, playstyle!)
), ),
if (nerdStats == null) InfoThingy("Enter values and press \"Calc\" to see Nerd Stats for them") if (nerdStats == null) InfoThingy(t.calcDestination.tip)
], ],
), ),
); );
@ -275,7 +275,7 @@ class _DestinationCalculatorState extends State<DestinationCalculator> {
return SizedBox( return SizedBox(
width: width - (hasSidebar ? 80 : 0), width: width - (hasSidebar ? 80 : 0),
height: widget.constraints.maxHeight - (hasSidebar ? 108 : 178), height: widget.constraints.maxHeight - (hasSidebar ? 108 : 178),
child: clears.isEmpty ? InfoThingy("Click on the actions on the left to add them here") : child: clears.isEmpty ? InfoThingy(t.calcDestination.damageCalcTip) :
Card( Card(
child: Column( child: Column(
children: [ children: [
@ -301,7 +301,7 @@ class _DestinationCalculatorState extends State<DestinationCalculator> {
padding: const EdgeInsets.fromLTRB(16.0, 0.0, 34.0, 0.0), padding: const EdgeInsets.fromLTRB(16.0, 0.0, 34.0, 0.0),
child: Row( child: Row(
children: [ children: [
Text("Total damage:", style: TextStyle(fontSize: 36, fontWeight: ui.FontWeight.w100)), Text("${t.calcDestination.totalDamage}:", style: TextStyle(fontSize: 36, fontWeight: ui.FontWeight.w100)),
Spacer(), Spacer(),
Text(intf.format(totalDamage), style: TextStyle(fontFamily: "Eurostile Round Extended", fontSize: 36, fontWeight: ui.FontWeight.w100)) Text(intf.format(totalDamage), style: TextStyle(fontFamily: "Eurostile Round Extended", fontSize: 36, fontWeight: ui.FontWeight.w100))
], ],
@ -310,11 +310,11 @@ class _DestinationCalculatorState extends State<DestinationCalculator> {
Row( Row(
mainAxisAlignment: MainAxisAlignment.spaceAround, mainAxisAlignment: MainAxisAlignment.spaceAround,
children: [ children: [
Text("Lineclears: ${intf.format(normalDamage)}"), Text("${t.calcDestination.lineclears}: ${intf.format(normalDamage)}"),
Text("Combo: ${intf.format(comboDamage)}"), Text("${t.calcDestination.combo}: ${intf.format(comboDamage)}"),
Text("B2B: ${intf.format(b2bDamage)}"), Text("${t.stats.b2b.short}: ${intf.format(b2bDamage)}"),
Text("Surge: ${intf.format(surgeDamage)}"), Text("${t.calcDestination.surge}: ${intf.format(surgeDamage)}"),
Text("PCs: ${intf.format(pcDamage)}") Text("${t.calcDestination.pcs}: ${intf.format(pcDamage)}")
], ],
), ),
if (totalDamage > 0) SfLinearGauge( if (totalDamage > 0) SfLinearGauge(
@ -382,9 +382,9 @@ class _DestinationCalculatorState extends State<DestinationCalculator> {
}, },
), ),
)); ));
if (key != "Mini spins") rSideWidgets.add(Card( if (key != "${t.stats.mini} ${t.stats.spins}") rSideWidgets.add(Card(
child: ListTile( child: ListTile(
title: Text("Custom"), title: Text(t.calcDestination.custom),
trailing: Row( trailing: Row(
mainAxisSize: MainAxisSize.min, mainAxisSize: MainAxisSize.min,
children: [ children: [
@ -394,13 +394,13 @@ class _DestinationCalculatorState extends State<DestinationCalculator> {
decoration: InputDecoration(hintText: "5"), decoration: InputDecoration(hintText: "5"),
onChanged: (value) => customClearsChoice[key] = int.parse(value), onChanged: (value) => customClearsChoice[key] = int.parse(value),
)), )),
Text(" Lines", style: Theme.of(context).textTheme.displayLarge), Text(" ${t.stats.lines}", style: Theme.of(context).textTheme.displayLarge),
Icon(Icons.arrow_forward_ios) Icon(Icons.arrow_forward_ios)
], ],
), ),
onTap: (){ onTap: (){
setState((){ setState((){
clears.add(ClearData("${key == "Spins" ? "Spin " : ""}${clearNames[min(customClearsChoice[key]!, clearNames.length-1)]} (${customClearsChoice[key]!} Lines)", key == "Spins" ? Lineclears.TSPIN_PENTA : Lineclears.PENTA, customClearsChoice[key]!, false, key == "Spins").cloneWith(idCounter)); clears.add(ClearData("${key == t.calcDestination.spins ? "${t.stats.spin} " : ""}${clearNames[min(customClearsChoice[key]!, clearNames.length-1)]} (${customClearsChoice[key]!} ${t.stats.lines})", key == t.calcDestination.spins ? Lineclears.TSPIN_PENTA : Lineclears.PENTA, customClearsChoice[key]!, false, key == t.calcDestination.spins).cloneWith(idCounter));
}); });
idCounter++; idCounter++;
}, },
@ -466,7 +466,7 @@ class _DestinationCalculatorState extends State<DestinationCalculator> {
padding: const EdgeInsets.only(bottom: 8.0), padding: const EdgeInsets.only(bottom: 8.0),
child: Column( child: Column(
children: [ children: [
Text("Damage Calucator", style: Theme.of(context).textTheme.titleLarge), Text(t.calcNavigation.damage, style: Theme.of(context).textTheme.titleLarge),
], ],
), ),
)), )),
@ -483,9 +483,9 @@ class _DestinationCalculatorState extends State<DestinationCalculator> {
children: [ children: [
Card( Card(
child: TabBar(tabs: [ child: TabBar(tabs: [
Tab(text: "Actions"), Tab(text: t.calcDestination.actions),
if (widget.constraints.maxWidth <= 768.0) Tab(text: "Results"), if (widget.constraints.maxWidth <= 768.0) Tab(text: t.calcDestination.results),
Tab(text: "Rules"), Tab(text: t.calcDestination.rules),
]), ]),
), ),
SizedBox( SizedBox(
@ -506,7 +506,7 @@ class _DestinationCalculatorState extends State<DestinationCalculator> {
child: Column( child: Column(
children: [ children: [
ListTile( ListTile(
title: Text("Multiplier", style: mainToggleInRules), title: Text(t.calcDestination.multiplier, style: mainToggleInRules),
trailing: SizedBox(width: 90.0, child: TextField( trailing: SizedBox(width: 90.0, child: TextField(
keyboardType: TextInputType.number, keyboardType: TextInputType.number,
inputFormatters: [FilteringTextInputFormatter.allow(RegExp(r'[0-9.]'))], inputFormatters: [FilteringTextInputFormatter.allow(RegExp(r'[0-9.]'))],
@ -515,7 +515,7 @@ class _DestinationCalculatorState extends State<DestinationCalculator> {
)), )),
), ),
ListTile( ListTile(
title: Text("Perfect Clear Damage"), title: Text(t.calcDestination.pcDamage),
trailing: SizedBox(width: 90.0, child: TextField( trailing: SizedBox(width: 90.0, child: TextField(
keyboardType: TextInputType.number, keyboardType: TextInputType.number,
inputFormatters: [FilteringTextInputFormatter.allow(RegExp(r'[0-9]'))], inputFormatters: [FilteringTextInputFormatter.allow(RegExp(r'[0-9]'))],
@ -530,11 +530,11 @@ class _DestinationCalculatorState extends State<DestinationCalculator> {
child: Column( child: Column(
children: [ children: [
ListTile( ListTile(
title: Text("Combo", style: mainToggleInRules), title: Text(t.calcDestination.combo, style: mainToggleInRules),
trailing: Switch(value: rules.combo, onChanged: (v) => setState((){rules.combo = v;})), trailing: Switch(value: rules.combo, onChanged: (v) => setState((){rules.combo = v;})),
), ),
if (rules.combo) ListTile( if (rules.combo) ListTile(
title: Text("Combo Table"), title: Text(t.calcDestination.comboTable),
trailing: DropdownButton( trailing: DropdownButton(
items: [for (var v in ComboTables.values) if (v != ComboTables.none) DropdownMenuItem(value: v.index, child: Text(comboTablesNames[v]!))], items: [for (var v in ComboTables.values) if (v != ComboTables.none) DropdownMenuItem(value: v.index, child: Text(comboTablesNames[v]!))],
value: rules.comboTable.index, value: rules.comboTable.index,
@ -548,11 +548,11 @@ class _DestinationCalculatorState extends State<DestinationCalculator> {
child: Column( child: Column(
children: [ children: [
ListTile( ListTile(
title: Text("Back-To-Back (B2B)", style: mainToggleInRules), title: Text("${t.stats.b2b.full} (${t.stats.b2b.short})", style: mainToggleInRules),
trailing: Switch(value: rules.b2b, onChanged: (v) => setState((){rules.b2b = v;})), trailing: Switch(value: rules.b2b, onChanged: (v) => setState((){rules.b2b = v;})),
), ),
if (rules.b2b) ListTile( if (rules.b2b) ListTile(
title: Text("Back-To-Back Chaining"), title: Text(t.calcDestination.b2bChaining),
trailing: Switch(value: rules.b2bChaining, onChanged: (v) => setState((){rules.b2bChaining = v;})), trailing: Switch(value: rules.b2bChaining, onChanged: (v) => setState((){rules.b2bChaining = v;})),
), ),
], ],
@ -562,11 +562,11 @@ class _DestinationCalculatorState extends State<DestinationCalculator> {
child: Column( child: Column(
children: [ children: [
ListTile( ListTile(
title: Text("Surge", style: mainToggleInRules), title: Text(t.calcDestination.surge, style: mainToggleInRules),
trailing: Switch(value: rules.surge, onChanged: (v) => setState((){rules.surge = v;})), trailing: Switch(value: rules.surge, onChanged: (v) => setState((){rules.surge = v;})),
), ),
if (rules.surge) ListTile( if (rules.surge) ListTile(
title: Text("Starts at B2B"), title: Text(t.calcDestination.surgeStartAtB2B),
trailing: SizedBox(width: 90.0, child: TextField( trailing: SizedBox(width: 90.0, child: TextField(
keyboardType: TextInputType.number, keyboardType: TextInputType.number,
inputFormatters: [FilteringTextInputFormatter.digitsOnly], inputFormatters: [FilteringTextInputFormatter.digitsOnly],
@ -575,7 +575,7 @@ class _DestinationCalculatorState extends State<DestinationCalculator> {
)), )),
), ),
if (rules.surge) ListTile( if (rules.surge) ListTile(
title: Text("Start amount"), title: Text(t.calcDestination.surgeStartAmount),
trailing: SizedBox(width: 90.0, child: TextField( trailing: SizedBox(width: 90.0, child: TextField(
keyboardType: TextInputType.number, keyboardType: TextInputType.number,
inputFormatters: [FilteringTextInputFormatter.digitsOnly], inputFormatters: [FilteringTextInputFormatter.digitsOnly],
@ -617,13 +617,13 @@ class _DestinationCalculatorState extends State<DestinationCalculator> {
if (widget.constraints.maxWidth > 768.0) SegmentedButton<CalcCards>( if (widget.constraints.maxWidth > 768.0) SegmentedButton<CalcCards>(
showSelectedIcon: false, showSelectedIcon: false,
segments: <ButtonSegment<CalcCards>>[ segments: <ButtonSegment<CalcCards>>[
const ButtonSegment<CalcCards>( ButtonSegment<CalcCards>(
value: CalcCards.calc, value: CalcCards.calc,
label: Text('Stats Calculator'), label: Text(t.calcNavigation.stats),
), ),
ButtonSegment<CalcCards>( ButtonSegment<CalcCards>(
value: CalcCards.damage, value: CalcCards.damage,
label: Text('Damage Calculator'), label: Text(t.calcNavigation.damage),
), ),
], ],
selected: <CalcCards>{calcCard}, selected: <CalcCards>{calcCard},

View File

@ -5,6 +5,7 @@ import 'package:syncfusion_flutter_gauges/gauges.dart';
import 'package:tetra_stats/data_objects/cutoff_tetrio.dart'; import 'package:tetra_stats/data_objects/cutoff_tetrio.dart';
import 'package:tetra_stats/data_objects/tetrio_constants.dart'; import 'package:tetra_stats/data_objects/tetrio_constants.dart';
import 'package:tetra_stats/data_objects/tetrio_player_from_leaderboard.dart'; import 'package:tetra_stats/data_objects/tetrio_player_from_leaderboard.dart';
import 'package:tetra_stats/gen/strings.g.dart';
import 'package:tetra_stats/main.dart'; import 'package:tetra_stats/main.dart';
import 'package:tetra_stats/utils/numers_formats.dart'; import 'package:tetra_stats/utils/numers_formats.dart';
import 'package:tetra_stats/utils/text_shadow.dart'; import 'package:tetra_stats/utils/text_shadow.dart';
@ -75,8 +76,8 @@ class _DestinationCutoffsState extends State<DestinationCutoffs> {
padding: const EdgeInsets.only(bottom: 8.0), padding: const EdgeInsets.only(bottom: 8.0),
child: Column( child: Column(
children: [ children: [
Text("Tetra League State", style: Theme.of(context).textTheme.titleLarge), Text(t.cutoffsDestination.title, style: Theme.of(context).textTheme.titleLarge),
Text("as of ${timestamp(snapshot.data!.timestamp)}"), Text(t.cutoffsDestination.relevance(timestamp: timestamp(snapshot.data!.timestamp))),
], ],
), ),
)), )),
@ -94,9 +95,9 @@ class _DestinationCutoffsState extends State<DestinationCutoffs> {
children: [ children: [
Padding( Padding(
padding: const EdgeInsets.only(bottom: 12.0), padding: const EdgeInsets.only(bottom: 12.0),
child: Text("Actual"), child: Text(t.cutoffsDestination.actual),
), ),
Text("Target") Text(t.cutoffsDestination.target)
] ]
), ),
), ),
@ -177,42 +178,42 @@ class _DestinationCutoffsState extends State<DestinationCutoffs> {
children: [ children: [
TableRow( TableRow(
children: [ children: [
Text("Rank", textAlign: TextAlign.center, style: const TextStyle(fontFamily: "Eurostile Round", fontSize: 14, fontWeight: FontWeight.w500, color: Colors.white)), Text(t.rank, textAlign: TextAlign.center, style: const TextStyle(fontFamily: "Eurostile Round", fontSize: 14, fontWeight: FontWeight.w500, color: Colors.white)),
const Padding( Padding(
padding: EdgeInsets.only(right: 8.0), padding: EdgeInsets.only(right: 8.0),
child: Text("Cutoff TR", textAlign: TextAlign.right, style: TextStyle(fontFamily: "Eurostile Round", fontSize: 28, fontWeight: FontWeight.w500, color: Colors.white)), child: Text(t.cutoffsDestination.cutoffTR, textAlign: TextAlign.right, style: TextStyle(fontFamily: "Eurostile Round", fontSize: 28, fontWeight: FontWeight.w500, color: Colors.white)),
), ),
const Padding( Padding(
padding: EdgeInsets.only(right: 8.0), padding: EdgeInsets.only(right: 8.0),
child: Text("Target TR", textAlign: TextAlign.right, style: TextStyle(fontFamily: "Eurostile Round", fontSize: 24, fontWeight: FontWeight.w100, color: Colors.white)), child: Text(t.cutoffsDestination.targetTR, textAlign: TextAlign.right, style: TextStyle(fontFamily: "Eurostile Round", fontSize: 24, fontWeight: FontWeight.w100, color: Colors.white)),
), ),
Padding( Padding(
padding: const EdgeInsets.only(right: 8.0), padding: const EdgeInsets.only(right: 8.0),
child: Text("State", textAlign: TextAlign.right, style: const TextStyle(fontFamily: "Eurostile Round", fontSize: 14, fontWeight: FontWeight.w500, color: Colors.white)), child: Text(t.cutoffsDestination.state, textAlign: TextAlign.right, style: const TextStyle(fontFamily: "Eurostile Round", fontSize: 14, fontWeight: FontWeight.w500, color: Colors.white)),
), ),
const Padding( Padding(
padding: EdgeInsets.only(right: 8.0), padding: EdgeInsets.only(right: 8.0),
child: Text("APM", textAlign: TextAlign.right, style: TextStyle(fontFamily: "Eurostile Round", fontSize: 28, fontWeight: FontWeight.w500, color: Colors.white)), child: Text(t.stats.apm.short, textAlign: TextAlign.right, style: TextStyle(fontFamily: "Eurostile Round", fontSize: 28, fontWeight: FontWeight.w500, color: Colors.white)),
), ),
const Padding( Padding(
padding: EdgeInsets.only(right: 8.0), padding: EdgeInsets.only(right: 8.0),
child: Text("PPS", textAlign: TextAlign.right, style: TextStyle(fontFamily: "Eurostile Round", fontSize: 28, fontWeight: FontWeight.w500, color: Colors.white)), child: Text(t.stats.pps.short, textAlign: TextAlign.right, style: TextStyle(fontFamily: "Eurostile Round", fontSize: 28, fontWeight: FontWeight.w500, color: Colors.white)),
), ),
const Padding( Padding(
padding: EdgeInsets.only(right: 8.0), padding: EdgeInsets.only(right: 8.0),
child: Text("VS", textAlign: TextAlign.right, style: TextStyle(fontFamily: "Eurostile Round", fontSize: 28, fontWeight: FontWeight.w500, color: Colors.white)), child: Text(t.stats.vs.short, textAlign: TextAlign.right, style: TextStyle(fontFamily: "Eurostile Round", fontSize: 28, fontWeight: FontWeight.w500, color: Colors.white)),
), ),
const Padding( Padding(
padding: EdgeInsets.only(right: 8.0), padding: EdgeInsets.only(right: 8.0),
child: Text("Advanced", textAlign: TextAlign.right, style: TextStyle(fontFamily: "Eurostile Round", fontSize: 14, fontWeight: FontWeight.w500, color: Colors.white)), child: Text(t.cutoffsDestination.advanced, textAlign: TextAlign.right, style: TextStyle(fontFamily: "Eurostile Round", fontSize: 14, fontWeight: FontWeight.w500, color: Colors.white)),
), ),
Padding( Padding(
padding: const EdgeInsets.only(right: 8.0), padding: const EdgeInsets.only(right: 8.0),
child: Text("Players (${intf.format(snapshot.data!.total)})", textAlign: TextAlign.right, style: const TextStyle(fontFamily: "Eurostile Round", fontSize: 14, fontWeight: FontWeight.w500, color: Colors.white)), child: Text(t.cutoffsDestination.players(n: intf.format(snapshot.data!.total)), textAlign: TextAlign.right, style: const TextStyle(fontFamily: "Eurostile Round", fontSize: 14, fontWeight: FontWeight.w500, color: Colors.white)),
), ),
Padding( Padding(
padding: const EdgeInsets.only(right: 8.0), padding: const EdgeInsets.only(right: 8.0),
child: TextButton(child: Text("More Info", textAlign: TextAlign.center, style: const TextStyle(fontFamily: "Eurostile Round", fontSize: 14, fontWeight: FontWeight.w500)), onPressed: () { child: TextButton(child: Text(t.cutoffsDestination.moreInfo, textAlign: TextAlign.center, style: const TextStyle(fontFamily: "Eurostile Round", fontSize: 14, fontWeight: FontWeight.w500)), onPressed: () {
Navigator.push(context, MaterialPageRoute( Navigator.push(context, MaterialPageRoute(
builder: (context) => RankView(rank: "", nextRankTR: snapshot.data!.data["top1"]!.tr, nextRankPercentile: 0.00, nextRankTargetTR: 25000.00, totalPlayers: snapshot.data!.total, cutoffTetrio: CutoffTetrio(apm: 0, pps: 0, vs: 0, pos: 0, percentile: 1, count: snapshot.data!.total, countPercentile: 1, tr: snapshot.data!.data["d"]!.tr, targetTr: snapshot.data!.data['d']!.targetTr)), builder: (context) => RankView(rank: "", nextRankTR: snapshot.data!.data["top1"]!.tr, nextRankPercentile: 0.00, nextRankTargetTR: 25000.00, totalPlayers: snapshot.data!.total, cutoffTetrio: CutoffTetrio(apm: 0, pps: 0, vs: 0, pos: 0, percentile: 1, count: snapshot.data!.total, countPercentile: 1, tr: snapshot.data!.data["d"]!.tr, targetTr: snapshot.data!.data['d']!.targetTr)),
), ),
@ -240,11 +241,11 @@ class _DestinationCutoffsState extends State<DestinationCutoffs> {
text: TextSpan( text: TextSpan(
style: const TextStyle(fontFamily: "Eurostile Round", fontSize: 14, fontWeight: FontWeight.w100, color: Colors.white, shadows: textShadow), style: const TextStyle(fontFamily: "Eurostile Round", fontSize: 14, fontWeight: FontWeight.w100, color: Colors.white, shadows: textShadow),
children: [ children: [
if (rank == "x+") TextSpan(text: "№ 1 is ${f2.format(snapshot.data!.data["top1"]!.tr)} TR", style: const TextStyle(color: Colors.white60, shadows: null)) if (rank == "x+") TextSpan(text: t.cutoffsDestination.NumberOne(tr: f2.format(snapshot.data!.data["top1"]!.tr)), style: const TextStyle(color: Colors.white60, shadows: null))
else TextSpan(text: snapshot.data!.data[ranks[ranks.indexOf(rank)+1]]!.tr > snapshot.data!.data[ranks[ranks.indexOf(rank)+1]]!.targetTr ? "Inflated on ${f2.format(snapshot.data!.data[ranks[ranks.indexOf(rank)+1]]!.tr - snapshot.data!.data[ranks[ranks.indexOf(rank)+1]]!.targetTr)} TR" : "Not inflated", style: TextStyle(color: snapshot.data!.data[ranks[ranks.indexOf(rank)+1]]!.tr > snapshot.data!.data[ranks[ranks.indexOf(rank)+1]]!.targetTr ? Colors.white :Colors.white60, shadows: null)), else TextSpan(text: snapshot.data!.data[ranks[ranks.indexOf(rank)+1]]!.tr > snapshot.data!.data[ranks[ranks.indexOf(rank)+1]]!.targetTr ? t.cutoffsDestination.inflated(tr: f2.format(snapshot.data!.data[ranks[ranks.indexOf(rank)+1]]!.tr - snapshot.data!.data[ranks[ranks.indexOf(rank)+1]]!.targetTr)) : t.cutoffsDestination.notInflated, style: TextStyle(color: snapshot.data!.data[ranks[ranks.indexOf(rank)+1]]!.tr > snapshot.data!.data[ranks[ranks.indexOf(rank)+1]]!.targetTr ? Colors.white :Colors.white60, shadows: null)),
TextSpan(text: "\n", style: const TextStyle(color: Colors.white60, shadows: null)), TextSpan(text: "\n", style: const TextStyle(color: Colors.white60, shadows: null)),
if (rank == "d") TextSpan(text: "Well...", style: const TextStyle(color: Colors.white60, shadows: null)) if (rank == "d") TextSpan(text: t.cutoffsDestination.wellDotDotDot, style: const TextStyle(color: Colors.white60, shadows: null))
else TextSpan(text: snapshot.data!.data[rank]!.tr < snapshot.data!.data[rank]!.targetTr ? "Deflated on ${f2.format(snapshot.data!.data[rank]!.targetTr - snapshot.data!.data[rank]!.tr)} TR" : "Not deflated", style: TextStyle(color: snapshot.data!.data[rank]!.tr < snapshot.data!.data[rank]!.targetTr ? Colors.white : Colors.white60, shadows: null)) else TextSpan(text: snapshot.data!.data[rank]!.tr < snapshot.data!.data[rank]!.targetTr ? t.cutoffsDestination.deflated(tr: f2.format(snapshot.data!.data[rank]!.targetTr - snapshot.data!.data[rank]!.tr)) : t.cutoffsDestination.notDeflated, style: TextStyle(color: snapshot.data!.data[rank]!.tr < snapshot.data!.data[rank]!.targetTr ? Colors.white : Colors.white60, shadows: null))
] ]
)), )),
), ),
@ -262,7 +263,7 @@ class _DestinationCutoffsState extends State<DestinationCutoffs> {
), ),
Padding( Padding(
padding: const EdgeInsets.only(right: 8.0), padding: const EdgeInsets.only(right: 8.0),
child: Text("${snapshot.data?.data[rank]?.apm != null && snapshot.data?.data[rank]?.pps != null ? f3.format(snapshot.data!.data[rank]!.apm! / (snapshot.data!.data[rank]!.pps! * 60)) : "-.---"} APP\n${snapshot.data?.data[rank]?.apm != null && snapshot.data?.data[rank]?.vs != null ? f3.format(snapshot.data!.data[rank]!.vs! / snapshot.data!.data[rank]!.apm!) : "-.---"} VS/APM", textAlign: TextAlign.right, style: TextStyle(fontFamily: "Eurostile Round", fontSize: 14, fontWeight: FontWeight.w100, color: snapshot.data?.data[rank]?.apm != null && snapshot.data?.data[rank]?.pps != null && snapshot.data?.data[rank]?.vs != null ? Colors.white : Colors.grey, shadows: textShadow)), child: Text("${snapshot.data?.data[rank]?.apm != null && snapshot.data?.data[rank]?.pps != null ? f3.format(snapshot.data!.data[rank]!.apm! / (snapshot.data!.data[rank]!.pps! * 60)) : "-.---"} ${t.stats.app.short}\n${snapshot.data?.data[rank]?.apm != null && snapshot.data?.data[rank]?.vs != null ? f3.format(snapshot.data!.data[rank]!.vs! / snapshot.data!.data[rank]!.apm!) : "-.---"} ${t.stats.vsapm.short}", textAlign: TextAlign.right, style: TextStyle(fontFamily: "Eurostile Round", fontSize: 14, fontWeight: FontWeight.w100, color: snapshot.data?.data[rank]?.apm != null && snapshot.data?.data[rank]?.pps != null && snapshot.data?.data[rank]?.vs != null ? Colors.white : Colors.grey, shadows: textShadow)),
), ),
Padding( Padding(
padding: const EdgeInsets.only(right: 8.0), padding: const EdgeInsets.only(right: 8.0),
@ -273,13 +274,13 @@ class _DestinationCutoffsState extends State<DestinationCutoffs> {
children: [ children: [
TextSpan(text: intf.format(snapshot.data!.data[rank]!.count)), TextSpan(text: intf.format(snapshot.data!.data[rank]!.count)),
TextSpan(text: " (${f2.format(snapshot.data!.data[rank]!.countPercentile * 100)}%)", style: const TextStyle(color: Colors.white60, shadows: null)), TextSpan(text: " (${f2.format(snapshot.data!.data[rank]!.countPercentile * 100)}%)", style: const TextStyle(color: Colors.white60, shadows: null)),
TextSpan(text: "\n(from № ${intf.format(snapshot.data!.data[rank]!.pos)})", style: const TextStyle(color: Colors.white60, shadows: null)) TextSpan(text: "\n(${t.cutoffsDestination.fromPlace(n: intf.format(snapshot.data!.data[rank]!.pos))})", style: const TextStyle(color: Colors.white60, shadows: null))
] ]
)) ))
), ),
Padding( Padding(
padding: const EdgeInsets.only(right: 8.0), padding: const EdgeInsets.only(right: 8.0),
child: TextButton(child: Text("View", textAlign: TextAlign.right, style: const TextStyle(fontFamily: "Eurostile Round", fontSize: 14, fontWeight: FontWeight.w500)), onPressed: () { child: TextButton(child: Text(t.cutoffsDestination.viewButton, textAlign: TextAlign.right, style: const TextStyle(fontFamily: "Eurostile Round", fontSize: 14, fontWeight: FontWeight.w500)), onPressed: () {
Navigator.push(context, MaterialPageRoute(maintainState: true, Navigator.push(context, MaterialPageRoute(maintainState: true,
builder: (context) => RankView(rank: rank, nextRankTR: rank == "x+" ? snapshot.data!.data["top1"]!.tr : snapshot.data!.data[ranks[ranks.indexOf(rank)+1]]!.tr, nextRankPercentile: rank == "x+" ? 0.00 : snapshot.data!.data[ranks[ranks.indexOf(rank)+1]]!.percentile, nextRankTargetTR: rank == "x+" ? 25000.00 : snapshot.data!.data[ranks[ranks.indexOf(rank)+1]]!.targetTr, totalPlayers: snapshot.data!.total, cutoffTetrio: snapshot.data!.data[rank]!), builder: (context) => RankView(rank: rank, nextRankTR: rank == "x+" ? snapshot.data!.data["top1"]!.tr : snapshot.data!.data[ranks[ranks.indexOf(rank)+1]]!.tr, nextRankPercentile: rank == "x+" ? 0.00 : snapshot.data!.data[ranks[ranks.indexOf(rank)+1]]!.percentile, nextRankTargetTR: rank == "x+" ? 25000.00 : snapshot.data!.data[ranks[ranks.indexOf(rank)+1]]!.targetTr, totalPlayers: snapshot.data!.total, cutoffTetrio: snapshot.data!.data[rank]!),
), ),

View File

@ -76,7 +76,7 @@ class _DestinationGraphsState extends State<DestinationGraphs> {
style: const TextStyle(fontFamily: "Eurostile Round", fontSize: 20), style: const TextStyle(fontFamily: "Eurostile Round", fontSize: 20),
), ),
), ),
Text(_gamesPlayedInsteadOfDateAndTime ? t.gamesPlayed(games: t.games(n: data.gamesPlayed)) : timestamp(data.timestamp)) Text(_gamesPlayedInsteadOfDateAndTime ? t.graphsDestination.gamesPlayed(games: t.stats.games(n: data.gamesPlayed)) : timestamp(data.timestamp))
], ],
), ),
); );
@ -145,9 +145,9 @@ class _DestinationGraphsState extends State<DestinationGraphs> {
if(fetchHistory){ if(fetchHistory){
try{ try{
var history = await teto.fetchAndsaveTLHistory(widget.searchFor); var history = await teto.fetchAndsaveTLHistory(widget.searchFor);
if (context.mounted) ScaffoldMessenger.of(context).showSnackBar(SnackBar(content: Text(t.fetchAndsaveTLHistoryResult(number: history.length)))); if (context.mounted) ScaffoldMessenger.of(context).showSnackBar(SnackBar(content: Text(t.graphsDestination.fetchAndsaveTLHistoryResult(number: history.length))));
}on TetrioHistoryNotExist{ }on TetrioHistoryNotExist{
if (context.mounted) ScaffoldMessenger.of(context).showSnackBar(SnackBar(content: Text(t.noHistorySaved))); if (context.mounted) ScaffoldMessenger.of(context).showSnackBar(SnackBar(content: Text(t.errors.noHistorySaved)));
}on P1nkl0bst3rForbidden { }on P1nkl0bst3rForbidden {
if (context.mounted) ScaffoldMessenger.of(context).showSnackBar(SnackBar(content: Text(t.errors.p1nkl0bst3rForbidden))); if (context.mounted) ScaffoldMessenger.of(context).showSnackBar(SnackBar(content: Text(t.errors.p1nkl0bst3rForbidden)));
}on P1nkl0bst3rInternalProblem { }on P1nkl0bst3rInternalProblem {
@ -208,7 +208,7 @@ class _DestinationGraphsState extends State<DestinationGraphs> {
return const Center(child: CircularProgressIndicator()); return const Center(child: CircularProgressIndicator());
case ConnectionState.done: case ConnectionState.done:
if (snapshot.hasData){ if (snapshot.hasData){
if (snapshot.data!.isEmpty || !snapshot.data!.containsKey(_season)) return ErrorThingy(eText: "Not enough data"); if (snapshot.data!.isEmpty || !snapshot.data!.containsKey(_season)) return ErrorThingy(eText: t.errors.notEnoughData);
List<_HistoryChartSpot> selectedGraph = snapshot.data![_season]![Ychart]!; List<_HistoryChartSpot> selectedGraph = snapshot.data![_season]![Ychart]!;
yAxisTitle = chartsShortTitles[Ychart]!; yAxisTitle = chartsShortTitles[Ychart]!;
return SfCartesianChart( return SfCartesianChart(
@ -394,7 +394,7 @@ class _DestinationGraphsState extends State<DestinationGraphs> {
if (graph == Graph.history) Row( if (graph == Graph.history) Row(
mainAxisSize: MainAxisSize.min, mainAxisSize: MainAxisSize.min,
children: [ children: [
const Padding(padding: EdgeInsets.all(8.0), child: Text("Season:", style: TextStyle(fontSize: 22))), Padding(padding: EdgeInsets.all(8.0), child: Text("${t.season}:", style: TextStyle(fontSize: 22))),
DropdownButton( DropdownButton(
items: [for (int i = 1; i <= currentSeason; i++) DropdownMenuItem(value: i-1, child: Text("$i"))], items: [for (int i = 1; i <= currentSeason; i++) DropdownMenuItem(value: i-1, child: Text("$i"))],
value: _season, value: _season,
@ -412,7 +412,7 @@ class _DestinationGraphsState extends State<DestinationGraphs> {
const Padding(padding: EdgeInsets.all(8.0), child: Text("X:", style: TextStyle(fontSize: 22))), const Padding(padding: EdgeInsets.all(8.0), child: Text("X:", style: TextStyle(fontSize: 22))),
DropdownButton( DropdownButton(
items: switch (graph){ items: switch (graph){
Graph.history => [DropdownMenuItem(value: false, child: Text("Date & Time")), DropdownMenuItem(value: true, child: Text("Games Played"))], Graph.history => [DropdownMenuItem(value: false, child: Text(t.graphsDestination.dateAndTime)), DropdownMenuItem(value: true, child: Text(t.stats.gp.full))],
Graph.leagueState => _yAxis, Graph.leagueState => _yAxis,
Graph.leagueCutoffs => [], Graph.leagueCutoffs => [],
}, },
@ -462,11 +462,11 @@ class _DestinationGraphsState extends State<DestinationGraphs> {
return StatefulBuilder( return StatefulBuilder(
builder: (context, StateSetter setAlertState) { builder: (context, StateSetter setAlertState) {
return AlertDialog( return AlertDialog(
title: Text("Filter ranks on graph", textAlign: TextAlign.center), title: Text(t.graphsDestination.filterModaleTitle, textAlign: TextAlign.center),
content: SingleChildScrollView( content: SingleChildScrollView(
child: Column( child: Column(
children: [ children: [
CheckboxListTile(value: getTotalFilterValue(), tristate: true, title: Text("All", style: TextStyle(fontFamily: "Eurostile Round Extended")), onChanged: (value){ CheckboxListTile(value: getTotalFilterValue(), tristate: true, title: Text(t.filterModale.all, style: TextStyle(fontFamily: "Eurostile Round Extended")), onChanged: (value){
setAlertState( setAlertState(
(){ (){
if (excludeRanks.length*2 > ranks.length){ if (excludeRanks.length*2 > ranks.length){
@ -493,7 +493,11 @@ class _DestinationGraphsState extends State<DestinationGraphs> {
), ),
actions: <Widget>[ actions: <Widget>[
TextButton( TextButton(
child: const Text("Apply"), child: Text(t.actions.cancel),
onPressed: () {Navigator.of(context).pop();}
),
TextButton(
child: Text(t.actions.apply),
onPressed: () {Navigator.of(context).pop(); setState((){futureLeague = getTetraLeagueData(_Xchart, Ychart);});} onPressed: () {Navigator.of(context).pop(); setState((){futureLeague = getTetraLeagueData(_Xchart, Ychart);});}
) )
] ]
@ -524,15 +528,15 @@ class _DestinationGraphsState extends State<DestinationGraphs> {
if (!widget.noSidebar) SegmentedButton<Graph>( if (!widget.noSidebar) SegmentedButton<Graph>(
showSelectedIcon: false, showSelectedIcon: false,
segments: <ButtonSegment<Graph>>[ segments: <ButtonSegment<Graph>>[
const ButtonSegment<Graph>( ButtonSegment<Graph>(
value: Graph.history, value: Graph.history,
label: Text('Player History')), label: Text(t.graphsNavigation.history)),
ButtonSegment<Graph>( ButtonSegment<Graph>(
value: Graph.leagueState, value: Graph.leagueState,
label: Text('League State')), label: Text(t.graphsNavigation.league)),
ButtonSegment<Graph>( ButtonSegment<Graph>(
value: Graph.leagueCutoffs, value: Graph.leagueCutoffs,
label: Text('League Cutoffs'), label: Text(t.graphsNavigation.cutoffs),
), ),
], ],
selected: <Graph>{graph}, selected: <Graph>{graph},

View File

@ -57,61 +57,61 @@ Cards rightCard = Cards.overview;
CardMod cardMod = CardMod.info; CardMod cardMod = CardMod.info;
Map<Cards, List<ButtonSegment<CardMod>>> modeButtons = { Map<Cards, List<ButtonSegment<CardMod>>> modeButtons = {
Cards.overview: [ Cards.overview: [
const ButtonSegment<CardMod>( ButtonSegment<CardMod>(
value: CardMod.info, value: CardMod.info,
label: Text('General'), label: Text(t.general),
), ),
], ],
Cards.tetraLeague: [ Cards.tetraLeague: [
const ButtonSegment<CardMod>( ButtonSegment<CardMod>(
value: CardMod.info, value: CardMod.info,
label: Text('Standing'), label: Text(t.homeNavigation.standing),
), ),
const ButtonSegment<CardMod>( ButtonSegment<CardMod>(
value: CardMod.ex, // yeah i misusing my own Enum shut the fuck up value: CardMod.ex, // yeah i misusing my own Enum shut the fuck up
label: Text('Seasons'), label: Text(t.homeNavigation.seasons),
), ),
const ButtonSegment<CardMod>( ButtonSegment<CardMod>(
value: CardMod.records, value: CardMod.records,
label: Text('Matches'), label: Text(t.homeNavigation.mathces),
), ),
], ],
Cards.quickPlay: [ Cards.quickPlay: [
const ButtonSegment<CardMod>( ButtonSegment<CardMod>(
value: CardMod.info, value: CardMod.info,
label: Text('Normal'), label: Text(t.homeNavigation.normal),
), ),
const ButtonSegment<CardMod>( ButtonSegment<CardMod>(
value: CardMod.records, value: CardMod.records,
label: Text('Records'), label: Text(t.records),
), ),
const ButtonSegment<CardMod>( ButtonSegment<CardMod>(
value: CardMod.ex, value: CardMod.ex,
label: Text('Expert'), label: Text(t.homeNavigation.expert),
), ),
const ButtonSegment<CardMod>( ButtonSegment<CardMod>(
value: CardMod.exRecords, value: CardMod.exRecords,
label: Text('Ex Records'), label: Text(t.homeNavigation.expertRecords),
) )
], ],
Cards.blitz: [ Cards.blitz: [
const ButtonSegment<CardMod>( ButtonSegment<CardMod>(
value: CardMod.info, value: CardMod.info,
label: Text('PB'), label: Text(t.homeNavigation.pb),
), ),
const ButtonSegment<CardMod>( ButtonSegment<CardMod>(
value: CardMod.records, value: CardMod.records,
label: Text('Records'), label: Text(t.recent),
) )
], ],
Cards.sprint: [ Cards.sprint: [
const ButtonSegment<CardMod>( ButtonSegment<CardMod>(
value: CardMod.info, value: CardMod.info,
label: Text('PB'), label: Text(t.homeNavigation.pb),
), ),
const ButtonSegment<CardMod>( ButtonSegment<CardMod>(
value: CardMod.records, value: CardMod.records,
label: Text('Records'), label: Text(t.recent),
) )
] ]
}; };
@ -140,7 +140,7 @@ class ZenithCard extends StatelessWidget {
fontSize: 65, fontSize: 65,
height: 1.2, height: 1.2,
)), )),
const Positioned(left: 25, top: 20, child: Text("otal time", style: TextStyle(fontFamily: "Eurostile Round Extended"))), Positioned(left: 25, top: 20, child: Text(t.stats.totalTime.widgetTitle, style: TextStyle(fontFamily: "Eurostile Round Extended"))),
Padding( Padding(
padding: const EdgeInsets.only(left: 10.0), padding: const EdgeInsets.only(left: 10.0),
child: Text(getMoreNormalTime(record!.stats.finalTime), style: const TextStyle( child: Text(getMoreNormalTime(record!.stats.finalTime), style: const TextStyle(
@ -160,11 +160,11 @@ class ZenithCard extends StatelessWidget {
0: FixedColumnWidth(36) 0: FixedColumnWidth(36)
}, },
children: [ children: [
const TableRow( TableRow(
children: [ children: [
Text("Floor"), Text(t.stats.floor),
Text("Split", textAlign: TextAlign.right), Text(t.stats.split, textAlign: TextAlign.right),
Text("Total", textAlign: TextAlign.right), Text(t.stats.total, textAlign: TextAlign.right),
] ]
), ),
for (int i = 0; i < record!.stats.zenith!.splits.length; i++) TableRow( for (int i = 0; i < record!.stats.zenith!.splits.length; i++) TableRow(
@ -196,7 +196,7 @@ class ZenithCard extends StatelessWidget {
mainAxisSize: MainAxisSize.min, mainAxisSize: MainAxisSize.min,
crossAxisAlignment: CrossAxisAlignment.center, crossAxisAlignment: CrossAxisAlignment.center,
children: [ children: [
Text(t.quickPlay, style: Theme.of(context).textTheme.titleLarge), Text(t.gamemodes["zenith"]!, style: Theme.of(context).textTheme.titleLarge),
//Text("Leaderboard reset in ${countdown(postSeasonLeft)}", textAlign: TextAlign.center), //Text("Leaderboard reset in ${countdown(postSeasonLeft)}", textAlign: TextAlign.center),
], ],
), ),
@ -307,7 +307,7 @@ class RecordCard extends StatelessWidget {
)), )),
if (record!.rank != -1) TextSpan(text: "${intf.format(record!.rank)}", style: TextStyle(color: getColorOfRank(record!.rank))), if (record!.rank != -1) TextSpan(text: "${intf.format(record!.rank)}", style: TextStyle(color: getColorOfRank(record!.rank))),
if (record!.rank != -1) const TextSpan(text: ""), if (record!.rank != -1) const TextSpan(text: ""),
if (record!.countryRank != -1) TextSpan(text: "${intf.format(record!.countryRank)} local", style: TextStyle(color: getColorOfRank(record!.countryRank))), if (record!.countryRank != -1) TextSpan(text: "${intf.format(record!.countryRank)} ${t.localStanding}", style: TextStyle(color: getColorOfRank(record!.countryRank))),
if (record!.countryRank != -1) const TextSpan(text: ""), if (record!.countryRank != -1) const TextSpan(text: ""),
TextSpan(text: timestamp(record!.timestamp)), TextSpan(text: timestamp(record!.timestamp)),
] ]
@ -332,15 +332,15 @@ class RecordCard extends StatelessWidget {
_ => "What if " _ => "What if "
}, textAlign: TextAlign.right, style: const TextStyle(fontSize: 21)), }, textAlign: TextAlign.right, style: const TextStyle(fontSize: 21)),
Text(switch(record!.gamemode){ Text(switch(record!.gamemode){
"40l" => " Pieces", "40l" => " ${t.stats.pieces.full}",
"blitz" => " Level", "blitz" => " ${t.stats.level.full}",
"5mblast" => " SPP", "5mblast" => " ${t.stats.spp.short}",
_ => " i wanted to" _ => " i wanted to"
}, textAlign: TextAlign.left, style: const TextStyle(fontSize: 21)), }, textAlign: TextAlign.left, style: const TextStyle(fontSize: 21)),
]), ]),
TableRow(children: [ TableRow(children: [
Text(f2.format(record!.stats.pps), textAlign: TextAlign.right, style: const TextStyle(fontSize: 21)), Text(f2.format(record!.stats.pps), textAlign: TextAlign.right, style: const TextStyle(fontSize: 21)),
const Text(" PPS", textAlign: TextAlign.left, style: TextStyle(fontSize: 21)), Text(" ${t.stats.pps.short}", textAlign: TextAlign.left, style: TextStyle(fontSize: 21)),
]), ]),
TableRow(children: [ TableRow(children: [
Text(switch(record!.gamemode){ Text(switch(record!.gamemode){
@ -350,9 +350,9 @@ class RecordCard extends StatelessWidget {
_ => "but god said" _ => "but god said"
}, textAlign: TextAlign.right, style: const TextStyle(fontSize: 21)), }, textAlign: TextAlign.right, style: const TextStyle(fontSize: 21)),
Text(switch(record!.gamemode){ Text(switch(record!.gamemode){
"40l" => " KPP", "40l" => " ${t.stats.kpp.short}",
"blitz" => " SPP", "blitz" => " ${t.stats.spp.short}",
"5mblast" => " Pieces", "5mblast" => " ${t.stats.pieces.short}",
_ => " no" _ => " no"
}, textAlign: TextAlign.left, style: const TextStyle(fontSize: 21)), }, textAlign: TextAlign.left, style: const TextStyle(fontSize: 21)),
]) ])
@ -365,11 +365,11 @@ class RecordCard extends StatelessWidget {
children: [ children: [
TableRow(children: [ TableRow(children: [
Text(intf.format(record!.stats.inputs), textAlign: TextAlign.right, style: const TextStyle(fontSize: 21)), Text(intf.format(record!.stats.inputs), textAlign: TextAlign.right, style: const TextStyle(fontSize: 21)),
const Text(" Key presses", textAlign: TextAlign.left, style: TextStyle(fontSize: 21)), Text(" ${t.stats.kp.short}", textAlign: TextAlign.left, style: TextStyle(fontSize: 21)),
]), ]),
TableRow(children: [ TableRow(children: [
Text(f2.format(record!.stats.kps), textAlign: TextAlign.right, style: const TextStyle(fontSize: 21)), Text(f2.format(record!.stats.kps), textAlign: TextAlign.right, style: const TextStyle(fontSize: 21)),
const Text(" KPS", textAlign: TextAlign.left, style: TextStyle(fontSize: 21)), Text(" ${t.stats.kps.short}", textAlign: TextAlign.left, style: TextStyle(fontSize: 21)),
]), ]),
TableRow(children: [ TableRow(children: [
Text(switch(record!.gamemode){ Text(switch(record!.gamemode){
@ -380,8 +380,8 @@ class RecordCard extends StatelessWidget {
}, textAlign: TextAlign.right, style: const TextStyle(fontSize: 21)), }, textAlign: TextAlign.right, style: const TextStyle(fontSize: 21)),
Text(switch(record!.gamemode){ Text(switch(record!.gamemode){
"40l" => " ", "40l" => " ",
"blitz" => " Pieces", "blitz" => " ${t.stats.pieces.short}",
"5mblast" => " Pieces", "5mblast" => " ${t.stats.pieces.short}",
_ => " no" _ => " no"
}, textAlign: TextAlign.left, style: const TextStyle(fontSize: 21)), }, textAlign: TextAlign.left, style: const TextStyle(fontSize: 21)),
]) ])
@ -402,7 +402,7 @@ class RecordCard extends StatelessWidget {
children: [ children: [
FinesseThingy(record!.stats.finesse, record!.stats.finessePercentage), FinesseThingy(record!.stats.finesse, record!.stats.finessePercentage),
LineclearsThingy(record!.stats.clears, record!.stats.lines, record!.stats.holds, record!.stats.tSpins), LineclearsThingy(record!.stats.clears, record!.stats.lines, record!.stats.holds, record!.stats.tSpins),
if (record!.gamemode == 'blitz') Text("${f2.format(record!.stats.kpp)} KPP") if (record!.gamemode == 'blitz') Text("${f2.format(record!.stats.kpp)} ${t.stats.kpp.short}")
], ],
), ),
), ),
@ -412,8 +412,8 @@ class RecordCard extends StatelessWidget {
@override @override
Widget build(BuildContext context) { Widget build(BuildContext context) {
if (record == null) { if (record == null) {
return const Card( return Card(
child: Center(child: Text("No record", style: TextStyle(fontSize: 42))), child: Center(child: Text(t.noRecord, style: TextStyle(fontSize: 42))),
); );
} }
return Column( return Column(
@ -427,9 +427,9 @@ class RecordCard extends StatelessWidget {
crossAxisAlignment: CrossAxisAlignment.center, crossAxisAlignment: CrossAxisAlignment.center,
children: [ children: [
Text(switch(record!.gamemode){ Text(switch(record!.gamemode){
"40l" => t.sprint, "40l" => t.gamemodes["40l"]!,
"blitz" => t.blitz, "blitz" => t.gamemodes["blitz"]!,
"5mblast" => "5,000,000 Blast", "5mblast" => t.gamemodes["5mblast"]!,
_ => record!.gamemode _ => record!.gamemode
}, style: Theme.of(context).textTheme.titleLarge) }, style: Theme.of(context).textTheme.titleLarge)
], ],
@ -516,7 +516,7 @@ class RecordSummary extends StatelessWidget{
"blitz" => readableIntDifference(record!.stats.score, blitzAverages[rank]!), "blitz" => readableIntDifference(record!.stats.score, blitzAverages[rank]!),
_ => record!.stats.score.toString() _ => record!.stats.score.toString()
}, verdict: betterThanRankAverage??false ? t.verdictBetter : t.verdictWorse, rank: rank!.toUpperCase())}\n", style: TextStyle( }, verdict: betterThanRankAverage??false ? t.verdictBetter : t.verdictWorse, rank: rank!.toUpperCase())}\n", style: TextStyle(
color: betterThanClosestAverage??false ? Colors.greenAccent : Colors.redAccent color: betterThanRankAverage??false ? Colors.greenAccent : Colors.redAccent
)) ))
else if ((rank == null || rank == "z") && closestAverage != null) TextSpan(text: "${t.verdictGeneral(n: switch(record!.gamemode){ else if ((rank == null || rank == "z") && closestAverage != null) TextSpan(text: "${t.verdictGeneral(n: switch(record!.gamemode){
"40l" => readableTimeDifference(record!.stats.finalTime, closestAverage!.value), "40l" => readableTimeDifference(record!.stats.finalTime, closestAverage!.value),
@ -527,7 +527,7 @@ class RecordSummary extends StatelessWidget{
)), )),
if (record!.rank != -1) TextSpan(text: "${intf.format(record!.rank)}", style: TextStyle(color: getColorOfRank(record!.rank))), if (record!.rank != -1) TextSpan(text: "${intf.format(record!.rank)}", style: TextStyle(color: getColorOfRank(record!.rank))),
if (record!.rank != -1 && record!.countryRank != -1) const TextSpan(text: ""), if (record!.rank != -1 && record!.countryRank != -1) const TextSpan(text: ""),
if (record!.countryRank != -1) TextSpan(text: "${intf.format(record!.countryRank)} local", style: TextStyle(color: getColorOfRank(record!.countryRank))), if (record!.countryRank != -1) TextSpan(text: "${intf.format(record!.countryRank)} ${t.localStanding}", style: TextStyle(color: getColorOfRank(record!.countryRank))),
const TextSpan(text: "\n"), const TextSpan(text: "\n"),
TextSpan(text: timestamp(record!.timestamp)), TextSpan(text: timestamp(record!.timestamp)),
] ]
@ -609,11 +609,11 @@ class AchievementSummary extends StatelessWidget{
style: const TextStyle(fontFamily: "Eurostile Round", fontSize: 14, color: Colors.grey), style: const TextStyle(fontFamily: "Eurostile Round", fontSize: 14, color: Colors.grey),
children: [ children: [
if (achievement!.object.isNotEmpty) TextSpan(text: "${achievement!.object}\n"), if (achievement!.object.isNotEmpty) TextSpan(text: "${achievement!.object}\n"),
if (achievement!.vt == 4) TextSpan(text: "Floor ${achievement?.a != null ? achievement!.a! : "-"}"), if (achievement!.vt == 4) TextSpan(text: "${t.stats.floor} ${achievement?.a != null ? achievement!.a! : "-"}"),
if (achievement!.vt == 4) TextSpan(text: ""), if (achievement!.vt == 4) TextSpan(text: ""),
if (achievement!.vt != 5) TextSpan(text: (achievement?.pos != null && !achievement!.pos!.isNegative) ? "${intf.format(achievement!.pos!+1)}" : "№ ---", style: TextStyle(color: achievement?.pos != null ? getColorOfRank(achievement!.pos!+1) : Colors.grey)), if (achievement!.vt != 5) TextSpan(text: (achievement?.pos != null && !achievement!.pos!.isNegative) ? "${intf.format(achievement!.pos!+1)}" : "№ ---", style: TextStyle(color: achievement?.pos != null ? getColorOfRank(achievement!.pos!+1) : Colors.grey)),
if (achievement!.vt != 5) TextSpan(text: "", style: TextStyle(color: achievement?.pos != null ? getColorOfRank(achievement!.pos!+1) : Colors.grey)), if (achievement!.vt != 5) TextSpan(text: "", style: TextStyle(color: achievement?.pos != null ? getColorOfRank(achievement!.pos!+1) : Colors.grey)),
TextSpan(text: "Top ${achievement?.pos != null ? percentagef4.format(achievement!.pos! / achievement!.total!) : "---%"}", style: TextStyle(color: achievement?.pos != null ? getColorOfRank(achievement!.pos!+1) : Colors.grey)), TextSpan(text: t.stats.top(percentage: achievement?.pos != null ? percentagef4.format(achievement!.pos! / achievement!.total!) : "---"), style: TextStyle(color: achievement?.pos != null ? getColorOfRank(achievement!.pos!+1) : Colors.grey)),
] ]
), ),
), ),
@ -653,7 +653,7 @@ class LeagueCard extends StatelessWidget{
crossAxisAlignment: CrossAxisAlignment.baseline, crossAxisAlignment: CrossAxisAlignment.baseline,
textBaseline: TextBaseline.alphabetic, textBaseline: TextBaseline.alphabetic,
children: [ children: [
Text("Season ${league.season}", style: Theme.of(context).textTheme.titleSmall), Text("${t.season} ${league.season}", style: Theme.of(context).textTheme.titleSmall),
Spacer(), Spacer(),
Text( Text(
"${seasonStarts.elementAtOrNull(league.season - 1) != null ? timestamp(seasonStarts[league.season - 1]) : "---"}${seasonEnds.elementAtOrNull(league.season - 1) != null ? timestamp(seasonEnds[league.season - 1]) : "---"}", "${seasonStarts.elementAtOrNull(league.season - 1) != null ? timestamp(seasonStarts[league.season - 1]) : "---"}${seasonEnds.elementAtOrNull(league.season - 1) != null ? timestamp(seasonEnds[league.season - 1]) : "---"}",
@ -663,14 +663,14 @@ class LeagueCard extends StatelessWidget{
) : Column( ) : Column(
crossAxisAlignment: CrossAxisAlignment.center, crossAxisAlignment: CrossAxisAlignment.center,
children: [ children: [
Text("Season ${league.season}", style: Theme.of(context).textTheme.titleSmall), Text("${t.season} ${league.season}", style: Theme.of(context).textTheme.titleSmall),
Text( Text(
"${seasonStarts.elementAtOrNull(league.season - 1) != null ? timestamp(seasonStarts[league.season - 1]) : "---"}${seasonEnds.elementAtOrNull(league.season - 1) != null ? timestamp(seasonEnds[league.season - 1]) : "---"}", "${seasonStarts.elementAtOrNull(league.season - 1) != null ? timestamp(seasonStarts[league.season - 1]) : "---"}${seasonEnds.elementAtOrNull(league.season - 1) != null ? timestamp(seasonEnds[league.season - 1]) : "---"}",
textAlign: TextAlign.center, textAlign: TextAlign.center,
style: TextStyle(color: Colors.grey)), style: TextStyle(color: Colors.grey)),
], ],
) )
else Text("Tetra League", style: Theme.of(context).textTheme.titleSmall), else Text(t.gamemodes["league"]!, style: Theme.of(context).textTheme.titleSmall),
const Divider(), const Divider(),
TLRatingThingy(userID: league.id, tlData: league, showPositions: true), TLRatingThingy(userID: league.id, tlData: league, showPositions: true),
const Divider(), const Divider(),
@ -679,15 +679,15 @@ class LeagueCard extends StatelessWidget{
text: TextSpan( text: TextSpan(
style: const TextStyle(fontFamily: "Eurostile Round", color: Colors.grey), style: const TextStyle(fontFamily: "Eurostile Round", color: Colors.grey),
children: [ children: [
TextSpan(text: "${league.apm != null ? f2.format(league.apm) : "-.--"} APM", style: TextStyle(color: league.apm != null ? getStatColor(league.apm!, averages?.apm, true) : null)), TextSpan(text: "${league.apm != null ? f2.format(league.apm) : "-.--"} ${t.stats.apm.short}", style: TextStyle(color: league.apm != null ? getStatColor(league.apm!, averages?.apm, true) : null)),
TextSpan(text: ""), TextSpan(text: ""),
TextSpan(text: "${league.pps != null ? f2.format(league.pps) : "-.--"} PPS", style: TextStyle(color: league.pps != null ? getStatColor(league.pps!, averages?.pps, true) : null)), TextSpan(text: "${league.pps != null ? f2.format(league.pps) : "-.--"} ${t.stats.pps.short}", style: TextStyle(color: league.pps != null ? getStatColor(league.pps!, averages?.pps, true) : null)),
TextSpan(text: ""), TextSpan(text: ""),
TextSpan(text: "${league.vs != null ? f2.format(league.vs) : "-.--"} VS", style: TextStyle(color: league.vs != null ? getStatColor(league.vs!, averages?.vs, true) : null)), TextSpan(text: "${league.vs != null ? f2.format(league.vs) : "-.--"} ${t.stats.vs.short}", style: TextStyle(color: league.vs != null ? getStatColor(league.vs!, averages?.vs, true) : null)),
TextSpan(text: ""), TextSpan(text: ""),
TextSpan(text: "${league.nerdStats != null ? f2.format(league.nerdStats!.app) : "-.--"} APP", style: TextStyle(color: league.nerdStats != null ? getStatColor(league.nerdStats!.app, averages?.nerdStats?.app, true) : null)), TextSpan(text: "${league.nerdStats != null ? f2.format(league.nerdStats!.app) : "-.--"} ${t.stats.app.short}", style: TextStyle(color: league.nerdStats != null ? getStatColor(league.nerdStats!.app, averages?.nerdStats?.app, true) : null)),
TextSpan(text: ""), TextSpan(text: ""),
TextSpan(text: "${league.nerdStats != null ? f2.format(league.nerdStats!.vsapm) : "-.--"} VS/APM", style: TextStyle(color: league.nerdStats != null ? getStatColor(league.nerdStats!.vsapm, averages?.nerdStats?.vsapm, true) : null)), TextSpan(text: "${league.nerdStats != null ? f2.format(league.nerdStats!.vsapm) : "-.--"} ${t.stats.vsapm.short}", style: TextStyle(color: league.nerdStats != null ? getStatColor(league.nerdStats!.vsapm, averages?.nerdStats?.vsapm, true) : null)),
] ]
)), )),
], ],
@ -712,7 +712,6 @@ class _DestinationHomeState extends State<DestinationHome> with SingleTickerProv
Widget getOverviewCard(Summaries summaries, CutoffTetrio? averages, double width){ Widget getOverviewCard(Summaries summaries, CutoffTetrio? averages, double width){
return LayoutGrid( return LayoutGrid(
// ASCII-art named areas 🔥
areas: width > 600 ? ''' areas: width > 600 ? '''
h h h h
t t t t
@ -730,13 +729,10 @@ class _DestinationHomeState extends State<DestinationHome> with SingleTickerProv
6 6
7 7
''', ''',
// Concise track sizing extension methods 🔥
columnSizes: width > 600 ? [auto, auto] : [auto], columnSizes: width > 600 ? [auto, auto] : [auto],
rowSizes: width > 600 ? [auto, auto, auto, auto, auto, auto] : [auto, auto, auto, auto, auto, auto, auto, auto], rowSizes: width > 600 ? [auto, auto, auto, auto, auto, auto] : [auto, auto, auto, auto, auto, auto, auto, auto],
// Column and row gaps! 🔥
columnGap: 0, columnGap: 0,
rowGap: 0, rowGap: 0,
// Handy grid placement extension methods on Widget 🔥
children: [ children: [
if (width > 600) Card( if (width > 600) Card(
child: Padding( child: Padding(
@ -746,7 +742,7 @@ class _DestinationHomeState extends State<DestinationHome> with SingleTickerProv
mainAxisSize: MainAxisSize.min, mainAxisSize: MainAxisSize.min,
crossAxisAlignment: CrossAxisAlignment.center, crossAxisAlignment: CrossAxisAlignment.center,
children: [ children: [
Text("Overview", style: TextStyle(fontFamily: "Eurostile Round Extended", fontSize: 42)), Text(t.homeNavigation.overview, style: TextStyle(fontFamily: "Eurostile Round Extended", fontSize: 42)),
], ],
), ),
), ),
@ -759,7 +755,7 @@ class _DestinationHomeState extends State<DestinationHome> with SingleTickerProv
child: Column( child: Column(
crossAxisAlignment: CrossAxisAlignment.center, crossAxisAlignment: CrossAxisAlignment.center,
children: [ children: [
Text("40 Lines", style: Theme.of(context).textTheme.titleSmall), Text(t.gamemodes['40l']!, style: Theme.of(context).textTheme.titleSmall),
const Divider(), const Divider(),
RecordSummary(record: summaries.sprint, betterThanClosestAverage: sprintBetterThanClosestAverage, betterThanRankAverage: sprintBetterThanRankAverage, closestAverage: closestAverageSprint, rank: summaries.league.percentileRank), RecordSummary(record: summaries.sprint, betterThanClosestAverage: sprintBetterThanClosestAverage, betterThanRankAverage: sprintBetterThanRankAverage, closestAverage: closestAverageSprint, rank: summaries.league.percentileRank),
const Divider(), const Divider(),
@ -774,7 +770,7 @@ class _DestinationHomeState extends State<DestinationHome> with SingleTickerProv
child: Column( child: Column(
crossAxisAlignment: CrossAxisAlignment.center, crossAxisAlignment: CrossAxisAlignment.center,
children: [ children: [
Text("Blitz", style: Theme.of(context).textTheme.titleSmall), Text(t.gamemodes['blitz']!, style: Theme.of(context).textTheme.titleSmall),
const Divider(), const Divider(),
RecordSummary(record: summaries.blitz, betterThanClosestAverage: blitzBetterThanClosestAverage, betterThanRankAverage: blitzBetterThanRankAverage, closestAverage: closestAverageBlitz, rank: summaries.league.percentileRank), RecordSummary(record: summaries.blitz, betterThanClosestAverage: blitzBetterThanClosestAverage, betterThanRankAverage: blitzBetterThanRankAverage, closestAverage: closestAverageBlitz, rank: summaries.league.percentileRank),
const Divider(), const Divider(),
@ -789,11 +785,11 @@ class _DestinationHomeState extends State<DestinationHome> with SingleTickerProv
child: Column( child: Column(
crossAxisAlignment: CrossAxisAlignment.center, crossAxisAlignment: CrossAxisAlignment.center,
children: [ children: [
Text("QP", style: Theme.of(context).textTheme.titleSmall), Text(t.gamemodes['zenith']!, style: Theme.of(context).textTheme.titleSmall),
const Divider(), const Divider(),
RecordSummary(record: summaries.zenith != null ? summaries.zenith : summaries.zenithCareerBest, hideRank: true, old: summaries.zenith == null), RecordSummary(record: summaries.zenith != null ? summaries.zenith : summaries.zenithCareerBest, hideRank: true, old: summaries.zenith == null),
const Divider(), const Divider(),
Text("Overall PB: ${(summaries.achievements.isNotEmpty && summaries.achievements.firstWhere((e) => e.k == 18).v != null) ? f2.format(summaries.achievements.firstWhere((e) => e.k == 18).v!) : "-.--"} m", style: const TextStyle(color: Colors.grey)) Text(t.overallPB(pb: (summaries.achievements.isNotEmpty && summaries.achievements.firstWhere((e) => e.k == 18).v != null) ? f2.format(summaries.achievements.firstWhere((e) => e.k == 18).v!) : "-.--"), style: const TextStyle(color: Colors.grey))
], ],
), ),
), ),
@ -804,11 +800,11 @@ class _DestinationHomeState extends State<DestinationHome> with SingleTickerProv
child: Column( child: Column(
crossAxisAlignment: CrossAxisAlignment.center, crossAxisAlignment: CrossAxisAlignment.center,
children: [ children: [
Text("QP Expert", style: Theme.of(context).textTheme.titleSmall), Text(t.gamemodes['zenithex']!, style: Theme.of(context).textTheme.titleSmall),
const Divider(), const Divider(),
RecordSummary(record: summaries.zenithEx != null ? summaries.zenithEx : summaries.zenithExCareerBest, hideRank: true, old: summaries.zenith == null), RecordSummary(record: summaries.zenithEx != null ? summaries.zenithEx : summaries.zenithExCareerBest, hideRank: true, old: summaries.zenith == null),
const Divider(), const Divider(),
Text("Overall PB: ${(summaries.achievements.isNotEmpty && summaries.achievements.firstWhere((e) => e.k == 19).v != null) ? f2.format(summaries.achievements.firstWhere((e) => e.k == 19).v!) : "-.--"} m", style: const TextStyle(color: Colors.grey)) Text(t.overallPB(pb: (summaries.achievements.isNotEmpty && summaries.achievements.firstWhere((e) => e.k == 19).v != null) ? f2.format(summaries.achievements.firstWhere((e) => e.k == 19).v!) : "-.--"), style: const TextStyle(color: Colors.grey))
], ],
), ),
), ),
@ -819,10 +815,10 @@ class _DestinationHomeState extends State<DestinationHome> with SingleTickerProv
child: Column( child: Column(
crossAxisAlignment: CrossAxisAlignment.center, crossAxisAlignment: CrossAxisAlignment.center,
children: [ children: [
Center(child: Text("Zen", style: Theme.of(context).textTheme.titleSmall)), Center(child: Text(t.gamemodes['zen']!, style: Theme.of(context).textTheme.titleSmall)),
Text("Level ${intf.format(summaries.zen.level)}", style: const TextStyle(fontFamily: "Eurostile Round", fontSize: 36, fontWeight: FontWeight.w500, color: Colors.white)), Text("${t.stats.level.full} ${intf.format(summaries.zen.level)}", style: const TextStyle(fontFamily: "Eurostile Round", fontSize: 36, fontWeight: FontWeight.w500, color: Colors.white)),
Text("Score ${intf.format(summaries.zen.score)}"), Text("${t.stats.score} ${intf.format(summaries.zen.score)}"),
Text("Level up requirement: ${intf.format(summaries.zen.scoreRequirement)}", style: const TextStyle(color: Colors.grey)) Text(t.stats.levelUpRequirement(p: intf.format(summaries.zen.scoreRequirement)), style: const TextStyle(color: Colors.grey))
], ],
), ),
), ),
@ -841,7 +837,7 @@ class _DestinationHomeState extends State<DestinationHome> with SingleTickerProv
fontSize: 65, fontSize: 65,
height: 1.2, height: 1.2,
)), )),
const Positioned(left: 25, top: 20, child: Text("inesse", style: TextStyle(fontFamily: "Eurostile Round Extended"))), Positioned(left: 25, top: 20, child: Text(t.stats.finesse.widgetTitle, style: TextStyle(fontFamily: "Eurostile Round Extended"))),
Padding( Padding(
padding: const EdgeInsets.only(left: 10.0), padding: const EdgeInsets.only(left: 10.0),
child: Text("${(summaries.achievements.isNotEmpty && summaries.achievements.firstWhere((e) => e.k == 4).v != null && summaries.achievements.firstWhere((e) => e.k == 1).v != null) ? child: Text("${(summaries.achievements.isNotEmpty && summaries.achievements.firstWhere((e) => e.k == 4).v != null && summaries.achievements.firstWhere((e) => e.k == 1).v != null) ?
@ -857,14 +853,14 @@ class _DestinationHomeState extends State<DestinationHome> with SingleTickerProv
), ),
Row( Row(
children: [ children: [
const Text("Total pieces placed:"), Text("${t.stats.piecesTotal}:"),
const Spacer(), const Spacer(),
Text((summaries.achievements.isNotEmpty && summaries.achievements.firstWhere((e) => e.k == 1).v != null) ? intf.format(summaries.achievements.firstWhere((e) => e.k == 1).v!) : "---"), Text((summaries.achievements.isNotEmpty && summaries.achievements.firstWhere((e) => e.k == 1).v != null) ? intf.format(summaries.achievements.firstWhere((e) => e.k == 1).v!) : "---"),
], ],
), ),
Row( Row(
children: [ children: [
const Text(" - Placed with perfect finesse:"), Text(" - ${t.stats.piecesWithPerfectFinesse}:"),
const Spacer(), const Spacer(),
Text((summaries.achievements.isNotEmpty && summaries.achievements.firstWhere((e) => e.k == 4).v != null) ? intf.format(summaries.achievements.firstWhere((e) => e.k == 4).v!) : "---"), Text((summaries.achievements.isNotEmpty && summaries.achievements.firstWhere((e) => e.k == 4).v != null) ? intf.format(summaries.achievements.firstWhere((e) => e.k == 4).v!) : "---"),
], ],
@ -873,7 +869,7 @@ class _DestinationHomeState extends State<DestinationHome> with SingleTickerProv
), ),
), ),
).inGridArea('6'), ).inGridArea('6'),
Card( if (summaries.achievements.isNotEmpty) Card(
child: Padding( child: Padding(
padding: const EdgeInsets.fromLTRB(20.0, 0.0, 20.0, 0.0), padding: const EdgeInsets.fromLTRB(20.0, 0.0, 20.0, 0.0),
child: Column( child: Column(
@ -913,7 +909,7 @@ class _DestinationHomeState extends State<DestinationHome> with SingleTickerProv
mainAxisSize: MainAxisSize.min, mainAxisSize: MainAxisSize.min,
crossAxisAlignment: CrossAxisAlignment.center, crossAxisAlignment: CrossAxisAlignment.center,
children: [ children: [
Text(t.tetraLeague, style: Theme.of(context).textTheme.titleLarge), Text(t.gamemodes["league"]!, style: Theme.of(context).textTheme.titleLarge),
//Text("${states.last.timestamp} ${states.last.tr}", textAlign: TextAlign.center) //Text("${states.last.timestamp} ${states.last.tr}", textAlign: TextAlign.center)
], ],
), ),
@ -949,7 +945,7 @@ class _DestinationHomeState extends State<DestinationHome> with SingleTickerProv
mainAxisSize: MainAxisSize.min, mainAxisSize: MainAxisSize.min,
crossAxisAlignment: CrossAxisAlignment.center, crossAxisAlignment: CrossAxisAlignment.center,
children: [ children: [
Text("Previous Seasons", style: Theme.of(context).textTheme.titleLarge, textAlign: TextAlign.center), Text(t.previousSeasons, style: Theme.of(context).textTheme.titleLarge, textAlign: TextAlign.center),
//Text("${t.seasonStarts} ${countdown(postSeasonLeft)}", textAlign: TextAlign.center) //Text("${t.seasonStarts} ${countdown(postSeasonLeft)}", textAlign: TextAlign.center)
], ],
), ),
@ -966,7 +962,7 @@ class _DestinationHomeState extends State<DestinationHome> with SingleTickerProv
Widget getListOfRecords(String recentStream, String topStream, BoxConstraints constraints){ Widget getListOfRecords(String recentStream, String topStream, BoxConstraints constraints){
return Column( return Column(
children: [ children: [
const Card( Card(
child: Padding( child: Padding(
padding: EdgeInsets.only(bottom: 4.0), padding: EdgeInsets.only(bottom: 4.0),
child: Center( child: Center(
@ -974,7 +970,7 @@ class _DestinationHomeState extends State<DestinationHome> with SingleTickerProv
mainAxisSize: MainAxisSize.min, mainAxisSize: MainAxisSize.min,
crossAxisAlignment: CrossAxisAlignment.center, crossAxisAlignment: CrossAxisAlignment.center,
children: [ children: [
Text("Records", style: TextStyle(fontFamily: "Eurostile Round Extended", fontSize: 42)), Text(t.records, style: TextStyle(fontFamily: "Eurostile Round Extended", fontSize: 42)),
//Text("${t.seasonStarts} ${countdown(postSeasonLeft)}", textAlign: TextAlign.center) //Text("${t.seasonStarts} ${countdown(postSeasonLeft)}", textAlign: TextAlign.center)
], ],
), ),
@ -987,10 +983,10 @@ class _DestinationHomeState extends State<DestinationHome> with SingleTickerProv
child: Column( child: Column(
mainAxisSize: MainAxisSize.min, mainAxisSize: MainAxisSize.min,
children: [ children: [
const TabBar( TabBar(
tabs: [ tabs: [
Tab(text: "Recent"), Tab(text: t.recent),
Tab(text: "Top"), Tab(text: t.top),
], ],
), ),
SizedBox( SizedBox(
@ -1026,10 +1022,10 @@ class _DestinationHomeState extends State<DestinationHome> with SingleTickerProv
title: Text( title: Text(
switch (snapshot.data!.records[i].gamemode){ switch (snapshot.data!.records[i].gamemode){
"40l" => get40lTime(snapshot.data!.records[i].stats.finalTime.inMicroseconds), "40l" => get40lTime(snapshot.data!.records[i].stats.finalTime.inMicroseconds),
"blitz" => t.blitzScore(p: NumberFormat.decimalPattern().format(snapshot.data!.records[i].stats.score)), "blitz" => t.stats.blitzScore(p: NumberFormat.decimalPattern().format(snapshot.data!.records[i].stats.score)),
"5mblast" => get40lTime(snapshot.data!.records[i].stats.finalTime.inMicroseconds), "5mblast" => get40lTime(snapshot.data!.records[i].stats.finalTime.inMicroseconds),
"zenith" => "${f2.format(snapshot.data!.records[i].stats.zenith!.altitude)} m${(snapshot.data!.records[i].extras as ZenithExtras).mods.isNotEmpty ? " (${t.withModsPlural(n: (snapshot.data!.records[i].extras as ZenithExtras).mods.length)})" : ""}", "zenith" => "${f2.format(snapshot.data!.records[i].stats.zenith!.altitude)} m${(snapshot.data!.records[i].extras as ZenithExtras).mods.isNotEmpty ? " (${t.stats.qpWithMods(n: (snapshot.data!.records[i].extras as ZenithExtras).mods.length)})" : ""}",
"zenithex" => "${f2.format(snapshot.data!.records[i].stats.zenith!.altitude)} m${(snapshot.data!.records[i].extras as ZenithExtras).mods.isNotEmpty ? " (${t.withModsPlural(n: (snapshot.data!.records[i].extras as ZenithExtras).mods.length)})" : ""}", "zenithex" => "${f2.format(snapshot.data!.records[i].stats.zenith!.altitude)} m${(snapshot.data!.records[i].extras as ZenithExtras).mods.isNotEmpty ? " (${t.stats.qpWithMods(n: (snapshot.data!.records[i].extras as ZenithExtras).mods.length)})" : ""}",
String() => "huh", String() => "huh",
}, },
style: Theme.of(context).textTheme.displayLarge), style: Theme.of(context).textTheme.displayLarge),
@ -1067,10 +1063,10 @@ class _DestinationHomeState extends State<DestinationHome> with SingleTickerProv
title: Text( title: Text(
switch (snapshot.data!.records[i].gamemode){ switch (snapshot.data!.records[i].gamemode){
"40l" => get40lTime(snapshot.data!.records[i].stats.finalTime.inMicroseconds), "40l" => get40lTime(snapshot.data!.records[i].stats.finalTime.inMicroseconds),
"blitz" => t.blitzScore(p: NumberFormat.decimalPattern().format(snapshot.data!.records[i].stats.score)), "blitz" => t.stats.blitzScore(p: NumberFormat.decimalPattern().format(snapshot.data!.records[i].stats.score)),
"5mblast" => get40lTime(snapshot.data!.records[i].stats.finalTime.inMicroseconds), "5mblast" => get40lTime(snapshot.data!.records[i].stats.finalTime.inMicroseconds),
"zenith" => "${f2.format(snapshot.data!.records[i].stats.zenith!.altitude)} m${(snapshot.data!.records[i].extras as ZenithExtras).mods.isNotEmpty ? " (${t.withModsPlural(n: (snapshot.data!.records[i].extras as ZenithExtras).mods.length)})" : ""}", "zenith" => "${f2.format(snapshot.data!.records[i].stats.zenith!.altitude)} m${(snapshot.data!.records[i].extras as ZenithExtras).mods.isNotEmpty ? " (${t.stats.qpWithMods(n: (snapshot.data!.records[i].extras as ZenithExtras).mods.length)})" : ""}",
"zenithex" => "${f2.format(snapshot.data!.records[i].stats.zenith!.altitude)} m${(snapshot.data!.records[i].extras as ZenithExtras).mods.isNotEmpty ? " (${t.withModsPlural(n: (snapshot.data!.records[i].extras as ZenithExtras).mods.length)})" : ""}", "zenithex" => "${f2.format(snapshot.data!.records[i].stats.zenith!.altitude)} m${(snapshot.data!.records[i].extras as ZenithExtras).mods.isNotEmpty ? " (${t.stats.qpWithMods(n: (snapshot.data!.records[i].extras as ZenithExtras).mods.length)})" : ""}",
String() => "huh", String() => "huh",
}, },
style: Theme.of(context).textTheme.displayLarge), style: Theme.of(context).textTheme.displayLarge),

View File

@ -78,8 +78,8 @@ class _DestinationInfo extends State<DestinationInfo> {
height: widget.constraints.maxHeight - 77, height: widget.constraints.maxHeight - 77,
viewportWidth: widget.constraints.maxWidth, viewportWidth: widget.constraints.maxWidth,
assetLink: "res/images/info card 1 focus.png", assetLink: "res/images/info card 1 focus.png",
title: "40 Lines & Blitz Averages", title: t.infoDestination.sprintAndBlitzAverages,
description: "Since calculating 40 Lines & Blitz averages is tedious process, it gets updated only once in a while. Click on the title of this card to see the full 40 Lines & Blitz averages table\n\n${t.sprintAndBlitsRelevance(date: DateFormat.yMMMd(LocaleSettings.currentLocale.languageCode).format(sprintAndBlitzRelevance))}", description: "${t.infoDestination.sprintAndBlitzAveragesDescription}\n\n${t.sprintAndBlitsRelevance(date: DateFormat.yMMMd(LocaleSettings.currentLocale.languageCode).format(sprintAndBlitzRelevance))}",
onPressed: (){ onPressed: (){
Navigator.push(context, MaterialPageRoute( Navigator.push(context, MaterialPageRoute(
builder: (context) => SprintAndBlitzView(), builder: (context) => SprintAndBlitzView(),
@ -90,8 +90,8 @@ class _DestinationInfo extends State<DestinationInfo> {
height: widget.constraints.maxHeight - 77, height: widget.constraints.maxHeight - 77,
viewportWidth: widget.constraints.maxWidth, viewportWidth: widget.constraints.maxWidth,
assetLink: "res/images/Снимок экрана_2023-11-06_01-00-50.png", assetLink: "res/images/Снимок экрана_2023-11-06_01-00-50.png",
title: "Tetra Stats Wiki", title: t.infoDestination.tetraStatsWiki,
description: "Find more information about Tetra Stats functions and statictic, that it provides", description: t.infoDestination.tetraStatsWikiDescription,
onPressed: (){ onPressed: (){
launchInBrowser(Uri.https("github.com", "dan63047/TetraStats/wiki")); launchInBrowser(Uri.https("github.com", "dan63047/TetraStats/wiki"));
} }
@ -100,8 +100,8 @@ class _DestinationInfo extends State<DestinationInfo> {
height: widget.constraints.maxHeight - 77, height: widget.constraints.maxHeight - 77,
viewportWidth: widget.constraints.maxWidth, viewportWidth: widget.constraints.maxWidth,
assetLink: "res/images/Снимок экрана_2023-11-06_01-00-50.png", assetLink: "res/images/Снимок экрана_2023-11-06_01-00-50.png",
title: "About Tetra Stats", title: t.infoDestination.about,
description: "Developed by dan63\n", description: t.infoDestination.aboutDescription,
onPressed: (){ onPressed: (){
Navigator.push(context, MaterialPageRoute( Navigator.push(context, MaterialPageRoute(
builder: (context) => AboutView(), builder: (context) => AboutView(),
@ -114,7 +114,7 @@ class _DestinationInfo extends State<DestinationInfo> {
mainAxisSize: MainAxisSize.min, mainAxisSize: MainAxisSize.min,
children: [ children: [
Card( Card(
child: Center(child: Text("Information Center", style: Theme.of(context).textTheme.titleLarge)), child: Center(child: Text(t.infoDestination.title, style: Theme.of(context).textTheme.titleLarge)),
), ),
SingleChildScrollView( SingleChildScrollView(
scrollDirection: Axis.horizontal, scrollDirection: Axis.horizontal,

View File

@ -37,14 +37,14 @@ enum Leaderboards{
class _DestinationLeaderboardsState extends State<DestinationLeaderboards> { class _DestinationLeaderboardsState extends State<DestinationLeaderboards> {
//Duration postSeasonLeft = seasonStart.difference(DateTime.now()); //Duration postSeasonLeft = seasonStart.difference(DateTime.now());
final Map<Leaderboards, String> leaderboards = { final Map<Leaderboards, String> leaderboards = {
Leaderboards.tl: "Tetra League (Current Season)", Leaderboards.tl: t.leaderboardsDestination.tl,
Leaderboards.fullTL: "Tetra League (Current Season, full one)", Leaderboards.fullTL: t.leaderboardsDestination.fullTL,
Leaderboards.xp: "XP", Leaderboards.xp: t.stats.xp.full,
Leaderboards.ar: "Acievement Points", Leaderboards.ar: t.leaderboardsDestination.ar,
Leaderboards.sprint: "40 Lines", Leaderboards.sprint: t.gamemodes["40l"]!,
Leaderboards.blitz: "Blitz", Leaderboards.blitz: t.gamemodes["blitz"]!,
Leaderboards.zenith: "Quick Play", Leaderboards.zenith: t.gamemodes["zenith"]!,
Leaderboards.zenithex: "Quick Play Expert", Leaderboards.zenithex: t.gamemodes["zenithex"]!,
}; };
Leaderboards _currentLb = Leaderboards.tl; Leaderboards _currentLb = Leaderboards.tl;
final StreamController<List<dynamic>> _dataStreamController = StreamController<List<dynamic>>.broadcast(); final StreamController<List<dynamic>> _dataStreamController = StreamController<List<dynamic>>.broadcast();
@ -342,7 +342,7 @@ class _DestinationLeaderboardsState extends State<DestinationLeaderboards> {
mainAxisSize: MainAxisSize.min, mainAxisSize: MainAxisSize.min,
children: [ children: [
Spacer(), Spacer(),
Text("Leaderboards", style: Theme.of(context).textTheme.headlineMedium!.copyWith(fontSize: 32)), Text(t.leaderboardsDestination.title, style: Theme.of(context).textTheme.headlineMedium!.copyWith(fontSize: 32)),
Spacer() Spacer()
], ],
), ),
@ -355,7 +355,7 @@ class _DestinationLeaderboardsState extends State<DestinationLeaderboards> {
child: ListTile( child: ListTile(
title: Text(leaderboards.values.elementAt(index)), title: Text(leaderboards.values.elementAt(index)),
trailing: Icon(Icons.arrow_right, color: _currentLb.index == index ? Colors.white : Colors.grey), trailing: Icon(Icons.arrow_right, color: _currentLb.index == index ? Colors.white : Colors.grey),
subtitle: index == 1 ? Text("Heavy, but allows you to sort players by their stats and filter them by ranks", style: TextStyle(color: Colors.grey, fontSize: 12)) : null, subtitle: index == 1 ? Text(t.leaderboardsDestination.fullTLnote, style: TextStyle(color: Colors.grey, fontSize: 12)) : null,
onTap: () { onTap: () {
if (widget.constraints.maxWidth <= transformThreshold) Navigator.push( if (widget.constraints.maxWidth <= transformThreshold) Navigator.push(
context, context,
@ -366,7 +366,7 @@ class _DestinationLeaderboardsState extends State<DestinationLeaderboards> {
padding: const EdgeInsets.fromLTRB(0.0, 12.0, 0.0, 0.0), padding: const EdgeInsets.fromLTRB(0.0, 12.0, 0.0, 0.0),
child: FloatingActionButton( child: FloatingActionButton(
onPressed: () => Navigator.pop(context), onPressed: () => Navigator.pop(context),
tooltip: 'Fuck go back', tooltip: t.goBackButton,
child: const Icon(Icons.arrow_back), child: const Icon(Icons.arrow_back),
), ),
), ),

View File

@ -42,7 +42,7 @@ class _DestinationSavedData extends State<DestinationSavedData> {
leading: IconButton( leading: IconButton(
onPressed: () { onPressed: () {
teto.deleteState(data.id+data.timestamp.millisecondsSinceEpoch.toRadixString(16)).then((value) => setState(() { teto.deleteState(data.id+data.timestamp.millisecondsSinceEpoch.toRadixString(16)).then((value) => setState(() {
ScaffoldMessenger.of(context).showSnackBar(SnackBar(content: Text(t.stateRemoved(date: timestamp(data.timestamp))))); ScaffoldMessenger.of(context).showSnackBar(SnackBar(content: Text(t.snackBarMessages.stateRemoved(date: timestamp(data.timestamp)))));
})); }));
}, },
icon: Icon(Icons.delete_forever) icon: Icon(Icons.delete_forever)
@ -165,7 +165,7 @@ class _DestinationSavedData extends State<DestinationSavedData> {
padding: const EdgeInsets.fromLTRB(0.0, 12.0, 0.0, 0.0), padding: const EdgeInsets.fromLTRB(0.0, 12.0, 0.0, 0.0),
child: FloatingActionButton( child: FloatingActionButton(
onPressed: () => Navigator.pop(context), onPressed: () => Navigator.pop(context),
tooltip: 'Fuck go back', tooltip: t.goBackButton,
child: const Icon(Icons.arrow_back), child: const Icon(Icons.arrow_back),
), ),
), ),

View File

@ -355,9 +355,9 @@ class _DestinationSettings extends State<DestinationSettings> with SingleTickerP
trailing: DropdownButton( trailing: DropdownButton(
value: timestampMode, value: timestampMode,
items: <DropdownMenuItem>[ items: <DropdownMenuItem>[
DropdownMenuItem(value: 0, child: Text(t.timestampsAbsoluteGMT)), DropdownMenuItem(value: 0, child: Text(t.settingsDestination.timestampsAbsoluteGMT)),
DropdownMenuItem(value: 1, child: Text(t.timestampsAbsoluteLocalTime)), DropdownMenuItem(value: 1, child: Text(t.settingsDestination.timestampsAbsoluteLocalTime)),
DropdownMenuItem(value: 2, child: Text(t.timestampsRelative)) DropdownMenuItem(value: 2, child: Text(t.settingsDestination.timestampsRelative))
], ],
onChanged: (dynamic value){ onChanged: (dynamic value){
prefs.setInt("timestampMode", value); prefs.setInt("timestampMode", value);
@ -491,7 +491,7 @@ class _DestinationSettings extends State<DestinationSettings> with SingleTickerP
title: Text("Export Database", style: Theme.of(context).textTheme.displayLarge), title: Text("Export Database", style: Theme.of(context).textTheme.displayLarge),
onTap: () { onTap: () {
if (kIsWeb){ if (kIsWeb){
ScaffoldMessenger.of(context).showSnackBar(SnackBar(content: Text(t.notForWeb))); ScaffoldMessenger.of(context).showSnackBar(SnackBar(content: Text(t.snackBarMessages.notForWeb)));
} else if (Platform.isAndroid){ } else if (Platform.isAndroid){
var downloadFolder = Directory("/storage/emulated/0/Download"); var downloadFolder = Directory("/storage/emulated/0/Download");
File exportedDB = File("${downloadFolder.path}/TetraStats.db"); File exportedDB = File("${downloadFolder.path}/TetraStats.db");
@ -500,15 +500,15 @@ class _DestinationSettings extends State<DestinationSettings> with SingleTickerP
showDialog( showDialog(
context: context, context: context,
builder: (BuildContext context) => AlertDialog( builder: (BuildContext context) => AlertDialog(
title: Text(t.androidExportAlertTitle, title: Text(t.settingsDestination.androidExportAlertTitle,
style: const TextStyle( style: const TextStyle(
fontFamily: "Eurostile Round Extended")), fontFamily: "Eurostile Round Extended")),
content: SingleChildScrollView( content: SingleChildScrollView(
child: ListBody(children: [Text(t.androidExportText(exportedDB: exportedDB))]), child: ListBody(children: [Text(t.settingsDestination.androidExportText(exportedDB: exportedDB))]),
), ),
actions: <Widget>[ actions: <Widget>[
TextButton( TextButton(
child: Text(t.popupActions.ok), child: Text(t.actions.ok),
onPressed: () { onPressed: () {
Navigator.of(context).pop(); Navigator.of(context).pop();
}, },
@ -520,17 +520,17 @@ class _DestinationSettings extends State<DestinationSettings> with SingleTickerP
showDialog( showDialog(
context: context, context: context,
builder: (BuildContext context) => AlertDialog( builder: (BuildContext context) => AlertDialog(
title: Text(t.desktopExportAlertTitle, title: Text(t.settingsDestination.desktopExportAlertTitle,
style: const TextStyle( style: const TextStyle(
fontFamily: "Eurostile Round Extended")), fontFamily: "Eurostile Round Extended")),
content: SingleChildScrollView( content: SingleChildScrollView(
child: ListBody(children: [ child: ListBody(children: [
Text(t.desktopExportText) Text(t.settingsDestination.desktopExportText)
]), ]),
), ),
actions: <Widget>[ actions: <Widget>[
TextButton( TextButton(
child: Text(t.popupActions.ok), child: Text(t.actions.ok),
onPressed: () { onPressed: () {
Navigator.of(context).pop(); Navigator.of(context).pop();
}, },
@ -546,7 +546,7 @@ class _DestinationSettings extends State<DestinationSettings> with SingleTickerP
title: Text("Import Database", style: Theme.of(context).textTheme.displayLarge), title: Text("Import Database", style: Theme.of(context).textTheme.displayLarge),
onTap: (){ onTap: (){
if (kIsWeb){ if (kIsWeb){
ScaffoldMessenger.of(context).showSnackBar(SnackBar(content: Text(t.notForWeb))); ScaffoldMessenger.of(context).showSnackBar(SnackBar(content: Text(t.snackBarMessages.notForWeb)));
}else if(Platform.isAndroid){ }else if(Platform.isAndroid){
FilePicker.platform.pickFiles( FilePicker.platform.pickFiles(
type: FileType.any, type: FileType.any,
@ -560,7 +560,7 @@ class _DestinationSettings extends State<DestinationSettings> with SingleTickerP
var oldDB = File("${value.path}/TetraStats.db"); var oldDB = File("${value.path}/TetraStats.db");
oldDB.writeAsBytes(File(newDB).readAsBytesSync()).then((value){ oldDB.writeAsBytes(File(newDB).readAsBytesSync()).then((value){
teto.open(); teto.open();
ScaffoldMessenger.of(context).showSnackBar(SnackBar(content: Text(t.importSuccess))); ScaffoldMessenger.of(context).showSnackBar(SnackBar(content: Text(t.snackBarMessages.importSuccess)));
}); });
}); });
}); });
@ -569,7 +569,7 @@ class _DestinationSettings extends State<DestinationSettings> with SingleTickerP
} }
}); });
} else { } else {
ScaffoldMessenger.of(context).showSnackBar(SnackBar(content: Text(t.importCancelled))); ScaffoldMessenger.of(context).showSnackBar(SnackBar(content: Text(t.snackBarMessages.importCancelled)));
} }
}); });
}else{ }else{
@ -587,7 +587,7 @@ class _DestinationSettings extends State<DestinationSettings> with SingleTickerP
var oldDB = File("${value.path}/TetraStats.db"); var oldDB = File("${value.path}/TetraStats.db");
oldDB.writeAsBytes(File(newDB).readAsBytesSync()).then((value){ oldDB.writeAsBytes(File(newDB).readAsBytesSync()).then((value){
teto.open(); teto.open();
ScaffoldMessenger.of(context).showSnackBar(SnackBar(content: Text(t.importSuccess))); ScaffoldMessenger.of(context).showSnackBar(SnackBar(content: Text(t.snackBarMessages.importSuccess)));
}); });
}); });
}); });
@ -596,7 +596,7 @@ class _DestinationSettings extends State<DestinationSettings> with SingleTickerP
} }
}); });
} else { } else {
ScaffoldMessenger.of(context).showSnackBar(SnackBar(content: Text(t.importCancelled))); ScaffoldMessenger.of(context).showSnackBar(SnackBar(content: Text(t.snackBarMessages.importCancelled)));
} }
}); });
} }
@ -661,7 +661,7 @@ class _DestinationSettings extends State<DestinationSettings> with SingleTickerP
padding: const EdgeInsets.fromLTRB(0.0, 12.0, 0.0, 0.0), padding: const EdgeInsets.fromLTRB(0.0, 12.0, 0.0, 0.0),
child: FloatingActionButton( child: FloatingActionButton(
onPressed: () => Navigator.pop(context), onPressed: () => Navigator.pop(context),
tooltip: 'Fuck go back', tooltip: t.goBackButton,
child: const Icon(Icons.arrow_back), child: const Icon(Icons.arrow_back),
), ),
), ),

View File

@ -97,12 +97,12 @@ class MainView extends StatefulWidget {
enum Cards {overview, tetraLeague, quickPlay, sprint, blitz} enum Cards {overview, tetraLeague, quickPlay, sprint, blitz}
enum CardMod {info, records, ex, exRecords} enum CardMod {info, records, ex, exRecords}
Map<Cards, String> cardsTitles = { Map<Cards, String> cardsTitles = {
Cards.overview: "Overview", Cards.overview: t.homeNavigation.overview,
Cards.tetraLeague: t.tetraLeague, Cards.tetraLeague: t.gamemodes["league"]!,
Cards.quickPlay: t.quickPlay, Cards.quickPlay: t.gamemodes["zenith"]!,
//Cards.quickPlayExpert: "${t.quickPlay} ${t.expert}", //Cards.quickPlayExpert: "${t.quickPlay} ${t.expert}",
Cards.sprint: t.sprint, Cards.sprint: t.gamemodes["zenith"]!,
Cards.blitz: t.blitz, Cards.blitz: t.gamemodes["zenithex"]!,
//Cards.other: t.other //Cards.other: t.other
}; };

View File

@ -1,5 +1,6 @@
import 'package:flutter/material.dart'; import 'package:flutter/material.dart';
import 'package:tetra_stats/data_objects/cutoff_tetrio.dart'; import 'package:tetra_stats/data_objects/cutoff_tetrio.dart';
import 'package:tetra_stats/gen/strings.g.dart';
import 'package:tetra_stats/main.dart'; import 'package:tetra_stats/main.dart';
import 'package:tetra_stats/utils/numers_formats.dart'; import 'package:tetra_stats/utils/numers_formats.dart';
import 'package:tetra_stats/widgets/future_error.dart'; import 'package:tetra_stats/widgets/future_error.dart';
@ -36,70 +37,70 @@ class _RankState extends State<RankView> {
return Column( return Column(
children: [ children: [
Divider(), Divider(),
Text("Average Stats", style: Theme.of(context).textTheme.displayLarge), Text(t.rankView.avgStats, style: Theme.of(context).textTheme.displayLarge),
Text("${f2.format(data != null ? data[0].apm : widget.cutoffTetrio.apm)} APM${f2.format(data != null ? data[0].pps : widget.cutoffTetrio.pps)} PPS${f2.format(data != null ? data[0].vs : widget.cutoffTetrio.vs)} VS", style: Theme.of(context).textTheme.displayLarge), Text("${f2.format(data != null ? data[0].apm : widget.cutoffTetrio.apm)} ${t.stats.apm.short}${f2.format(data != null ? data[0].pps : widget.cutoffTetrio.pps)} ${t.stats.pps.short}${f2.format(data != null ? data[0].vs : widget.cutoffTetrio.vs)} ${t.stats.vs.short}", style: Theme.of(context).textTheme.displayLarge),
Divider(), Divider(),
Center(child: Text("Average Nerd Stats", style: Theme.of(context).textTheme.displayLarge)), Center(child: Text(t.rankView.avgNerdStats, style: Theme.of(context).textTheme.displayLarge)),
Row( Row(
mainAxisAlignment: MainAxisAlignment.spaceBetween, mainAxisAlignment: MainAxisAlignment.spaceBetween,
children: [ children: [
Text("Attack Per Piece", style: Theme.of(context).textTheme.displayLarge), Text(t.stats.app.full, style: Theme.of(context).textTheme.displayLarge),
Text(f3.format(data != null ? data[1]["avgAPP"] : widget.cutoffTetrio.nerdStats?.app), style: Theme.of(context).textTheme.displayLarge) Text(f3.format(data != null ? data[1]["avgAPP"] : widget.cutoffTetrio.nerdStats?.app), style: Theme.of(context).textTheme.displayLarge)
], ],
), ),
Row( Row(
mainAxisAlignment: MainAxisAlignment.spaceBetween, mainAxisAlignment: MainAxisAlignment.spaceBetween,
children: [ children: [
Text("VS / APM", style: Theme.of(context).textTheme.displayLarge), Text(t.stats.vsapm.full, style: Theme.of(context).textTheme.displayLarge),
Text(f3.format(data != null ? data[1]["avgVSAPM"] : widget.cutoffTetrio.nerdStats?.vsapm), style: Theme.of(context).textTheme.displayLarge) Text(f3.format(data != null ? data[1]["avgVSAPM"] : widget.cutoffTetrio.nerdStats?.vsapm), style: Theme.of(context).textTheme.displayLarge)
], ],
), ),
Row( Row(
mainAxisAlignment: MainAxisAlignment.spaceBetween, mainAxisAlignment: MainAxisAlignment.spaceBetween,
children: [ children: [
Text("Downstack Per Second", style: Theme.of(context).textTheme.displayLarge), Text(t.stats.dss.full, style: Theme.of(context).textTheme.displayLarge),
Text(f3.format(data != null ? data[1]["avgDSS"] : widget.cutoffTetrio.nerdStats?.dss), style: Theme.of(context).textTheme.displayLarge) Text(f3.format(data != null ? data[1]["avgDSS"] : widget.cutoffTetrio.nerdStats?.dss), style: Theme.of(context).textTheme.displayLarge)
], ],
), ),
Row( Row(
mainAxisAlignment: MainAxisAlignment.spaceBetween, mainAxisAlignment: MainAxisAlignment.spaceBetween,
children: [ children: [
Text("Downstack Per Piece", style: Theme.of(context).textTheme.displayLarge), Text(t.stats.dsp.full, style: Theme.of(context).textTheme.displayLarge),
Text(f3.format(data != null ? data[1]["avgDSP"] : widget.cutoffTetrio.nerdStats?.dsp), style: Theme.of(context).textTheme.displayLarge) Text(f3.format(data != null ? data[1]["avgDSP"] : widget.cutoffTetrio.nerdStats?.dsp), style: Theme.of(context).textTheme.displayLarge)
], ],
), ),
Row( Row(
mainAxisAlignment: MainAxisAlignment.spaceBetween, mainAxisAlignment: MainAxisAlignment.spaceBetween,
children: [ children: [
Text("APP + DSP", style: Theme.of(context).textTheme.displayLarge), Text(t.stats.appdsp.full, style: Theme.of(context).textTheme.displayLarge),
Text(f3.format(data != null ? data[1]["avgAPPDSP"] : widget.cutoffTetrio.nerdStats?.appdsp), style: Theme.of(context).textTheme.displayLarge) Text(f3.format(data != null ? data[1]["avgAPPDSP"] : widget.cutoffTetrio.nerdStats?.appdsp), style: Theme.of(context).textTheme.displayLarge)
], ],
), ),
Row( Row(
mainAxisAlignment: MainAxisAlignment.spaceBetween, mainAxisAlignment: MainAxisAlignment.spaceBetween,
children: [ children: [
Text("Cheese Index", style: Theme.of(context).textTheme.displayLarge), Text(t.stats.cheese.full, style: Theme.of(context).textTheme.displayLarge),
Text(f2.format(data != null ? data[1]["avgCheese"] : widget.cutoffTetrio.nerdStats?.cheese), style: Theme.of(context).textTheme.displayLarge) Text(f2.format(data != null ? data[1]["avgCheese"] : widget.cutoffTetrio.nerdStats?.cheese), style: Theme.of(context).textTheme.displayLarge)
], ],
), ),
Row( Row(
mainAxisAlignment: MainAxisAlignment.spaceBetween, mainAxisAlignment: MainAxisAlignment.spaceBetween,
children: [ children: [
Text("Garbage Efficiency", style: Theme.of(context).textTheme.displayLarge), Text(t.stats.gbe.full, style: Theme.of(context).textTheme.displayLarge),
Text(f3.format(data != null ? data[1]["avgGBE"] : widget.cutoffTetrio.nerdStats?.gbe), style: Theme.of(context).textTheme.displayLarge) Text(f3.format(data != null ? data[1]["avgGBE"] : widget.cutoffTetrio.nerdStats?.gbe), style: Theme.of(context).textTheme.displayLarge)
], ],
), ),
Row( Row(
mainAxisAlignment: MainAxisAlignment.spaceBetween, mainAxisAlignment: MainAxisAlignment.spaceBetween,
children: [ children: [
Text("Weighted APP", style: Theme.of(context).textTheme.displayLarge), Text(t.stats.nyaapp.full, style: Theme.of(context).textTheme.displayLarge),
Text(f3.format(data != null ? data[1]["avgNyaAPP"] : widget.cutoffTetrio.nerdStats?.nyaapp), style: Theme.of(context).textTheme.displayLarge) Text(f3.format(data != null ? data[1]["avgNyaAPP"] : widget.cutoffTetrio.nerdStats?.nyaapp), style: Theme.of(context).textTheme.displayLarge)
], ],
), ),
Row( Row(
mainAxisAlignment: MainAxisAlignment.spaceBetween, mainAxisAlignment: MainAxisAlignment.spaceBetween,
children: [ children: [
Text("Area", style: Theme.of(context).textTheme.displayLarge), Text(t.stats.area.full, style: Theme.of(context).textTheme.displayLarge),
Text(f1.format(data != null ? data[1]["avgArea"] : widget.cutoffTetrio.nerdStats?.area), style: Theme.of(context).textTheme.displayLarge) Text(f1.format(data != null ? data[1]["avgArea"] : widget.cutoffTetrio.nerdStats?.area), style: Theme.of(context).textTheme.displayLarge)
], ],
), ),
@ -255,7 +256,7 @@ class _RankState extends State<RankView> {
padding: const EdgeInsets.fromLTRB(8.0, 4.0, 0.0, 0.0), padding: const EdgeInsets.fromLTRB(8.0, 4.0, 0.0, 0.0),
child: FloatingActionButton( child: FloatingActionButton(
onPressed: () => Navigator.pop(context), onPressed: () => Navigator.pop(context),
tooltip: 'Fuck go back', tooltip: t.goBackButton,
child: const Icon(Icons.arrow_back), child: const Icon(Icons.arrow_back),
), ),
), ),

View File

@ -21,7 +21,7 @@ class SingleplayerRecordView extends StatelessWidget {
padding: const EdgeInsets.fromLTRB(16.0, 8.0, 0.0, 0.0), padding: const EdgeInsets.fromLTRB(16.0, 8.0, 0.0, 0.0),
child: FloatingActionButton( child: FloatingActionButton(
onPressed: () => Navigator.pop(context), onPressed: () => Navigator.pop(context),
tooltip: 'Fuck go back', tooltip: t.goBackButton,
child: const Icon(Icons.arrow_back), child: const Icon(Icons.arrow_back),
), ),
), ),

View File

@ -22,16 +22,16 @@ class SprintAndBlitzState extends State<SprintAndBlitzView> {
@override @override
void initState() { void initState() {
if (!kIsWeb && !Platform.isAndroid && !Platform.isIOS){ // if (!kIsWeb && !Platform.isAndroid && !Platform.isIOS){
windowManager.getTitle().then((value) => oldWindowTitle = value); // windowManager.getTitle().then((value) => oldWindowTitle = value);
windowManager.setTitle("Tetra Stats: ${t.settings}"); // windowManager.setTitle("Tetra Stats: ${t.settings}");
} // }
super.initState(); super.initState();
} }
@override @override
void dispose(){ void dispose(){
if (!kIsWeb && !Platform.isAndroid && !Platform.isIOS) windowManager.setTitle(oldWindowTitle); // if (!kIsWeb && !Platform.isAndroid && !Platform.isIOS) windowManager.setTitle(oldWindowTitle);
super.dispose(); super.dispose();
} }
@ -45,7 +45,7 @@ class SprintAndBlitzState extends State<SprintAndBlitzView> {
padding: const EdgeInsets.fromLTRB(0.0, 12.0, 0.0, 0.0), padding: const EdgeInsets.fromLTRB(0.0, 12.0, 0.0, 0.0),
child: FloatingActionButton( child: FloatingActionButton(
onPressed: () => Navigator.pop(context), onPressed: () => Navigator.pop(context),
tooltip: 'Fuck go back', tooltip: t.goBackButton,
child: const Icon(Icons.arrow_back), child: const Icon(Icons.arrow_back),
), ),
), ),
@ -73,11 +73,11 @@ class SprintAndBlitzState extends State<SprintAndBlitzView> {
Text(t.rank, textAlign: TextAlign.center, style: const TextStyle(fontFamily: "Eurostile Round", fontSize: 14, fontWeight: FontWeight.w500, color: Colors.white)), Text(t.rank, textAlign: TextAlign.center, style: const TextStyle(fontFamily: "Eurostile Round", fontSize: 14, fontWeight: FontWeight.w500, color: Colors.white)),
Padding( Padding(
padding: const EdgeInsets.only(right: 8.0), padding: const EdgeInsets.only(right: 8.0),
child: Text(t.sprint, textAlign: TextAlign.right, style: TextStyle(fontFamily: bigScreen ? "Eurostile Round" : "Eurostile Round Condensed", fontSize: 28, fontWeight: FontWeight.w500, color: Colors.white)), child: Text(t.gamemodes["40l"]!, textAlign: TextAlign.right, style: TextStyle(fontFamily: bigScreen ? "Eurostile Round" : "Eurostile Round Condensed", fontSize: 28, fontWeight: FontWeight.w500, color: Colors.white)),
), ),
Padding( Padding(
padding: const EdgeInsets.only(right: 8.0), padding: const EdgeInsets.only(right: 8.0),
child: Text(t.blitz, textAlign: TextAlign.right, style: TextStyle(fontFamily: bigScreen ? "Eurostile Round" : "Eurostile Round Condensed", fontSize: 28, fontWeight: FontWeight.w500, color: Colors.white)), child: Text(t.gamemodes["blitz"]!, textAlign: TextAlign.right, style: TextStyle(fontFamily: bigScreen ? "Eurostile Round" : "Eurostile Round Condensed", fontSize: 28, fontWeight: FontWeight.w500, color: Colors.white)),
), ),
] ]
), ),

View File

@ -1,8 +1,6 @@
// ignore_for_file: use_build_context_synchronously, type_literal_in_constant_pattern // ignore_for_file: use_build_context_synchronously, type_literal_in_constant_pattern
import 'dart:io'; import 'dart:io';
import 'package:tetra_stats/data_objects/beta_league_round.dart';
import 'package:tetra_stats/data_objects/beta_league_stats.dart';
import 'package:tetra_stats/data_objects/beta_record.dart'; import 'package:tetra_stats/data_objects/beta_record.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/utils/relative_timestamps.dart'; import 'package:tetra_stats/utils/relative_timestamps.dart';
@ -45,60 +43,23 @@ class TlMatchResultState extends State<TlMatchResultView> {
late String reason; late String reason;
Duration totalTime = const Duration(); Duration totalTime = const Duration();
List<Duration> roundLengths = []; List<Duration> roundLengths = [];
List<BetaLeagueStats> timeWeightedStats = [];
late bool initPlayerWon; late bool initPlayerWon;
@override @override
void initState(){ void initState(){
rounds = [DropdownMenuItem(value: -1, child: Text(t.match))]; rounds = [DropdownMenuItem(value: -1, child: Text(t.tlMatchView.match))];
rounds.addAll([for (int i = 0; i < widget.record.results.rounds.length; i++) DropdownMenuItem(value: i, child: Text(t.roundNumber(n: i+1)))]); rounds.addAll([for (int i = 0; i < widget.record.results.rounds.length; i++) DropdownMenuItem(value: i, child: Text(t.tlMatchView.roundNumber(n: i+1)))]);
if (rounds.indexWhere((element) => element.value == -2) == -1) rounds.insert(1, DropdownMenuItem(value: -2, child: Text(t.timeWeightedmatch)));
greenSidePlayer = widget.record.results.leaderboard.indexWhere((element) => element.id == widget.initPlayerId); greenSidePlayer = widget.record.results.leaderboard.indexWhere((element) => element.id == widget.initPlayerId);
redSidePlayer = widget.record.results.leaderboard.indexWhere((element) => element.id != widget.initPlayerId); redSidePlayer = widget.record.results.leaderboard.indexWhere((element) => element.id != widget.initPlayerId);
List<double> apmMultipliedByWeights = [0, 0];
List<double> ppsMultipliedByWeights= [0, 0];
List<double> vsMultipliedByWeights = [0, 0];
for (var round in widget.record.results.rounds){ for (var round in widget.record.results.rounds){
var longerLifetime = round[0].lifetime.compareTo(round[1].lifetime) == 1 ? round[0].lifetime : round[1].lifetime; var longerLifetime = round[0].lifetime.compareTo(round[1].lifetime) == 1 ? round[0].lifetime : round[1].lifetime;
roundLengths.add(longerLifetime); roundLengths.add(longerLifetime);
totalTime += longerLifetime; totalTime += longerLifetime;
BetaLeagueRound greenSide = round.firstWhere((element) => element.id == widget.initPlayerId);
BetaLeagueRound redSide = round.firstWhere((element) => element.id != widget.initPlayerId);
apmMultipliedByWeights[0] += greenSide.stats.apm*longerLifetime.inMilliseconds;
apmMultipliedByWeights[1] += redSide.stats.apm*longerLifetime.inMilliseconds;
ppsMultipliedByWeights[0] += greenSide.stats.pps*longerLifetime.inMilliseconds;
ppsMultipliedByWeights[1] += redSide.stats.pps*longerLifetime.inMilliseconds;
vsMultipliedByWeights[0] += greenSide.stats.vs*longerLifetime.inMilliseconds;
vsMultipliedByWeights[1] += redSide.stats.vs*longerLifetime.inMilliseconds;
} }
timeWeightedStats = [
BetaLeagueStats(
apm: apmMultipliedByWeights[0]/totalTime.inMilliseconds,
pps: ppsMultipliedByWeights[0]/totalTime.inMilliseconds,
vs: vsMultipliedByWeights[0]/totalTime.inMilliseconds,
garbageSent: widget.record.results.leaderboard[greenSidePlayer].stats.garbageSent,
garbageReceived: widget.record.results.leaderboard[greenSidePlayer].stats.garbageReceived,
kills: widget.record.results.leaderboard[greenSidePlayer].stats.kills,
altitude: widget.record.results.leaderboard[greenSidePlayer].stats.altitude,
rank: widget.record.results.leaderboard[greenSidePlayer].stats.rank
),
BetaLeagueStats(
apm: apmMultipliedByWeights[1]/totalTime.inMilliseconds,
pps: ppsMultipliedByWeights[1]/totalTime.inMilliseconds,
vs: vsMultipliedByWeights[1]/totalTime.inMilliseconds,
garbageSent: widget.record.results.leaderboard[redSidePlayer].stats.garbageSent,
garbageReceived: widget.record.results.leaderboard[redSidePlayer].stats.garbageReceived,
kills: widget.record.results.leaderboard[redSidePlayer].stats.kills,
altitude: widget.record.results.leaderboard[redSidePlayer].stats.altitude,
rank: widget.record.results.leaderboard[redSidePlayer].stats.rank
),
];
initPlayerWon = widget.record.results.leaderboard[greenSidePlayer].wins > widget.record.results.leaderboard[redSidePlayer].wins; initPlayerWon = widget.record.results.leaderboard[greenSidePlayer].wins > widget.record.results.leaderboard[redSidePlayer].wins;
if (!kIsWeb && !Platform.isAndroid && !Platform.isIOS){ if (!kIsWeb && !Platform.isAndroid && !Platform.isIOS){
windowManager.getTitle().then((value) => oldWindowTitle = value); windowManager.getTitle().then((value) => oldWindowTitle = value);
windowManager.setTitle("Tetra Stats: ${widget.record.results.leaderboard[greenSidePlayer].username.toUpperCase()} ${t.vs} ${widget.record.results.leaderboard[redSidePlayer].username.toUpperCase()} ${t.inTLmatch} ${widget.record.gamemode} ${timestamp(widget.record.ts)}"); windowManager.setTitle("Tetra Stats: ${widget.record.results.leaderboard[greenSidePlayer].username.toUpperCase()} ${t.tlMatchView.vs} ${widget.record.results.leaderboard[redSidePlayer].username.toUpperCase()} ${timestamp(widget.record.ts)}");
} }
super.initState(); super.initState();
} }
@ -114,11 +75,11 @@ class TlMatchResultState extends State<TlMatchResultView> {
bool bigScreen = width >= 768; bool bigScreen = width >= 768;
if (roundSelector.isNegative){ if (roundSelector.isNegative){
time = totalTime; time = totalTime;
readableTime = !time.isNegative ? "${t.matchLength}: ${time.inMinutes}:${secs.format(time.inMicroseconds /1000000 % 60)}" : "${t.matchLength}: ---"; readableTime = !time.isNegative ? "${t.tlMatchView.matchLength}: ${time.inMinutes}:${secs.format(time.inMicroseconds /1000000 % 60)}" : "${t.tlMatchView.matchLength}: ---";
}else{ }else{
time = roundLengths[roundSelector]; time = roundLengths[roundSelector];
int alive = widget.record.results.rounds[roundSelector].indexWhere((element) => element.alive); int alive = widget.record.results.rounds[roundSelector].indexWhere((element) => element.alive);
readableTime = "${t.roundLength}: ${!time.isNegative ? "${time.inMinutes}:${secs.format(time.inMicroseconds /1000000 % 60)}" : "---"}\n${t.winner}: ${alive == -1 ? "idk" : widget.record.results.rounds[roundSelector][alive].username}"; readableTime = "${t.tlMatchView.roundLength}: ${!time.isNegative ? "${time.inMinutes}:${secs.format(time.inMicroseconds /1000000 % 60)}" : "---"}\n${t.tlMatchView.winner}: ${alive == -1 ? "idk" : widget.record.results.rounds[roundSelector][alive].username}";
} }
return SizedBox( return SizedBox(
width: width, width: width,
@ -191,7 +152,7 @@ class TlMatchResultState extends State<TlMatchResultView> {
crossAxisAlignment: CrossAxisAlignment.baseline, crossAxisAlignment: CrossAxisAlignment.baseline,
textBaseline: TextBaseline.alphabetic, textBaseline: TextBaseline.alphabetic,
children: [ children: [
Text("${t.statsFor}: ", Text("${t.tlMatchView.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;
@ -201,9 +162,6 @@ class TlMatchResultState extends State<TlMatchResultView> {
), ),
), ),
), ),
if (widget.record.id == widget.record.replayID && showMobileSelector) SliverToBoxAdapter(
child: Center(child: Text(t.p1nkl0bst3rAlert, textAlign: TextAlign.center)),
),
if (showMobileSelector) SliverToBoxAdapter(child: Center(child: Text(readableTime, textAlign: TextAlign.center))), if (showMobileSelector) SliverToBoxAdapter(child: Center(child: Text(readableTime, textAlign: TextAlign.center))),
const SliverToBoxAdapter( const SliverToBoxAdapter(
child: Divider(), child: Divider(),
@ -215,38 +173,32 @@ class TlMatchResultState extends State<TlMatchResultView> {
Column( Column(
children: [ children: [
CompareThingy( CompareThingy(
label: "APM", label: t.stats.apm.short,
greenSide: roundSelector == -2 ? timeWeightedStats[0].apm : greenSide: roundSelector.isNegative ? widget.record.results.leaderboard[greenSidePlayer].stats.apm : widget.record.results.rounds[roundSelector].firstWhere((element) => element.id == widget.initPlayerId).stats.apm,
roundSelector.isNegative ? widget.record.results.leaderboard[greenSidePlayer].stats.apm : widget.record.results.rounds[roundSelector].firstWhere((element) => element.id == widget.initPlayerId).stats.apm, redSide: roundSelector == -1 ? widget.record.results.leaderboard[redSidePlayer].stats.apm : widget.record.results.rounds[roundSelector].firstWhere((element) => element.id != widget.initPlayerId).stats.apm,
redSide: roundSelector == -2 ? timeWeightedStats[1].apm :
roundSelector == -1 ? widget.record.results.leaderboard[redSidePlayer].stats.apm : widget.record.results.rounds[roundSelector].firstWhere((element) => element.id != widget.initPlayerId).stats.apm,
fractionDigits: 2, fractionDigits: 2,
higherIsBetter: true, higherIsBetter: true,
), ),
CompareThingy( CompareThingy(
label: "PPS", label: t.stats.pps.short,
greenSide: roundSelector == -2 ? timeWeightedStats[0].pps : greenSide: roundSelector.isNegative ? widget.record.results.leaderboard[greenSidePlayer].stats.pps : widget.record.results.rounds[roundSelector].firstWhere((element) => element.id == widget.initPlayerId).stats.pps,
roundSelector.isNegative ? widget.record.results.leaderboard[greenSidePlayer].stats.pps : widget.record.results.rounds[roundSelector].firstWhere((element) => element.id == widget.initPlayerId).stats.pps, redSide: roundSelector == -1 ? widget.record.results.leaderboard[redSidePlayer].stats.pps : widget.record.results.rounds[roundSelector].firstWhere((element) => element.id != widget.initPlayerId).stats.pps,
redSide: roundSelector == -2 ? timeWeightedStats[1].pps :
roundSelector == -1 ? widget.record.results.leaderboard[redSidePlayer].stats.pps : widget.record.results.rounds[roundSelector].firstWhere((element) => element.id != widget.initPlayerId).stats.pps,
fractionDigits: 2, fractionDigits: 2,
higherIsBetter: true, higherIsBetter: true,
), ),
CompareThingy( CompareThingy(
label: "VS", label: t.stats.vs.short,
greenSide: roundSelector == -2 ? timeWeightedStats[0].vs : greenSide: roundSelector.isNegative ? widget.record.results.leaderboard[greenSidePlayer].stats.vs : widget.record.results.rounds[roundSelector].firstWhere((element) => element.id == widget.initPlayerId).stats.vs,
roundSelector.isNegative ? widget.record.results.leaderboard[greenSidePlayer].stats.vs : widget.record.results.rounds[roundSelector].firstWhere((element) => element.id == widget.initPlayerId).stats.vs, redSide: roundSelector == -1 ? widget.record.results.leaderboard[redSidePlayer].stats.vs : widget.record.results.rounds[roundSelector].firstWhere((element) => element.id != widget.initPlayerId).stats.vs,
redSide: roundSelector == -2 ? timeWeightedStats[1].vs :
roundSelector == -1 ? widget.record.results.leaderboard[redSidePlayer].stats.vs : widget.record.results.rounds[roundSelector].firstWhere((element) => element.id != widget.initPlayerId).stats.vs,
fractionDigits: 2, fractionDigits: 2,
higherIsBetter: true, higherIsBetter: true,
), ),
if (widget.record.gamemode == "league") CompareThingy(greenSide: roundSelector.isNegative ? widget.record.results.leaderboard[greenSidePlayer].stats.garbageSent : widget.record.results.rounds[roundSelector].firstWhere((element) => element.id == widget.initPlayerId).stats.garbageSent, if (widget.record.gamemode == "league") CompareThingy(greenSide: roundSelector.isNegative ? widget.record.results.leaderboard[greenSidePlayer].stats.garbageSent : widget.record.results.rounds[roundSelector].firstWhere((element) => element.id == widget.initPlayerId).stats.garbageSent,
redSide: roundSelector.isNegative ? widget.record.results.leaderboard[redSidePlayer].stats.garbageSent : widget.record.results.rounds[roundSelector].firstWhere((element) => element.id != widget.initPlayerId).stats.garbageSent, redSide: roundSelector.isNegative ? widget.record.results.leaderboard[redSidePlayer].stats.garbageSent : widget.record.results.rounds[roundSelector].firstWhere((element) => element.id != widget.initPlayerId).stats.garbageSent,
label: "Sent", higherIsBetter: true), label: t.stats.sent, higherIsBetter: true),
if (widget.record.gamemode == "league") CompareThingy(greenSide: roundSelector.isNegative ? widget.record.results.leaderboard[greenSidePlayer].stats.garbageReceived : widget.record.results.rounds[roundSelector].firstWhere((element) => element.id == widget.initPlayerId).stats.garbageReceived, if (widget.record.gamemode == "league") CompareThingy(greenSide: roundSelector.isNegative ? widget.record.results.leaderboard[greenSidePlayer].stats.garbageReceived : widget.record.results.rounds[roundSelector].firstWhere((element) => element.id == widget.initPlayerId).stats.garbageReceived,
redSide: roundSelector.isNegative ? widget.record.results.leaderboard[redSidePlayer].stats.garbageReceived : widget.record.results.rounds[roundSelector].firstWhere((element) => element.id != widget.initPlayerId).stats.garbageReceived, redSide: roundSelector.isNegative ? widget.record.results.leaderboard[redSidePlayer].stats.garbageReceived : widget.record.results.rounds[roundSelector].firstWhere((element) => element.id != widget.initPlayerId).stats.garbageReceived,
label: "Received", higherIsBetter: true), const Divider(), label: t.stats.received, higherIsBetter: true), const Divider(),
Column( Column(
children: [ children: [
Padding( Padding(
@ -257,142 +209,114 @@ class TlMatchResultState extends State<TlMatchResultView> {
fontSize: bigScreen ? 42 : 28)), fontSize: bigScreen ? 42 : 28)),
), ),
CompareThingy( CompareThingy(
label: "APP", label: t.stats.app.short,
greenSide: roundSelector == -2 ? timeWeightedStats[0].nerdStats.app : greenSide: roundSelector.isNegative ? widget.record.results.leaderboard[greenSidePlayer].stats.nerdStats.app : widget.record.results.rounds[roundSelector].firstWhere((element) => element.id == widget.initPlayerId).stats.nerdStats.app,
roundSelector.isNegative ? widget.record.results.leaderboard[greenSidePlayer].stats.nerdStats.app : widget.record.results.rounds[roundSelector].firstWhere((element) => element.id == widget.initPlayerId).stats.nerdStats.app, redSide: roundSelector.isNegative ? widget.record.results.leaderboard[redSidePlayer].stats.nerdStats.app : widget.record.results.rounds[roundSelector].firstWhere((element) => element.id != widget.initPlayerId).stats.nerdStats.app,
redSide: roundSelector == -2 ? timeWeightedStats[1].nerdStats.app :
roundSelector == -1 ? widget.record.results.leaderboard[redSidePlayer].stats.nerdStats.app : widget.record.results.rounds[roundSelector].firstWhere((element) => element.id != widget.initPlayerId).stats.nerdStats.app,
fractionDigits: 3, fractionDigits: 3,
higherIsBetter: true, higherIsBetter: true,
), ),
CompareThingy( CompareThingy(
label: "VS/APM", label: t.stats.vsapm.short,
greenSide: roundSelector == -2 ? timeWeightedStats[0].nerdStats.vsapm : greenSide: roundSelector.isNegative ? widget.record.results.leaderboard[greenSidePlayer].stats.nerdStats.vsapm : widget.record.results.rounds[roundSelector].firstWhere((element) => element.id == widget.initPlayerId).stats.nerdStats.vsapm,
roundSelector.isNegative ? widget.record.results.leaderboard[greenSidePlayer].stats.nerdStats.vsapm : widget.record.results.rounds[roundSelector].firstWhere((element) => element.id == widget.initPlayerId).stats.nerdStats.vsapm, redSide: roundSelector.isNegative ? widget.record.results.leaderboard[redSidePlayer].stats.nerdStats.vsapm : widget.record.results.rounds[roundSelector].firstWhere((element) => element.id != widget.initPlayerId).stats.nerdStats.vsapm,
redSide: roundSelector == -2 ? timeWeightedStats[1].nerdStats.vsapm :
roundSelector == -1 ? widget.record.results.leaderboard[redSidePlayer].stats.nerdStats.vsapm : widget.record.results.rounds[roundSelector].firstWhere((element) => element.id != widget.initPlayerId).stats.nerdStats.vsapm,
fractionDigits: 3, fractionDigits: 3,
higherIsBetter: true, higherIsBetter: true,
), ),
CompareThingy( CompareThingy(
label: "DS/S", label: t.stats.dss.short,
greenSide: roundSelector == -2 ? timeWeightedStats[0].nerdStats.dss : greenSide: roundSelector.isNegative ? widget.record.results.leaderboard[greenSidePlayer].stats.nerdStats.dss : widget.record.results.rounds[roundSelector].firstWhere((element) => element.id == widget.initPlayerId).stats.nerdStats.dss,
roundSelector.isNegative ? widget.record.results.leaderboard[greenSidePlayer].stats.nerdStats.dss : widget.record.results.rounds[roundSelector].firstWhere((element) => element.id == widget.initPlayerId).stats.nerdStats.dss, redSide: roundSelector.isNegative ? widget.record.results.leaderboard[redSidePlayer].stats.nerdStats.dss : widget.record.results.rounds[roundSelector].firstWhere((element) => element.id != widget.initPlayerId).stats.nerdStats.dss,
redSide: roundSelector == -2 ? timeWeightedStats[1].nerdStats.dss :
roundSelector == -1 ? widget.record.results.leaderboard[redSidePlayer].stats.nerdStats.dss : widget.record.results.rounds[roundSelector].firstWhere((element) => element.id != widget.initPlayerId).stats.nerdStats.dss,
fractionDigits: 3, fractionDigits: 3,
higherIsBetter: true, higherIsBetter: true,
), ),
CompareThingy( CompareThingy(
label: "DS/P", label: t.stats.dsp.short,
greenSide: roundSelector == -2 ? timeWeightedStats[0].nerdStats.dsp : greenSide: roundSelector.isNegative ? widget.record.results.leaderboard[greenSidePlayer].stats.nerdStats.dsp : widget.record.results.rounds[roundSelector].firstWhere((element) => element.id == widget.initPlayerId).stats.nerdStats.dsp,
roundSelector.isNegative ? widget.record.results.leaderboard[greenSidePlayer].stats.nerdStats.dsp : widget.record.results.rounds[roundSelector].firstWhere((element) => element.id == widget.initPlayerId).stats.nerdStats.dsp, redSide: roundSelector.isNegative ? widget.record.results.leaderboard[redSidePlayer].stats.nerdStats.dsp : widget.record.results.rounds[roundSelector].firstWhere((element) => element.id != widget.initPlayerId).stats.nerdStats.dsp,
redSide: roundSelector == -2 ? timeWeightedStats[1].nerdStats.dsp :
roundSelector == -1 ? widget.record.results.leaderboard[redSidePlayer].stats.nerdStats.dsp : widget.record.results.rounds[roundSelector].firstWhere((element) => element.id != widget.initPlayerId).stats.nerdStats.dsp,
fractionDigits: 3, fractionDigits: 3,
higherIsBetter: true, higherIsBetter: true,
), ),
CompareThingy( CompareThingy(
label: "APP + DS/P", label: t.stats.appdsp.short,
greenSide: roundSelector == -2 ? timeWeightedStats[0].nerdStats.appdsp : greenSide: roundSelector.isNegative ? widget.record.results.leaderboard[greenSidePlayer].stats.nerdStats.appdsp : widget.record.results.rounds[roundSelector].firstWhere((element) => element.id == widget.initPlayerId).stats.nerdStats.appdsp,
roundSelector.isNegative ? widget.record.results.leaderboard[greenSidePlayer].stats.nerdStats.appdsp : widget.record.results.rounds[roundSelector].firstWhere((element) => element.id == widget.initPlayerId).stats.nerdStats.appdsp, redSide: roundSelector.isNegative ? widget.record.results.leaderboard[redSidePlayer].stats.nerdStats.appdsp : widget.record.results.rounds[roundSelector].firstWhere((element) => element.id != widget.initPlayerId).stats.nerdStats.appdsp,
redSide: roundSelector == -2 ? timeWeightedStats[1].nerdStats.appdsp :
roundSelector == -1 ? widget.record.results.leaderboard[redSidePlayer].stats.nerdStats.appdsp : widget.record.results.rounds[roundSelector].firstWhere((element) => element.id != widget.initPlayerId).stats.nerdStats.appdsp,
fractionDigits: 3, fractionDigits: 3,
higherIsBetter: true, higherIsBetter: true,
), ),
CompareThingy( CompareThingy(
label: t.statCellNum.cheese.replaceAll(RegExp(r'\n'), " "), label: t.stats.cheese.short,
greenSide: roundSelector == -2 ? timeWeightedStats[0].nerdStats.cheese : greenSide: roundSelector.isNegative ? widget.record.results.leaderboard[greenSidePlayer].stats.nerdStats.cheese : widget.record.results.rounds[roundSelector].firstWhere((element) => element.id == widget.initPlayerId).stats.nerdStats.cheese,
roundSelector.isNegative ? widget.record.results.leaderboard[greenSidePlayer].stats.nerdStats.cheese : widget.record.results.rounds[roundSelector].firstWhere((element) => element.id == widget.initPlayerId).stats.nerdStats.cheese, redSide: roundSelector.isNegative ? widget.record.results.leaderboard[redSidePlayer].stats.nerdStats.cheese : widget.record.results.rounds[roundSelector].firstWhere((element) => element.id != widget.initPlayerId).stats.nerdStats.cheese,
redSide: roundSelector == -2 ? timeWeightedStats[1].nerdStats.cheese :
roundSelector == -1 ? widget.record.results.leaderboard[redSidePlayer].stats.nerdStats.cheese : widget.record.results.rounds[roundSelector].firstWhere((element) => element.id != widget.initPlayerId).stats.nerdStats.cheese,
fractionDigits: 2, fractionDigits: 2,
higherIsBetter: false, higherIsBetter: false,
), ),
CompareThingy( CompareThingy(
label: "Gb Eff.", label: t.stats.gbe.short,
greenSide: roundSelector == -2 ? timeWeightedStats[0].nerdStats.gbe : greenSide: roundSelector.isNegative ? widget.record.results.leaderboard[greenSidePlayer].stats.nerdStats.gbe : widget.record.results.rounds[roundSelector].firstWhere((element) => element.id == widget.initPlayerId).stats.nerdStats.gbe,
roundSelector.isNegative ? widget.record.results.leaderboard[greenSidePlayer].stats.nerdStats.gbe : widget.record.results.rounds[roundSelector].firstWhere((element) => element.id == widget.initPlayerId).stats.nerdStats.gbe, redSide: roundSelector.isNegative ? widget.record.results.leaderboard[redSidePlayer].stats.nerdStats.gbe : widget.record.results.rounds[roundSelector].firstWhere((element) => element.id != widget.initPlayerId).stats.nerdStats.gbe,
redSide: roundSelector == -2 ? timeWeightedStats[1].nerdStats.gbe :
roundSelector == -1 ? widget.record.results.leaderboard[redSidePlayer].stats.nerdStats.gbe : widget.record.results.rounds[roundSelector].firstWhere((element) => element.id != widget.initPlayerId).stats.nerdStats.gbe,
fractionDigits: 3, fractionDigits: 3,
higherIsBetter: true, higherIsBetter: true,
), ),
CompareThingy( CompareThingy(
label: "wAPP", label: t.stats.nyaapp.short,
greenSide: roundSelector == -2 ? timeWeightedStats[0].nerdStats.nyaapp : greenSide: roundSelector.isNegative ? widget.record.results.leaderboard[greenSidePlayer].stats.nerdStats.nyaapp : widget.record.results.rounds[roundSelector].firstWhere((element) => element.id == widget.initPlayerId).stats.nerdStats.nyaapp,
roundSelector.isNegative ? widget.record.results.leaderboard[greenSidePlayer].stats.nerdStats.nyaapp : widget.record.results.rounds[roundSelector].firstWhere((element) => element.id == widget.initPlayerId).stats.nerdStats.nyaapp, redSide: roundSelector.isNegative ? widget.record.results.leaderboard[redSidePlayer].stats.nerdStats.nyaapp : widget.record.results.rounds[roundSelector].firstWhere((element) => element.id != widget.initPlayerId).stats.nerdStats.nyaapp,
redSide: roundSelector == -2 ? timeWeightedStats[1].nerdStats.nyaapp :
roundSelector == -1 ? widget.record.results.leaderboard[redSidePlayer].stats.nerdStats.nyaapp : widget.record.results.rounds[roundSelector].firstWhere((element) => element.id != widget.initPlayerId).stats.nerdStats.nyaapp,
fractionDigits: 3, fractionDigits: 3,
higherIsBetter: true, higherIsBetter: true,
), ),
CompareThingy( CompareThingy(
label: "Area", label: t.stats.area.short,
greenSide: roundSelector == -2 ? timeWeightedStats[0].nerdStats.area : greenSide: roundSelector.isNegative ? widget.record.results.leaderboard[greenSidePlayer].stats.nerdStats.area : widget.record.results.rounds[roundSelector].firstWhere((element) => element.id == widget.initPlayerId).stats.nerdStats.area,
roundSelector.isNegative ? widget.record.results.leaderboard[greenSidePlayer].stats.nerdStats.area : widget.record.results.rounds[roundSelector].firstWhere((element) => element.id == widget.initPlayerId).stats.nerdStats.area, redSide: roundSelector.isNegative ? widget.record.results.leaderboard[redSidePlayer].stats.nerdStats.area : widget.record.results.rounds[roundSelector].firstWhere((element) => element.id != widget.initPlayerId).stats.nerdStats.area,
redSide: roundSelector == -2 ? timeWeightedStats[1].nerdStats.area :
roundSelector == -1 ? widget.record.results.leaderboard[redSidePlayer].stats.nerdStats.area : widget.record.results.rounds[roundSelector].firstWhere((element) => element.id != widget.initPlayerId).stats.nerdStats.area,
fractionDigits: 2, fractionDigits: 2,
higherIsBetter: true, higherIsBetter: true,
), ),
CompareThingy( CompareThingy(
label: t.statCellNum.estOfTRShort, label: t.stats.etr.short,
greenSide: roundSelector == -2 ? timeWeightedStats[0].estTr.esttr : greenSide: roundSelector.isNegative ? widget.record.results.leaderboard[greenSidePlayer].stats.estTr.esttr : widget.record.results.rounds[roundSelector].firstWhere((element) => element.id == widget.initPlayerId).stats.estTr.esttr,
roundSelector.isNegative ? widget.record.results.leaderboard[greenSidePlayer].stats.estTr.esttr : widget.record.results.rounds[roundSelector].firstWhere((element) => element.id == widget.initPlayerId).stats.estTr.esttr, redSide: roundSelector.isNegative ? widget.record.results.leaderboard[redSidePlayer].stats.estTr.esttr : widget.record.results.rounds[roundSelector].firstWhere((element) => element.id != widget.initPlayerId).stats.estTr.esttr,
redSide: roundSelector == -2 ? timeWeightedStats[1].estTr.esttr :
roundSelector == -1 ? widget.record.results.leaderboard[redSidePlayer].stats.estTr.esttr : widget.record.results.rounds[roundSelector].firstWhere((element) => element.id != widget.initPlayerId).stats.estTr.esttr,
fractionDigits: 2, fractionDigits: 2,
higherIsBetter: true, higherIsBetter: true,
), ),
CompareThingy( CompareThingy(
label: "Opener", label: t.stats.opener.short,
greenSide: roundSelector == -2 ? timeWeightedStats[0].playstyle.opener : greenSide: roundSelector.isNegative ? widget.record.results.leaderboard[greenSidePlayer].stats.playstyle.opener : widget.record.results.rounds[roundSelector].firstWhere((element) => element.id == widget.initPlayerId).stats.playstyle.opener,
roundSelector.isNegative ? widget.record.results.leaderboard[greenSidePlayer].stats.playstyle.opener : widget.record.results.rounds[roundSelector].firstWhere((element) => element.id == widget.initPlayerId).stats.playstyle.opener, redSide: roundSelector.isNegative ? widget.record.results.leaderboard[redSidePlayer].stats.playstyle.opener : widget.record.results.rounds[roundSelector].firstWhere((element) => element.id != widget.initPlayerId).stats.playstyle.opener,
redSide: roundSelector == -2 ? timeWeightedStats[1].playstyle.opener :
roundSelector == -1 ? widget.record.results.leaderboard[redSidePlayer].stats.playstyle.opener : widget.record.results.rounds[roundSelector].firstWhere((element) => element.id != widget.initPlayerId).stats.playstyle.opener,
fractionDigits: 3, fractionDigits: 3,
higherIsBetter: true, higherIsBetter: true,
), ),
CompareThingy( CompareThingy(
label: "Plonk", label: t.stats.plonk.short,
greenSide: roundSelector == -2 ? timeWeightedStats[0].playstyle.plonk : greenSide: roundSelector.isNegative ? widget.record.results.leaderboard[greenSidePlayer].stats.playstyle.plonk : widget.record.results.rounds[roundSelector].firstWhere((element) => element.id == widget.initPlayerId).stats.playstyle.plonk,
roundSelector.isNegative ? widget.record.results.leaderboard[greenSidePlayer].stats.playstyle.plonk : widget.record.results.rounds[roundSelector].firstWhere((element) => element.id == widget.initPlayerId).stats.playstyle.plonk, redSide: roundSelector.isNegative ? widget.record.results.leaderboard[redSidePlayer].stats.playstyle.plonk : widget.record.results.rounds[roundSelector].firstWhere((element) => element.id != widget.initPlayerId).stats.playstyle.plonk,
redSide: roundSelector == -2 ? timeWeightedStats[1].playstyle.plonk :
roundSelector == -1 ? widget.record.results.leaderboard[redSidePlayer].stats.playstyle.plonk : widget.record.results.rounds[roundSelector].firstWhere((element) => element.id != widget.initPlayerId).stats.playstyle.plonk,
fractionDigits: 3, fractionDigits: 3,
higherIsBetter: true, higherIsBetter: true,
), ),
CompareThingy( CompareThingy(
label: "Stride", label: t.stats.stride.short,
greenSide: roundSelector == -2 ? timeWeightedStats[0].playstyle.stride : greenSide: roundSelector.isNegative ? widget.record.results.leaderboard[greenSidePlayer].stats.playstyle.stride : widget.record.results.rounds[roundSelector].firstWhere((element) => element.id == widget.initPlayerId).stats.playstyle.stride,
roundSelector.isNegative ? widget.record.results.leaderboard[greenSidePlayer].stats.playstyle.stride : widget.record.results.rounds[roundSelector].firstWhere((element) => element.id == widget.initPlayerId).stats.playstyle.stride, redSide: roundSelector.isNegative ? widget.record.results.leaderboard[redSidePlayer].stats.playstyle.stride : widget.record.results.rounds[roundSelector].firstWhere((element) => element.id != widget.initPlayerId).stats.playstyle.stride,
redSide: roundSelector == -2 ? timeWeightedStats[1].playstyle.stride :
roundSelector == -1 ? widget.record.results.leaderboard[redSidePlayer].stats.playstyle.stride : widget.record.results.rounds[roundSelector].firstWhere((element) => element.id != widget.initPlayerId).stats.playstyle.stride,
fractionDigits: 3, fractionDigits: 3,
higherIsBetter: true, higherIsBetter: true,
), ),
CompareThingy( CompareThingy(
label: "Inf. DS", label: t.stats.infds.short,
greenSide: roundSelector == -2 ? timeWeightedStats[0].playstyle.infds : greenSide: roundSelector.isNegative ? widget.record.results.leaderboard[greenSidePlayer].stats.playstyle.infds : widget.record.results.rounds[roundSelector].firstWhere((element) => element.id == widget.initPlayerId).stats.playstyle.infds,
roundSelector.isNegative ? widget.record.results.leaderboard[greenSidePlayer].stats.playstyle.infds : widget.record.results.rounds[roundSelector].firstWhere((element) => element.id == widget.initPlayerId).stats.playstyle.infds, redSide: roundSelector.isNegative ? widget.record.results.leaderboard[redSidePlayer].stats.playstyle.infds : widget.record.results.rounds[roundSelector].firstWhere((element) => element.id != widget.initPlayerId).stats.playstyle.infds,
redSide: roundSelector == -2 ? timeWeightedStats[1].playstyle.infds :
roundSelector == -1 ? widget.record.results.leaderboard[redSidePlayer].stats.playstyle.infds : widget.record.results.rounds[roundSelector].firstWhere((element) => element.id != widget.initPlayerId).stats.playstyle.infds,
fractionDigits: 3, fractionDigits: 3,
higherIsBetter: true, higherIsBetter: true,
), ),
VsGraphs( VsGraphs(
roundSelector == -2 ? timeWeightedStats[0].apm : roundSelector.isNegative ? widget.record.results.leaderboard[greenSidePlayer].stats.apm : widget.record.results.rounds[roundSelector].firstWhere((element) => element.id == widget.initPlayerId).stats.apm, roundSelector.isNegative ? widget.record.results.leaderboard[greenSidePlayer].stats.apm : widget.record.results.rounds[roundSelector].firstWhere((element) => element.id == widget.initPlayerId).stats.apm,
roundSelector == -2 ? timeWeightedStats[0].pps : roundSelector.isNegative ? widget.record.results.leaderboard[greenSidePlayer].stats.pps : widget.record.results.rounds[roundSelector].firstWhere((element) => element.id == widget.initPlayerId).stats.pps, roundSelector.isNegative ? widget.record.results.leaderboard[greenSidePlayer].stats.pps : widget.record.results.rounds[roundSelector].firstWhere((element) => element.id == widget.initPlayerId).stats.pps,
roundSelector == -2 ? timeWeightedStats[0].vs : roundSelector.isNegative ? widget.record.results.leaderboard[greenSidePlayer].stats.vs : widget.record.results.rounds[roundSelector].firstWhere((element) => element.id == widget.initPlayerId).stats.vs, roundSelector.isNegative ? widget.record.results.leaderboard[greenSidePlayer].stats.vs : widget.record.results.rounds[roundSelector].firstWhere((element) => element.id == widget.initPlayerId).stats.vs,
roundSelector == -2 ? timeWeightedStats[0].nerdStats : roundSelector.isNegative ? widget.record.results.leaderboard[greenSidePlayer].stats.nerdStats : widget.record.results.rounds[roundSelector].firstWhere((element) => element.id == widget.initPlayerId).stats.nerdStats, roundSelector.isNegative ? widget.record.results.leaderboard[greenSidePlayer].stats.nerdStats : widget.record.results.rounds[roundSelector].firstWhere((element) => element.id == widget.initPlayerId).stats.nerdStats,
roundSelector == -2 ? timeWeightedStats[0].playstyle : roundSelector.isNegative ? widget.record.results.leaderboard[greenSidePlayer].stats.playstyle : widget.record.results.rounds[roundSelector].firstWhere((element) => element.id == widget.initPlayerId).stats.playstyle, roundSelector.isNegative ? widget.record.results.leaderboard[greenSidePlayer].stats.playstyle : widget.record.results.rounds[roundSelector].firstWhere((element) => element.id == widget.initPlayerId).stats.playstyle,
roundSelector == -2 ? timeWeightedStats[1].apm : roundSelector.isNegative ? widget.record.results.leaderboard[redSidePlayer].stats.apm : widget.record.results.rounds[roundSelector].firstWhere((element) => element.id != widget.initPlayerId).stats.apm, roundSelector.isNegative ? widget.record.results.leaderboard[redSidePlayer].stats.apm : widget.record.results.rounds[roundSelector].firstWhere((element) => element.id != widget.initPlayerId).stats.apm,
roundSelector == -2 ? timeWeightedStats[1].pps : roundSelector.isNegative ? widget.record.results.leaderboard[redSidePlayer].stats.pps : widget.record.results.rounds[roundSelector].firstWhere((element) => element.id != widget.initPlayerId).stats.pps, roundSelector.isNegative ? widget.record.results.leaderboard[redSidePlayer].stats.pps : widget.record.results.rounds[roundSelector].firstWhere((element) => element.id != widget.initPlayerId).stats.pps,
roundSelector == -2 ? timeWeightedStats[1].vs : roundSelector.isNegative ? widget.record.results.leaderboard[redSidePlayer].stats.vs : widget.record.results.rounds[roundSelector].firstWhere((element) => element.id != widget.initPlayerId).stats.vs, roundSelector.isNegative ? widget.record.results.leaderboard[redSidePlayer].stats.vs : widget.record.results.rounds[roundSelector].firstWhere((element) => element.id != widget.initPlayerId).stats.vs,
roundSelector == -2 ? timeWeightedStats[1].nerdStats : roundSelector.isNegative ? widget.record.results.leaderboard[redSidePlayer].stats.nerdStats : widget.record.results.rounds[roundSelector].firstWhere((element) => element.id != widget.initPlayerId).stats.nerdStats, roundSelector.isNegative ? widget.record.results.leaderboard[redSidePlayer].stats.nerdStats : widget.record.results.rounds[roundSelector].firstWhere((element) => element.id != widget.initPlayerId).stats.nerdStats,
roundSelector == -2 ? timeWeightedStats[1].playstyle : roundSelector.isNegative ? widget.record.results.leaderboard[redSidePlayer].stats.playstyle : widget.record.results.rounds[roundSelector].firstWhere((element) => element.id != widget.initPlayerId).stats.playstyle, roundSelector.isNegative ? widget.record.results.leaderboard[redSidePlayer].stats.playstyle : widget.record.results.rounds[roundSelector].firstWhere((element) => element.id != widget.initPlayerId).stats.playstyle,
) )
], ],
), ),
@ -449,7 +373,7 @@ class TlMatchResultState extends State<TlMatchResultView> {
Column( Column(
crossAxisAlignment: CrossAxisAlignment.start, crossAxisAlignment: CrossAxisAlignment.start,
children: [ children: [
Text(t.matchLength), Text(t.tlMatchView.matchLength),
RichText( RichText(
text: !totalTime.isNegative ? TextSpan( text: !totalTime.isNegative ? TextSpan(
text: "${totalTime.inMinutes}:${NumberFormat("00", LocaleSettings.currentLocale.languageCode).format(totalTime.inSeconds%60)}", text: "${totalTime.inMinutes}:${NumberFormat("00", LocaleSettings.currentLocale.languageCode).format(totalTime.inSeconds%60)}",
@ -465,7 +389,7 @@ class TlMatchResultState extends State<TlMatchResultView> {
if (widget.record.id != widget.record.replayID) Column( if (widget.record.id != widget.record.replayID) Column(
crossAxisAlignment: CrossAxisAlignment.end, crossAxisAlignment: CrossAxisAlignment.end,
children: [ children: [
Text(t.numberOfRounds), Text(t.tlMatchView.numberOfRounds),
RichText( RichText(
text: TextSpan( text: TextSpan(
text: widget.record.results.rounds.length.toString(), text: widget.record.results.rounds.length.toString(),
@ -478,25 +402,15 @@ class TlMatchResultState extends State<TlMatchResultView> {
), ),
) )
],), ],),
Column(children: [
OverflowBar(
alignment: MainAxisAlignment.spaceEvenly,
children: <Widget>[
TextButton( style: roundSelector == -1 ? ButtonStyle(backgroundColor: WidgetStatePropertyAll(Colors.grey.shade900)) : null,
onPressed: () {
roundSelector = -1;
setState(() {});
}, child: Text(t.matchStats)),
TextButton( style: roundSelector == -2 ? ButtonStyle(backgroundColor: WidgetStatePropertyAll(Colors.grey.shade900)) : null,
onPressed: timeWeightedStatsAvaliable ? () {
roundSelector = -2;
setState(() {});
} : null, child: Text(t.timeWeightedmatchStats)) ,
],
)
]),
], ],
) )
),
SliverToBoxAdapter(
child: TextButton( style: roundSelector == -1 ? ButtonStyle(backgroundColor: WidgetStatePropertyAll(Colors.grey.shade900)) : null,
onPressed: () {
roundSelector = -1;
setState(() {});
}, child: Text(t.tlMatchView.matchStats)),
) )
]; ];
}, },
@ -572,7 +486,7 @@ class TlMatchResultState extends State<TlMatchResultView> {
return Scaffold( return Scaffold(
appBar: AppBar( appBar: AppBar(
title: Text( title: Text(
"${widget.record.results.leaderboard[greenSidePlayer].username.toUpperCase()} ${t.vs} ${widget.record.results.leaderboard[redSidePlayer].username.toUpperCase()} ${t.inTLmatch} ${widget.record.gamemode} ${timestamp(widget.record.ts)}", "${widget.record.results.leaderboard[greenSidePlayer].username.toUpperCase()} ${t.tlMatchView.vs} ${widget.record.results.leaderboard[redSidePlayer].username.toUpperCase()} ${widget.record.gamemode} ${timestamp(widget.record.ts)}",
style: Theme.of(context).textTheme.titleMedium!.copyWith(fontSize: 28), style: Theme.of(context).textTheme.titleMedium!.copyWith(fontSize: 28),
), ),
actions: [ actions: [
@ -581,11 +495,11 @@ class TlMatchResultState extends State<TlMatchResultView> {
itemBuilder: (BuildContext context) => <PopupMenuEntry>[ itemBuilder: (BuildContext context) => <PopupMenuEntry>[
PopupMenuItem( PopupMenuItem(
value: 1, value: 1,
child: Text(t.downloadReplay), child: Text(t.tlMatchView.downloadReplay),
), ),
PopupMenuItem( PopupMenuItem(
value: 2, value: 2,
child: Text(t.openReplay), child: Text(t.tlMatchView.openReplay),
), ),
], ],
onSelected: (value) async { onSelected: (value) async {

View File

@ -49,7 +49,7 @@ class UserState extends State<UserView> {
padding: const EdgeInsets.fromLTRB(0.0, 12.0, 0.0, 0.0), padding: const EdgeInsets.fromLTRB(0.0, 12.0, 0.0, 0.0),
child: FloatingActionButton( child: FloatingActionButton(
onPressed: () => Navigator.pop(context), onPressed: () => Navigator.pop(context),
tooltip: 'Fuck go back', tooltip: t.goBackButton,
child: const Icon(Icons.arrow_back), child: const Icon(Icons.arrow_back),
), ),
), ),

View File

@ -56,7 +56,7 @@ class BadgesThingy extends StatelessWidget{
), ),
actions: <Widget>[ actions: <Widget>[
TextButton( TextButton(
child: Text(t.popupActions.ok), child: Text(t.actions.ok),
onPressed: () { onPressed: () {
Navigator.of(context).pop(); Navigator.of(context).pop();
}, },

View File

@ -452,13 +452,13 @@ class Graphs extends StatelessWidget{
getTitle: (index, angle) { getTitle: (index, angle) {
switch (index) { switch (index) {
case 0: case 0:
return RadarChartTitle(text: '${t.graphs.attack}\n${f2.format(apm)} APM', angle: 0, positionPercentageOffset: 0.05); return RadarChartTitle(text: '${t.stats.graphs.attack}\n${f2.format(apm)} APM', angle: 0, positionPercentageOffset: 0.05);
case 1: case 1:
return RadarChartTitle(text: '${t.graphs.speed}\n${f2.format(pps)} PPS', angle: 0, positionPercentageOffset: 0.05); return RadarChartTitle(text: '${t.stats.graphs.speed}\n${f2.format(pps)} PPS', angle: 0, positionPercentageOffset: 0.05);
case 2: case 2:
return RadarChartTitle(text: '${t.graphs.defense}\n${f2.format(nerdStats.dss)} DS/S', angle: angle + 180, positionPercentageOffset: 0.05); return RadarChartTitle(text: '${t.stats.graphs.defense}\n${f2.format(nerdStats.dss)} DS/S', angle: angle + 180, positionPercentageOffset: 0.05);
case 3: case 3:
return RadarChartTitle(text: '${t.graphs.cheese}\n${f3.format(nerdStats.cheese)}', angle: 0, positionPercentageOffset: 0.05); return RadarChartTitle(text: '${t.stats.graphs.cheese}\n${f3.format(nerdStats.cheese)}', angle: 0, positionPercentageOffset: 0.05);
default: default:
return const RadarChartTitle(text: ''); return const RadarChartTitle(text: '');
} }

View File

@ -21,14 +21,14 @@ class LineclearsThingy extends StatelessWidget{
child: Column( child: Column(
mainAxisSize: MainAxisSize.min, mainAxisSize: MainAxisSize.min,
children: [ children: [
Text(t.numOfGameActions.lineClears(n: lines), style: const TextStyle(color: Colors.white, fontFamily: "Eurostile Round Extended"), textAlign: TextAlign.center), Text(t.stats.linesCleared(n: lines), style: const TextStyle(color: Colors.white, fontFamily: "Eurostile Round Extended"), textAlign: TextAlign.center),
if (showMoreClears) Row(mainAxisAlignment: MainAxisAlignment.spaceBetween, children: [const Text("Pentas"), Text(clears.pentas.toString())]), if (showMoreClears) Row(mainAxisAlignment: MainAxisAlignment.spaceBetween, children: [Text(t.stats.lineClears.penta), Text(clears.pentas.toString())]),
Row(mainAxisAlignment: MainAxisAlignment.spaceBetween, children: [const Text("Quads"), Text(clears.quads.toString())]), Row(mainAxisAlignment: MainAxisAlignment.spaceBetween, children: [Text(t.stats.lineClears.quad), Text(clears.quads.toString())]),
Row(mainAxisAlignment: MainAxisAlignment.spaceBetween, children: [const Text("Triples"), Text(clears.triples.toString())]), Row(mainAxisAlignment: MainAxisAlignment.spaceBetween, children: [Text(t.stats.lineClears.triple), Text(clears.triples.toString())]),
Row(mainAxisAlignment: MainAxisAlignment.spaceBetween, children: [const Text("Doubles"), Text(clears.doubles.toString())]), Row(mainAxisAlignment: MainAxisAlignment.spaceBetween, children: [Text(t.stats.lineClears.double), Text(clears.doubles.toString())]),
Row(mainAxisAlignment: MainAxisAlignment.spaceBetween, children: [const Text("Singles"), Text(clears.singles.toString())]), Row(mainAxisAlignment: MainAxisAlignment.spaceBetween, children: [Text(t.stats.lineClears.single), Text(clears.singles.toString())]),
Row(mainAxisAlignment: MainAxisAlignment.spaceBetween, children: [Text("\n${t.numOfGameActions.pc}"), Text("\n${clears.allClears.toString()}")]), Row(mainAxisAlignment: MainAxisAlignment.spaceBetween, children: [Text("\n${t.stats.pcs}"), Text("\n${clears.allClears.toString()}")]),
Row(mainAxisAlignment: MainAxisAlignment.spaceBetween, children: [Text(t.numOfGameActions.hold), Text(holds.toString())]), Row(mainAxisAlignment: MainAxisAlignment.spaceBetween, children: [Text(t.stats.holds), Text(holds.toString())]),
], ],
), ),
), ),
@ -37,18 +37,18 @@ class LineclearsThingy extends StatelessWidget{
child: Column( child: Column(
mainAxisSize: MainAxisSize.min, mainAxisSize: MainAxisSize.min,
children: [ children: [
Text(t.numOfGameActions.tspinsTotal(n: tSpins), style: const TextStyle(color: Colors.white, fontFamily: "Eurostile Round Extended"), textAlign: TextAlign.center), Text(t.stats.tspinsTotal(n: tSpins), style: const TextStyle(color: Colors.white, fontFamily: "Eurostile Round Extended"), textAlign: TextAlign.center),
if (showMoreClears) Row(mainAxisAlignment: MainAxisAlignment.spaceBetween, children: [const Text("T-spin pentas"), Text(clears.tSpinPentas.toString())]), if (showMoreClears) Row(mainAxisAlignment: MainAxisAlignment.spaceBetween, children: [Text("${t.stats.tSpins} ${t.stats.lineClears.penta}"), Text(clears.tSpinPentas.toString())]),
if (showMoreClears) Row(mainAxisAlignment: MainAxisAlignment.spaceBetween, children: [const Text("T-spin quads"), Text(clears.tSpinQuads.toString())]), if (showMoreClears) Row(mainAxisAlignment: MainAxisAlignment.spaceBetween, children: [Text("${t.stats.tSpins} ${t.stats.lineClears.quad}"), Text(clears.tSpinQuads.toString())]),
Row(mainAxisAlignment: MainAxisAlignment.spaceBetween, children: [const Text("T-spins triples"), Text(clears.tSpinTriples.toString())]), Row(mainAxisAlignment: MainAxisAlignment.spaceBetween, children: [Text("${t.stats.tSpins} ${t.stats.lineClears.triple}"), Text(clears.tSpinTriples.toString())]),
Row(mainAxisAlignment: MainAxisAlignment.spaceBetween, children: [const Text("T-spins doubles"), Text(clears.tSpinDoubles.toString())]), Row(mainAxisAlignment: MainAxisAlignment.spaceBetween, children: [Text("${t.stats.tSpins} ${t.stats.lineClears.double}"), Text(clears.tSpinDoubles.toString())]),
Row(mainAxisAlignment: MainAxisAlignment.spaceBetween, children: [const Text("T-spins singles"), Text(clears.tSpinSingles.toString())]), Row(mainAxisAlignment: MainAxisAlignment.spaceBetween, children: [Text("${t.stats.tSpins} ${t.stats.lineClears.single}"), Text(clears.tSpinSingles.toString())]),
Row(mainAxisAlignment: MainAxisAlignment.spaceBetween, children: [const Text("T-spins zeros"), Text(clears.tSpinZeros.toString())]), Row(mainAxisAlignment: MainAxisAlignment.spaceBetween, children: [Text("${t.stats.tSpins} ${t.stats.lineClears.zero}"), Text(clears.tSpinZeros.toString())]),
if (showMoreClears) Row(mainAxisAlignment: MainAxisAlignment.spaceBetween, children: [const Text("Mini T-spins quads"), Text(clears.tSpinMiniQuads.toString())]), if (showMoreClears) Row(mainAxisAlignment: MainAxisAlignment.spaceBetween, children: [Text("${t.stats.mini} ${t.stats.tSpins} ${t.stats.lineClears.quad}"), Text(clears.tSpinMiniQuads.toString())]),
if (showMoreClears) Row(mainAxisAlignment: MainAxisAlignment.spaceBetween, children: [const Text("Mini T-spins triples"), Text(clears.tSpinMiniTriples.toString())]), if (showMoreClears) Row(mainAxisAlignment: MainAxisAlignment.spaceBetween, children: [Text("${t.stats.mini} ${t.stats.tSpins} ${t.stats.lineClears.triple}"), Text(clears.tSpinMiniTriples.toString())]),
Row(mainAxisAlignment: MainAxisAlignment.spaceBetween, children: [const Text("Mini T-spins doubles"), Text(clears.tSpinMiniDoubles.toString())]), Row(mainAxisAlignment: MainAxisAlignment.spaceBetween, children: [Text("${t.stats.mini} ${t.stats.tSpins} ${t.stats.lineClears.double}"), Text(clears.tSpinMiniDoubles.toString())]),
Row(mainAxisAlignment: MainAxisAlignment.spaceBetween, children: [const Text("Mini T-spins singles"), Text(clears.tSpinMiniSingles.toString())]), Row(mainAxisAlignment: MainAxisAlignment.spaceBetween, children: [Text("${t.stats.mini} ${t.stats.tSpins} ${t.stats.lineClears.single}"), Text(clears.tSpinMiniSingles.toString())]),
Row(mainAxisAlignment: MainAxisAlignment.spaceBetween, children: [const Text("Mini T-spins zeros"), Text(clears.tSpinMiniZeros.toString())]), Row(mainAxisAlignment: MainAxisAlignment.spaceBetween, children: [Text("${t.stats.mini} ${t.stats.tSpins} ${t.stats.lineClears.zero}"), Text(clears.tSpinMiniZeros.toString())]),
], ],
), ),
), ),

View File

@ -13,7 +13,7 @@ class TrailingStats extends StatelessWidget{
@override @override
Widget build(BuildContext context) { Widget build(BuildContext context) {
const TextStyle style = TextStyle(height: 1.1, fontWeight: FontWeight.w100, fontSize: 15); const TextStyle style = TextStyle(height: 1.0, fontWeight: FontWeight.w100, fontSize: 14);
return Table( return Table(
defaultColumnWidth: const IntrinsicColumnWidth(), defaultColumnWidth: const IntrinsicColumnWidth(),
defaultVerticalAlignment: TableCellVerticalAlignment.baseline, defaultVerticalAlignment: TableCellVerticalAlignment.baseline,

View File

@ -13,14 +13,6 @@ class NewsThingy extends StatelessWidget{
const NewsThingy(this.news, {super.key}); const NewsThingy(this.news, {super.key});
ListTile getNewsTile(NewsEntry news){ ListTile getNewsTile(NewsEntry news){
Map<String, String> gametypes = {
"40l": t.sprint,
"blitz": t.blitz,
"5mblast": "5,000,000 Blast",
"zenith": "Quick Play",
"zenithex": "Quick Play Expert",
};
// Individuly handle each entry type // Individuly handle each entry type
switch (news.type) { switch (news.type) {
case "leaderboard": case "leaderboard":
@ -32,7 +24,7 @@ class NewsThingy extends StatelessWidget{
children: [ children: [
TextSpan(text: "${news.data["rank"]} ", style: const TextStyle(fontWeight: FontWeight.bold)), TextSpan(text: "${news.data["rank"]} ", style: const TextStyle(fontWeight: FontWeight.bold)),
TextSpan(text: t.newsParts.leaderboardMiddle), TextSpan(text: t.newsParts.leaderboardMiddle),
TextSpan(text: "${gametypes[news.data["gametype"]]}", style: const TextStyle(fontWeight: FontWeight.bold)), TextSpan(text: "${t.gamemodes[news.data["gametype"]]}", style: const TextStyle(fontWeight: FontWeight.bold)),
] ]
) )
), ),
@ -45,7 +37,7 @@ class NewsThingy extends StatelessWidget{
style: const TextStyle(fontFamily: 'Eurostile Round', fontSize: 16, color: Colors.white), style: const TextStyle(fontFamily: 'Eurostile Round', fontSize: 16, color: Colors.white),
text: t.newsParts.personalbest, text: t.newsParts.personalbest,
children: [ children: [
TextSpan(text: "${gametypes[news.data["gametype"]]} ", style: const TextStyle(fontWeight: FontWeight.bold)), TextSpan(text: "${t.gamemodes[news.data["gametype"]]} ", style: const TextStyle(fontWeight: FontWeight.bold)),
TextSpan(text: t.newsParts.personalbestMiddle), TextSpan(text: t.newsParts.personalbestMiddle),
TextSpan(text: switch (news.data["gametype"]){ TextSpan(text: switch (news.data["gametype"]){
"blitz" => NumberFormat.decimalPattern().format(news.data["result"]), "blitz" => NumberFormat.decimalPattern().format(news.data["result"]),

View File

@ -37,7 +37,7 @@ class RecentSingleplayerGames extends StatelessWidget{
title: Text( title: Text(
switch (record.gamemode){ switch (record.gamemode){
"40l" => get40lTime(record.stats.finalTime.inMicroseconds), "40l" => get40lTime(record.stats.finalTime.inMicroseconds),
"blitz" => t.blitzScore(p: NumberFormat.decimalPattern().format(record.stats.score)), "blitz" => t.stats.blitzScore(p: NumberFormat.decimalPattern().format(record.stats.score)),
"5mblast" => get40lTime(record.stats.finalTime.inMicroseconds), "5mblast" => get40lTime(record.stats.finalTime.inMicroseconds),
String() => "huh", String() => "huh",
}, },

View File

@ -114,7 +114,7 @@ class TLRatingThingy extends StatelessWidget{
children: [ children: [
TextSpan(text: prefs.getInt("ratingMode") == 2 ? "${f2.format(tlData.tr)} TR • % ${t.rank}: ${tlData.percentileRank.toUpperCase()}" : "${t.top} ${f2.format(tlData.percentile * 100)}% (${tlData.percentileRank.toUpperCase()})"), TextSpan(text: prefs.getInt("ratingMode") == 2 ? "${f2.format(tlData.tr)} TR • % ${t.rank}: ${tlData.percentileRank.toUpperCase()}" : "${t.top} ${f2.format(tlData.percentile * 100)}% (${tlData.percentileRank.toUpperCase()})"),
if (tlData.bestRank != "z") const TextSpan(text: ""), if (tlData.bestRank != "z") const TextSpan(text: ""),
if (tlData.bestRank != "z") TextSpan(text: "${t.topRank}: ${tlData.bestRank.toUpperCase()}"), if (tlData.bestRank != "z") TextSpan(text: t.stats.topRank(rank: tlData.bestRank.toUpperCase())),
if (topTR != null) TextSpan(text: " (${f2.format(topTR)} TR)"), if (topTR != null) TextSpan(text: " (${f2.format(topTR)} TR)"),
TextSpan(text: "${prefs.getInt("ratingMode") == 1 ? "${f2.format(tlData.tr)} TR • RD: " : "Glicko: ${tlData.glicko != null ? f2.format(tlData.glicko) : "---"}±"}"), TextSpan(text: "${prefs.getInt("ratingMode") == 1 ? "${f2.format(tlData.tr)} TR • RD: " : "Glicko: ${tlData.glicko != null ? f2.format(tlData.glicko) : "---"}±"}"),
TextSpan(text: f2.format(tlData.rd!), style: tlData.decaying ? TextStyle(color: tlData.rd! > 98 ? Colors.red : Colors.yellow) : null), TextSpan(text: f2.format(tlData.rd!), style: tlData.decaying ? TextStyle(color: tlData.rd! > 98 ? Colors.red : Colors.yellow) : null),

View File

@ -215,14 +215,14 @@ class _UserThingyState extends State<UserThingy> with SingleTickerProviderStateM
showLabels: false showLabels: false
), ),
), ),
Text("${t.statCellNum.xpProgress}: ${((widget.player.level - widget.player.level.floor()) * 100).toStringAsFixed(2)} %"), Text(t.xp.progressToNextLevel(percentage: percentage.format((widget.player.level - widget.player.level.floor())))),
Text("${t.statCellNum.xpFrom0ToLevel(n: xpTableScuffed.keys.toList()[xpTableID])}: ${((widget.player.xp / xpTableScuffed.values.toList()[xpTableID]) * 100).toStringAsFixed(2)} % (${NumberFormat.decimalPatternDigits(locale: LocaleSettings.currentLocale.languageCode, decimalDigits: 0).format(xpTableScuffed.values.toList()[xpTableID] - widget.player.xp)} ${t.statCellNum.xpLeft})") Text(t.xp.progressTowardsGoal(goal: xpTableScuffed.keys.toList()[xpTableID], percentage: percentage.format(widget.player.xp / xpTableScuffed.values.toList()[xpTableID]), left: NumberFormat.decimalPatternDigits(locale: LocaleSettings.currentLocale.languageCode, decimalDigits: 0).format(xpTableScuffed.values.toList()[xpTableID] - widget.player.xp)))
] ]
), ),
), ),
actions: <Widget>[ actions: <Widget>[
TextButton( TextButton(
child: const Text("OK"), child: Text(t.actions.ok),
onPressed: () {Navigator.of(context).pop();} onPressed: () {Navigator.of(context).pop();}
) )
] ]
@ -236,7 +236,7 @@ class _UserThingyState extends State<UserThingy> with SingleTickerProviderStateM
showDialog( showDialog(
context: context, context: context,
builder: (BuildContext context) => AlertDialog( builder: (BuildContext context) => AlertDialog(
title: Text(t.exactGametime, textAlign: TextAlign.center), title: Text(t.gametime.title, textAlign: TextAlign.center),
content: SingleChildScrollView( content: SingleChildScrollView(
child: Column( child: Column(
children: [ children: [
@ -248,15 +248,20 @@ class _UserThingyState extends State<UserThingy> with SingleTickerProviderStateM
TextSpan(text: ".${nonsecs3.format(widget.player.gameTime.inMicroseconds%1000000)}", style: TextStyle(fontSize: 14)) TextSpan(text: ".${nonsecs3.format(widget.player.gameTime.inMicroseconds%1000000)}", style: TextStyle(fontSize: 14))
] ]
)), )),
Text("${playtime(avgGametimeADay)} a day in average"), Text(t.gametime.gametimeAday(gametime: playtime(avgGametimeADay))),
Padding( Padding(
padding: const EdgeInsets.only(top: 8.0), padding: const EdgeInsets.only(top: 8.0),
child: Text("It's ${f4.format(widget.player.gameTime.inSeconds/31536000)} years,"), child: Text(
), textAlign: TextAlign.center,
Text("or ${f4.format(widget.player.gameTime.inSeconds/2628000)} months,"), t.gametime.breakdown(
Text("or ${f4.format(widget.player.gameTime.inSeconds/86400)} days,"), years: f4.format(widget.player.gameTime.inSeconds/31536000),
Text("or ${f2.format(widget.player.gameTime.inMilliseconds/60000)} minutes,"), months: f4.format(widget.player.gameTime.inSeconds/2628000),
Text("or ${intf.format(widget.player.gameTime.inSeconds)} seconds"), days: f4.format(widget.player.gameTime.inSeconds/86400),
minutes: f2.format(widget.player.gameTime.inMilliseconds/60000),
seconds: intf.format(widget.player.gameTime.inSeconds)
)
),
)
] ]
), ),
), ),

View File

@ -227,13 +227,13 @@ class VsGraphs extends StatelessWidget{
getTitle: (index, angle) { getTitle: (index, angle) {
switch (index) { switch (index) {
case 0: case 0:
return RadarChartTitle(text: t.graphs.attack, angle: 0, positionPercentageOffset: 0.05); return RadarChartTitle(text: t.stats.graphs.attack, angle: 0, positionPercentageOffset: 0.05);
case 1: case 1:
return RadarChartTitle(text: t.graphs.speed, angle: 0, positionPercentageOffset: 0.05); return RadarChartTitle(text: t.stats.graphs.speed, angle: 0, positionPercentageOffset: 0.05);
case 2: case 2:
return RadarChartTitle(text: t.graphs.defense, angle: angle + 180, positionPercentageOffset: 0.05); return RadarChartTitle(text: t.stats.graphs.defense, angle: angle + 180, positionPercentageOffset: 0.05);
case 3: case 3:
return RadarChartTitle(text: t.graphs.cheese, angle: 0, positionPercentageOffset: 0.05); return RadarChartTitle(text: t.stats.graphs.cheese, angle: 0, positionPercentageOffset: 0.05);
default: default:
return const RadarChartTitle(text: ''); return const RadarChartTitle(text: '');
} }

View File

@ -4,13 +4,14 @@
"ru": "Russian (Русский)", "ru": "Russian (Русский)",
"zh-CN": "Simplified Chinese (简体中文)" "zh-CN": "Simplified Chinese (简体中文)"
}, },
"gamemodes":{ "gamemodes(map)":{
"tl": "Tetra League", "league": "Tetra League",
"zenith": "Quick Play", "zenith": "Quick Play",
"zenithex": "Quick Play Expert", "zenithex": "Quick Play Expert",
"40l": "40 Lines", "40l": "40 Lines",
"blitz": "Blitz", "blitz": "Blitz",
"5mblast": "5,000,000 Blast" "5mblast": "5,000,000 Blast",
"zen": "Zen"
}, },
"destinations": { "destinations": {
"home": "Home", "home": "Home",
@ -26,6 +27,7 @@
"nanow": "Not avaliable for now...", "nanow": "Not avaliable for now...",
"seasonEnds": "Season ends in ${countdown}", "seasonEnds": "Season ends in ${countdown}",
"seasonEnded": "Season has ended", "seasonEnded": "Season has ended",
"overallPB": "Overall PB: $pb",
"gamesUntilRanked": "${left} games until being ranked", "gamesUntilRanked": "${left} games until being ranked",
"numOfVictories": "~${wins} victories", "numOfVictories": "~${wins} victories",
"promotionOnNextWin": "Promotion on next win", "promotionOnNextWin": "Promotion on next win",
@ -33,6 +35,7 @@
"demotionOnNextLoss": "Demotion on next loss", "demotionOnNextLoss": "Demotion on next loss",
"records": "Records", "records": "Records",
"nerdStats": "Nerd Stats", "nerdStats": "Nerd Stats",
"playstyles": "Playstyles",
"horoscopes": "Horoscopes", "horoscopes": "Horoscopes",
"season": "Season", "season": "Season",
"smooth": "Smooth", "smooth": "Smooth",
@ -43,12 +46,15 @@
"verdictBetter": "ahead", "verdictBetter": "ahead",
"verdictWorse": "behind", "verdictWorse": "behind",
"localStanding": "local", "localStanding": "local",
"xpProgressToNextLevel": "Progress to next level: $percentage", "xp": {
"xpProgressTowardsGoal": "Progress from 0 XP to level $goal: $percentage ($left xp left)", "title": "XP Level",
"progressToNextLevel": "Progress to next level: $percentage",
"progressTowardsGoal": "Progress from 0 XP to level $goal: $percentage ($left XP left)"
},
"gametime":{ "gametime":{
"title": "Exact gametime", "title": "Exact gametime",
"gametimeAday": "$gametime a day in average", "gametimeAday": "$gametime a day in average",
"breakdown": "It's $years years,\nor $months months,\nor $days days,\nor$minutes minutes\nor $seconds seconds" "breakdown": "It's $years years,\nor $months months,\nor $days days,\nor $minutes minutes\nor $seconds seconds"
}, },
"track": "Track", "track": "Track",
"stopTracking": "Stop tracking", "stopTracking": "Stop tracking",
@ -90,6 +96,15 @@
"previousSeasons": "Previous Seasons", "previousSeasons": "Previous Seasons",
"recent": "Recent", "recent": "Recent",
"top": "Top", "top": "Top",
"noRecord": "No record",
"sprintAndBlitsRelevance": "Relevance: ${date}",
"snackBarMessages":{
"stateRemoved": "${date} state was removed from database!",
"matchRemoved": "${date} match was removed from database!",
"notForWeb": "Function is not available for web version",
"importSuccess": "Import successful",
"importCancelled": "Import was cancelled"
},
"errors": { "errors": {
"noRecords": "No records", "noRecords": "No records",
"notEnoughData": "Not enough data", "notEnoughData": "Not enough data",
@ -125,8 +140,21 @@
"cancel": "Cancel", "cancel": "Cancel",
"submit": "Submit", "submit": "Submit",
"ok": "OK", "ok": "OK",
"apply": "Apply",
"refresh": "Refresh" "refresh": "Refresh"
}, },
"graphsDestination": {
"fetchAndsaveTLHistory": "Get player history",
"fetchAndSaveOldTLmatches": "Get Tetra League matches history",
"fetchAndsaveTLHistoryResult": "${number} states was found",
"fetchAndSaveOldTLmatchesResult": "${number} matches was found",
"gamesPlayed": "$games played",
"dateAndTime": "Date & Time",
"filterModaleTitle": "Filter ranks on graph"
},
"filterModale":{
"all": "All"
},
"cutoffsDestination": { "cutoffsDestination": {
"title": "Tetra League State", "title": "Tetra League State",
"relevance": "as of $timestamp", "relevance": "as of $timestamp",
@ -140,7 +168,9 @@
"moreInfo": "More Info", "moreInfo": "More Info",
"NumberOne": "№ 1 is $tr TR", "NumberOne": "№ 1 is $tr TR",
"inflated": "Inflated on $tr TR", "inflated": "Inflated on $tr TR",
"notInflated": "Not inflated",
"deflated": "Deflated on $tr TR", "deflated": "Deflated on $tr TR",
"notDeflated": "Not deflated",
"wellDotDotDot": "Well...", "wellDotDotDot": "Well...",
"fromPlace": "from № $n", "fromPlace": "from № $n",
"viewButton": "View" "viewButton": "View"
@ -162,8 +192,74 @@
"minimums": "Minimums", "minimums": "Minimums",
"maximums": "Maximums" "maximums": "Maximums"
}, },
"tlMatchView": {
"match": "Match",
"vs": "vs",
"winner": "Winner",
"roundNumber": "Round $n",
"statsFor": "Stats for",
"numberOfRounds": "Number of rounds",
"matchLength": "Match Length",
"roundLength": "Round Length",
"matchStats": "Match stats",
"downloadReplay": "Download .ttrm replay",
"openReplay": "Open replay in TETR.IO"
},
"calcDestination": { "calcDestination": {
"tip": "Enter values and press \"Calc\" to see Nerd Stats for them" "tip": "Enter values and press \"Calc\" to see Nerd Stats for them",
"statsCalcButton": "Calc",
"damageCalcTip": "Click on the actions on the left to add them here",
"actions": "Actions",
"results": "Results",
"rules": "Rules",
"noSpinClears": "No Spin Clears",
"spins": "Spins",
"miniSpins": "Mini spins",
"noLineclear": "No lineclear (Break Combo)",
"custom": "Custom",
"multiplier": "Multiplier",
"pcDamage": "Perfect Clear Damage",
"comboTable": "Combo Table",
"b2bChaining": "Back-To-Back Chaining",
"surgeStartAtB2B": "Starts at B2B",
"surgeStartAmount": "Start amount",
"totalDamage": "Total damage",
"lineclears": "Lineclears",
"combo": "Combo",
"surge": "Surge",
"pcs": "PCs"
},
"infoDestination": {
"title": "Information Center",
"sprintAndBlitzAverages": "40 Lines & Blitz Averages",
"sprintAndBlitzAveragesDescription": "Since calculating 40 Lines & Blitz averages is tedious process, it gets updated only once in a while. Click on the title of this card to see the full 40 Lines & Blitz averages table",
"tetraStatsWiki": "Tetra Stats Wiki",
"tetraStatsWikiDescription": "Find more information about Tetra Stats functions and statictic, that it provides",
"about": "About Tetra Stats",
"aboutDescription": "Developed by dan63\n"
},
"leaderboardsDestination": {
"title": "Leaderboards",
"tl": "Tetra League (Current Season)",
"fullTL": "Tetra League (Current Season, full one)",
"ar": "Acievement Points",
"fullTLnote": "Heavy, but allows you to sort players by their stats and filter them by ranks"
},
"settingsDestination": {
"title": "Settings",
"timestamps": "Timestamps",
"timestampsDescription": "You can choose, in which way timestamps shows time",
"timestampsAbsoluteGMT": "Absolute (GMT)",
"timestampsAbsoluteLocalTime": "Absolute (Your timezone)",
"timestampsRelative": "Relative",
"exportDB": "Export local database",
"desktopExportAlertTitle": "Desktop export",
"desktopExportText": "It seems like you using this app on desktop. Check your documents folder, you should find \"TetraStats.db\". Copy it somewhere",
"androidExportAlertTitle": "Android export",
"androidExportText": "Exported.\n${exportedDB}",
"importDB": "Import local database",
"importDBDescription": "Restore your backup. Notice that already stored database will be overwritten.",
"importWrongFileType": "Wrong file type"
}, },
"homeNavigation": { "homeNavigation": {
"overview": "Overview", "overview": "Overview",
@ -184,7 +280,31 @@
"stats": "Stats Calculator", "stats": "Stats Calculator",
"damage": "Damage Calculator" "damage": "Damage Calculator"
}, },
"aboutView": {
"title": "About Tetra Stats",
"about": "Tetra Stats is a service, that works with TETR.IO Tetra Channel API, providing data from it and calculating some addtitional metrics, based on this data. Service allows user to track their progress in Tetra League with \"Track\" function, which records every Tetra League change into local database (not automatically, you have to visit service from time to time), so these changes could be looked through graphs.\n\nBeanserver blaster is a part of a Tetra Stats, that decoupled into a serverside script. It provides full Tetra League leaderboard, allowing Tetra Stats to sort leaderboard by any metric and build scatter chart, that allows user to analyse Tetra League trends. It also provides history of Tetra League ranks cutoffs, which can be viewed by user via graph as well.\n\nThere is a plans to add replay analysis and tournaments history, so stay tuned!\n\nService is not associated with TETR.IO or osk in any capacity.",
"appVersion": "App Version",
"build": "Build $build",
"GHrepo": "GitHub Repository",
"submitAnIssue": "Submit an issue",
"credits": "Credits",
"authorAndDeveloper": "Autor & developer",
"providedFormulas": "Provided formulas",
"providedS1history": "Provided S1 history",
"inoue": "Inoue (replay grabber)",
"zhCNlocale": "Simplfied Chinise locale",
"supportHim": "Support him!"
},
"stats": { "stats": {
"registrationDate": "Registration Date",
"gametime": "Time Played",
"ogp": "Online Games Played",
"ogw": "Online Games Won",
"followers": "Followers",
"xp": {
"short": "XP",
"full": "Experience Points"
},
"tr": { "tr": {
"short": "TR", "short": "TR",
"full": "Tetra Rating" "full": "Tetra Rating"
@ -201,6 +321,10 @@
"short": "GXE", "short": "GXE",
"full": "GLIXARE" "full": "GLIXARE"
}, },
"s1tr": {
"short": "S1 TR",
"full": "Season 1 like TR"
},
"gp":{ "gp":{
"short": "GP", "short": "GP",
"full": "Games Played" "full": "Games Played"
@ -229,6 +353,10 @@
"short": "APP", "short": "APP",
"full": "Attack Per Piece" "full": "Attack Per Piece"
}, },
"vsapm":{
"short": "VS/APM",
"full": "VS / APM"
},
"dss":{ "dss":{
"short": "DS/S", "short": "DS/S",
"full": "Downstack Per Second" "full": "Downstack Per Second"
@ -237,6 +365,10 @@
"short": "DS/P", "short": "DS/P",
"full": "Downstack Per Piece" "full": "Downstack Per Piece"
}, },
"appdsp": {
"short": "APP+DSP",
"full": "APP + DSP"
},
"cheese":{ "cheese":{
"short": "Cheese", "short": "Cheese",
"full": "Cheese Index" "full": "Cheese Index"
@ -304,6 +436,10 @@
"full": "Finesse", "full": "Finesse",
"widgetTitle": "inesse" "widgetTitle": "inesse"
}, },
"finesseFaults":{
"short": "FF",
"full": "Finesse Faults"
},
"totalTime":{ "totalTime":{
"short": "Time", "short": "Time",
"full": "Total Time", "full": "Total Time",
@ -313,12 +449,43 @@
"short": "Lvl", "short": "Lvl",
"full": "Level" "full": "Level"
}, },
"pieces": {
"short": "P",
"full": "Pieces"
},
"spp": {
"short": "SPP",
"full": "Score Per Piece"
},
"kp": {
"short": "KP",
"full": "Key presses"
},
"kpp": {
"short": "KPP",
"full": "Key presses Per Piece"
},
"kps": {
"short": "KPS",
"full": "Key presses Per Second"
},
"blitzScore": "$p points",
"levelUpRequirement": "Level up requirement: $p",
"piecesTotal": "Total pieces placed",
"piecesWithPerfectFinesse": "Placed with perfect finesse",
"score": "Score",
"lines": "Lines",
"pcs": "Perfect Clears",
"holds": "Holds",
"spike": "Top Spike", "spike": "Top Spike",
"top": "Top $percentage", "top": "Top $percentage",
"topRank": "Top rank: $rank", "topRank": "Top rank: $rank",
"floor": "Floor", "floor": "Floor",
"split": "Split", "split": "Split",
"total": "Total", "total": "Total",
"sent": "Sent",
"received": "Received",
"placement": "Placement",
"qpWithMods(plural)": { "qpWithMods(plural)": {
"one": "With 1 mod", "one": "With 1 mod",
"two": "With $n mods", "two": "With $n mods",
@ -342,7 +509,7 @@
"many": "$n T-spins total", "many": "$n T-spins total",
"other": "$n T-spins total" "other": "$n T-spins total"
}, },
"lineClears(plural)": { "linesCleared(plural)": {
"zero": "$n lines cleared", "zero": "$n lines cleared",
"one": "$n line cleared", "one": "$n line cleared",
"two": "$n lines cleared", "two": "$n lines cleared",
@ -372,7 +539,7 @@
"many": "$n games", "many": "$n games",
"other": "$n games" "other": "$n games"
}, },
"lineClears(map)": { "lineClear": {
"single": "Single", "single": "Single",
"double": "Double", "double": "Double",
"triple": "Triple", "triple": "Triple",
@ -395,8 +562,19 @@
"eicosa": "Eicosa", "eicosa": "Eicosa",
"kagaris": "Kagaris" "kagaris": "Kagaris"
}, },
"lineClears": {
"zero": "Zeros",
"single": "Singles",
"double": "Doubles",
"triple": "Triples",
"quad": "Quads",
"penta": "Pentas"
},
"mini": "Mini",
"tSpin": "T-spin", "tSpin": "T-spin",
"spin": "Spin" "tSpins": "T-spins",
"spin": "Spin",
"spins": "Spins"
}, },
"countries(map)": { "countries(map)": {
"": "Worldwide", "": "Worldwide",