diff --git a/lib/main.dart b/lib/main.dart index 43b4b69..3ee07f5 100644 --- a/lib/main.dart +++ b/lib/main.dart @@ -16,6 +16,7 @@ import 'package:tetra_stats/views/tracked_players_view.dart'; import 'package:tetra_stats/views/calc_view.dart'; late final PackageInfo packageInfo; +late SharedPreferences prefs; void main() async { if (kIsWeb) { diff --git a/lib/views/calc_view.dart b/lib/views/calc_view.dart index 8191e97..aee802e 100644 --- a/lib/views/calc_view.dart +++ b/lib/views/calc_view.dart @@ -1,10 +1,10 @@ import 'dart:io'; -import 'package:fl_chart/fl_chart.dart'; import 'package:flutter/foundation.dart'; import 'package:flutter/material.dart'; import 'package:intl/intl.dart'; import 'package:tetra_stats/data_objects/tetrio.dart'; import 'package:tetra_stats/gen/strings.g.dart'; +import 'package:tetra_stats/widgets/graphs.dart'; import 'package:window_manager/window_manager.dart'; double? apm; @@ -131,165 +131,7 @@ class CalcState extends State { _ListEntry(value: nerdStats!.nyaapp, label: t.statCellNum.nyaapp.replaceAll(RegExp(r'\n'), " "), fractionDigits: 3), _ListEntry(value: nerdStats!.area, label: t.statCellNum.area.replaceAll(RegExp(r'\n'), " "), fractionDigits: 3), _ListEntry(value: estTr!.esttr, label: t.statCellNum.estOfTR, fractionDigits: 3), - Wrap( - direction: Axis.horizontal, - alignment: WrapAlignment.center, - spacing: 25, - crossAxisAlignment: WrapCrossAlignment.start, - clipBehavior: Clip.hardEdge, - children: [ - Padding( - padding: const EdgeInsets.fromLTRB(18, 0, 18, 44), - child: SizedBox( - height: 310, - width: 310, - child: RadarChart( - RadarChartData( - radarShape: RadarShape.polygon, - tickCount: 4, - ticksTextStyle: const TextStyle(color: Colors.transparent, fontSize: 10), - radarBorderData: const BorderSide(color: Colors.transparent, width: 1), - gridBorderData: const BorderSide(color: Colors.white24, width: 1), - tickBorderData: const BorderSide(color: Colors.transparent, width: 1), - getTitle: (index, angle) { - switch (index) { - case 0: - return RadarChartTitle( - text: 'APM', - angle: angle, - positionPercentageOffset: 0.05 - ); - case 1: - return RadarChartTitle( - text: 'PPS', - angle: angle, - positionPercentageOffset: 0.05 - ); - case 2: - return RadarChartTitle(text: 'VS', angle: angle, positionPercentageOffset: 0.05); - case 3: - return RadarChartTitle(text: 'APP', angle: angle + 180, positionPercentageOffset: 0.05); - case 4: - return RadarChartTitle(text: 'DS/S', angle: angle + 180, positionPercentageOffset: 0.05); - case 5: - return RadarChartTitle(text: 'DS/P', angle: angle + 180, positionPercentageOffset: 0.05); - case 6: - return RadarChartTitle(text: 'APP+DS/P', angle: angle + 180, positionPercentageOffset: 0.05); - case 7: - return RadarChartTitle(text: 'VS/APM', angle: angle + 180, positionPercentageOffset: 0.05); - case 8: - return RadarChartTitle(text: 'Cheese', angle: angle, positionPercentageOffset: 0.05); - case 9: - return RadarChartTitle(text: 'Gb Eff.', angle: angle, positionPercentageOffset: 0.05); - default: - return const RadarChartTitle(text: ''); - } - }, - dataSets: [ - RadarDataSet( - dataEntries: [ - RadarEntry(value: apm! * 1), - RadarEntry(value: pps! * 45), - RadarEntry(value: vs! * 0.444), - RadarEntry(value: nerdStats!.app * 185), - RadarEntry(value: nerdStats!.dss * 175), - RadarEntry(value: nerdStats!.dsp * 450), - RadarEntry(value: nerdStats!.appdsp * 140), - RadarEntry(value: nerdStats!.vsapm * 60), - RadarEntry(value: nerdStats!.cheese * 1.25), - RadarEntry(value: nerdStats!.gbe * 315), - ], - ), - RadarDataSet( - fillColor: Colors.transparent, - borderColor: Colors.transparent, - dataEntries: [ - const RadarEntry(value: 0), - const RadarEntry(value: 0), - const RadarEntry(value: 0), - const RadarEntry(value: 0), - const RadarEntry(value: 0), - const RadarEntry(value: 0), - const RadarEntry(value: 0), - const RadarEntry(value: 0), - const RadarEntry(value: 0), - const RadarEntry(value: 0), - ], - ) - ], - ), - swapAnimationDuration: const Duration(milliseconds: 150), // Optional - swapAnimationCurve: Curves.linear, // Optional - ), - ), - ), - Padding( - padding: const EdgeInsets.fromLTRB(18, 0, 18, 44), - child: SizedBox( - height: 310, - width: 310, - child: RadarChart( - RadarChartData( - radarShape: RadarShape.polygon, - tickCount: 4, - ticksTextStyle: const TextStyle(color: Colors.white24, fontSize: 10), - radarBorderData: const BorderSide(color: Colors.transparent, width: 1), - gridBorderData: const BorderSide(color: Colors.white24, width: 1), - tickBorderData: const BorderSide(color: Colors.transparent, width: 1), - titleTextStyle: const TextStyle(height: 1.1), - radarTouchData: RadarTouchData(), - getTitle: (index, angle) { - switch (index) { - case 0: - return RadarChartTitle(text: 'Opener\n${f2.format(playstyle!.opener)}', angle: 0, positionPercentageOffset: 0.05); - case 1: - return RadarChartTitle(text: 'Stride\n${f2.format(playstyle!.stride)}', angle: 0, positionPercentageOffset: 0.05); - case 2: - return RadarChartTitle(text: 'Inf Ds\n${f2.format(playstyle!.infds)}', angle: angle + 180, positionPercentageOffset: 0.05); - case 3: - return RadarChartTitle(text: 'Plonk\n${f2.format(playstyle!.plonk)}', angle: 0, positionPercentageOffset: 0.05); - default: - return const RadarChartTitle(text: ''); - } - }, - dataSets: [ - RadarDataSet( - dataEntries: [ - RadarEntry(value: playstyle!.opener), - RadarEntry(value: playstyle!.stride), - RadarEntry(value: playstyle!.infds), - RadarEntry(value: playstyle!.plonk), - ], - ), - RadarDataSet( - fillColor: Colors.transparent, - borderColor: Colors.transparent, - dataEntries: [ - const RadarEntry(value: 0), - const RadarEntry(value: 0), - const RadarEntry(value: 0), - const RadarEntry(value: 0), - ], - ), - RadarDataSet( - fillColor: Colors.transparent, - borderColor: Colors.transparent, - dataEntries: [ - const RadarEntry(value: 1), - const RadarEntry(value: 1), - const RadarEntry(value: 1), - const RadarEntry(value: 1), - ], - ) - ], - ), - swapAnimationDuration: const Duration(milliseconds: 150), // Optional - swapAnimationCurve: Curves.linear, // Optional - ), - ), - ), - ], - ) + Graphs(apm!, pps!, vs!, nerdStats!, playstyle!), ], )), ), diff --git a/lib/views/compare_view.dart b/lib/views/compare_view.dart index 45ab9b1..921d941 100644 --- a/lib/views/compare_view.dart +++ b/lib/views/compare_view.dart @@ -1,12 +1,12 @@ import 'dart:io'; import 'dart:math'; -import 'package:fl_chart/fl_chart.dart'; import 'package:flutter/foundation.dart'; import 'package:flutter/material.dart'; import 'package:intl/intl.dart'; import 'package:tetra_stats/data_objects/tetrio.dart'; import 'package:tetra_stats/gen/strings.g.dart'; import 'package:tetra_stats/services/tetrio_crud.dart'; +import 'package:tetra_stats/widgets/vs_graphs.dart'; import 'package:window_manager/window_manager.dart'; enum Mode{ @@ -612,13 +612,13 @@ class CompareState extends State { theGreenSide[2].gamesPlayed > 9 && greenSideMode != Mode.stats && redSideMode != Mode.stats) - CompareThingy( - label: t.statCellNum.accOfEstShort, - greenSide: theGreenSide[2].esttracc!, - redSide: theRedSide[2].esttracc!, - fractionDigits: 2, - higherIsBetter: true, - ), + CompareThingy( + label: t.statCellNum.accOfEstShort, + greenSide: theGreenSide[2].esttracc!, + redSide: theRedSide[2].esttracc!, + fractionDigits: 2, + higherIsBetter: true, + ), CompareThingy( label: "Opener", greenSide: theGreenSide[2].playstyle!.opener, @@ -647,239 +647,51 @@ class CompareState extends State { fractionDigits: 3, higherIsBetter: true, ), - Wrap( - direction: Axis.horizontal, - alignment: WrapAlignment.center, - spacing: 25, - crossAxisAlignment: WrapCrossAlignment.start, - clipBehavior: Clip.hardEdge, - children: [ - Padding( - padding: const EdgeInsets.fromLTRB(18, 0, 18, 44), - child: SizedBox( - height: 310, - width: 310, - child: RadarChart( - RadarChartData( - radarShape: RadarShape.polygon, - tickCount: 4, - ticksTextStyle: const TextStyle(color: Colors.transparent, fontSize: 10), - radarBorderData: const BorderSide(color: Colors.transparent, width: 1), - gridBorderData: const BorderSide(color: Colors.white24, width: 1), - tickBorderData: const BorderSide(color: Colors.transparent, width: 1), - getTitle: (index, angle) { - switch (index) { - case 0: - return RadarChartTitle( - text: 'APM', - angle: angle, - positionPercentageOffset: 0.05 - ); - case 1: - return RadarChartTitle( - text: 'PPS', - angle: angle, - positionPercentageOffset: 0.05 - ); - case 2: - return RadarChartTitle(text: 'VS', angle: angle, positionPercentageOffset: 0.05); - case 3: - return RadarChartTitle(text: 'APP', angle: angle + 180, positionPercentageOffset: 0.05); - case 4: - return RadarChartTitle(text: 'DS/S', angle: angle + 180, positionPercentageOffset: 0.05); - case 5: - return RadarChartTitle(text: 'DS/P', angle: angle + 180, positionPercentageOffset: 0.05); - case 6: - return RadarChartTitle(text: 'APP+DS/P', angle: angle + 180, positionPercentageOffset: 0.05); - case 7: - return RadarChartTitle(text: 'VS/APM', angle: angle + 180, positionPercentageOffset: 0.05); - case 8: - return RadarChartTitle(text: 'Cheese', angle: angle, positionPercentageOffset: 0.05); - case 9: - return RadarChartTitle(text: 'Gb Eff.', angle: angle, positionPercentageOffset: 0.05); - default: - return const RadarChartTitle(text: ''); - } - }, - dataSets: [ - RadarDataSet( - fillColor: const Color.fromARGB(115, 76, 175, 79), - borderColor: Colors.green, - dataEntries: [ - RadarEntry(value: theGreenSide[2].apm! * apmWeight), - RadarEntry(value: theGreenSide[2].pps! * ppsWeight), - RadarEntry(value: theGreenSide[2].vs! * vsWeight), - RadarEntry(value: theGreenSide[2].nerdStats!.app * appWeight), - RadarEntry(value: theGreenSide[2].nerdStats!.dss * dssWeight), - RadarEntry(value: theGreenSide[2].nerdStats!.dsp * dspWeight), - RadarEntry(value: theGreenSide[2].nerdStats!.appdsp * appdspWeight), - RadarEntry(value: theGreenSide[2].nerdStats!.vsapm * vsapmWeight), - RadarEntry(value: theGreenSide[2].nerdStats!.cheese * cheeseWeight), - RadarEntry(value: theGreenSide[2].nerdStats!.gbe * gbeWeight), - ], - ), - RadarDataSet( - fillColor: const Color.fromARGB(115, 244, 67, 54), - borderColor: Colors.red, - dataEntries: [ - RadarEntry(value: theRedSide[2].apm! * apmWeight), - RadarEntry(value: theRedSide[2].pps! * ppsWeight), - RadarEntry(value: theRedSide[2].vs! * vsWeight), - RadarEntry(value: theRedSide[2].nerdStats!.app * appWeight), - RadarEntry(value: theRedSide[2].nerdStats!.dss * dssWeight), - RadarEntry(value: theRedSide[2].nerdStats!.dsp * dspWeight), - RadarEntry(value: theRedSide[2].nerdStats!.appdsp * appdspWeight), - RadarEntry(value: theRedSide[2].nerdStats!.vsapm * vsapmWeight), - RadarEntry(value: theRedSide[2].nerdStats!.cheese * cheeseWeight), - RadarEntry(value: theRedSide[2].nerdStats!.gbe * gbeWeight), - ], - ), - RadarDataSet( - fillColor: Colors.transparent, - borderColor: Colors.transparent, - dataEntries: [ - const RadarEntry(value: 0), - const RadarEntry(value: 0), - const RadarEntry(value: 0), - const RadarEntry(value: 0), - const RadarEntry(value: 0), - const RadarEntry(value: 0), - const RadarEntry(value: 0), - const RadarEntry(value: 0), - const RadarEntry(value: 0), - const RadarEntry(value: 0), - ], - ) - ], - ), - swapAnimationDuration: const Duration(milliseconds: 150), - swapAnimationCurve: Curves.linear, - ), - ), - ), - Padding( - padding: const EdgeInsets.fromLTRB(18, 0, 18, 44), - child: SizedBox( - height: 310, - width: 310, - child: RadarChart( - RadarChartData( - radarShape: RadarShape.polygon, - tickCount: 4, - ticksTextStyle: const TextStyle(color: Colors.white24, fontSize: 10), - radarBorderData: const BorderSide(color: Colors.transparent, width: 1), - gridBorderData: const BorderSide(color: Colors.white24, width: 1), - tickBorderData: const BorderSide(color: Colors.transparent, width: 1), - titleTextStyle: const TextStyle(height: 1.1), - radarTouchData: RadarTouchData(), - getTitle: (index, angle) { - switch (index) { - case 0: - return RadarChartTitle(text: 'Opener',angle: angle, positionPercentageOffset: 0.05); - case 1: - return RadarChartTitle(text: 'Stride', angle: angle, positionPercentageOffset: 0.05); - case 2: - return RadarChartTitle(text: 'Inf Ds', angle: angle + 180, positionPercentageOffset: 0.05); - case 3: - return RadarChartTitle(text: 'Plonk', angle: angle, positionPercentageOffset: 0.05); - default: - return const RadarChartTitle(text: ''); - } - }, - dataSets: [ - RadarDataSet( - fillColor: const Color.fromARGB(115, 76, 175, 79), - borderColor: Colors.green, - dataEntries: [ - RadarEntry(value: theGreenSide[2].playstyle!.opener), - RadarEntry(value: theGreenSide[2].playstyle!.stride), - RadarEntry(value: theGreenSide[2].playstyle!.infds), - RadarEntry(value: theGreenSide[2].playstyle!.plonk), - ], - ), - RadarDataSet( - fillColor: const Color.fromARGB(115, 244, 67, 54), - borderColor: Colors.red, - dataEntries: [ - RadarEntry(value: theRedSide[2].playstyle!.opener), - RadarEntry(value: theRedSide[2].playstyle!.stride), - RadarEntry(value: theRedSide[2].playstyle!.infds), - RadarEntry(value: theRedSide[2].playstyle!.plonk), - ], - ), - RadarDataSet( - fillColor: Colors.transparent, - borderColor: Colors.transparent, - dataEntries: [ - const RadarEntry(value: 0), - const RadarEntry(value: 0), - const RadarEntry(value: 0), - const RadarEntry(value: 0), - ], - ), - RadarDataSet( - fillColor: Colors.transparent, - borderColor: Colors.transparent, - dataEntries: [ - const RadarEntry(value: 1), - const RadarEntry(value: 1), - const RadarEntry(value: 1), - const RadarEntry(value: 1), - ], - ) - ], - ), - swapAnimationDuration: const Duration(milliseconds: 150), // Optional - swapAnimationCurve: Curves.linear, // Optional - ), - ), - ), - const Divider(), - Padding( - padding: const EdgeInsets.only(bottom: 16), - child: Text(t.winChance, - style: TextStyle( - fontFamily: "Eurostile Round Extended", - fontSize: bigScreen ? 42 : 28)), - ), - if (greenSideMode != Mode.stats && redSideMode != Mode.stats && - theGreenSide[2].gamesPlayed > 9 && theRedSide[2].gamesPlayed > 9) - CompareThingy( - label: t.byGlicko, - greenSide: getWinrateByTR( - theGreenSide[2].glicko!, - theGreenSide[2].rd!, - theRedSide[2].glicko!, - theRedSide[2].rd!) * - 100, - redSide: getWinrateByTR( - theRedSide[2].glicko!, - theRedSide[2].rd!, - theGreenSide[2].glicko!, - theGreenSide[2].rd!) * - 100, - fractionDigits: 2, - higherIsBetter: true, - ), - CompareThingy( - label: t.byEstTR, - greenSide: getWinrateByTR( - theGreenSide[2].estTr!.estglicko, - theGreenSide[2].rd ?? noTrRd, - theRedSide[2].estTr!.estglicko, - theRedSide[2].rd ?? noTrRd) * - 100, - redSide: getWinrateByTR( - theRedSide[2].estTr!.estglicko, - theRedSide[2].rd ?? noTrRd, - theGreenSide[2].estTr!.estglicko, - theGreenSide[2].rd ?? noTrRd) * - 100, - fractionDigits: 2, - higherIsBetter: true, - ), - ], - ) + VsGraphs(theGreenSide[2].apm!, theGreenSide[2].pps!, theGreenSide[2].vs!, theGreenSide[2].nerdStats!, theGreenSide[2].playstyle!, theRedSide[2].apm!, theRedSide[2].pps!, theRedSide[2].vs!, theRedSide[2].nerdStats!, theRedSide[2].playstyle!), + const Divider(), + Padding( + padding: const EdgeInsets.only(bottom: 16), + child: Text(t.winChance, + style: TextStyle( + fontFamily: "Eurostile Round Extended", + fontSize: bigScreen ? 42 : 28)), + ), + if (greenSideMode != Mode.stats && redSideMode != Mode.stats && + theGreenSide[2].gamesPlayed > 9 && theRedSide[2].gamesPlayed > 9) + CompareThingy( + label: t.byGlicko, + greenSide: getWinrateByTR( + theGreenSide[2].glicko!, + theGreenSide[2].rd!, + theRedSide[2].glicko!, + theRedSide[2].rd!) * + 100, + redSide: getWinrateByTR( + theRedSide[2].glicko!, + theRedSide[2].rd!, + theGreenSide[2].glicko!, + theGreenSide[2].rd!) * + 100, + fractionDigits: 2, + higherIsBetter: true, + ), + CompareThingy( + label: t.byEstTR, + greenSide: getWinrateByTR( + theGreenSide[2].estTr!.estglicko, + theGreenSide[2].rd ?? noTrRd, + theRedSide[2].estTr!.estglicko, + theRedSide[2].rd ?? noTrRd) * + 100, + redSide: getWinrateByTR( + theRedSide[2].estTr!.estglicko, + theRedSide[2].rd ?? noTrRd, + theGreenSide[2].estTr!.estglicko, + theGreenSide[2].rd ?? noTrRd) * + 100, + fractionDigits: 2, + higherIsBetter: true, + ), ], ) ] : [Padding( diff --git a/lib/views/main_view.dart b/lib/views/main_view.dart index e2c15bd..dd0ea00 100644 --- a/lib/views/main_view.dart +++ b/lib/views/main_view.dart @@ -11,6 +11,7 @@ import 'package:flutter/services.dart'; import 'package:tetra_stats/data_objects/tetrio.dart'; import 'package:tetra_stats/gen/strings.g.dart'; import 'package:tetra_stats/services/tetrio_crud.dart'; +import 'package:tetra_stats/main.dart' show prefs; import 'package:tetra_stats/services/crud_exceptions.dart'; import 'package:tetra_stats/views/ranks_averages_view.dart' show RankAveragesView; import 'package:tetra_stats/views/tl_leaderboard_view.dart' show TLLeaderboardView; @@ -25,15 +26,14 @@ Future me = Future.delayed(const Duration(seconds: 60), () => [null, null, String _searchFor = "6098518e3d5155e6ec429cdc"; String _titleNickname = "dan63047"; final TetrioService teto = TetrioService(); -late SharedPreferences prefs; var chartsData = >>[]; -List historyShortTitles = ["TR", "Glicko", "RD", "APM", "PPS", "VS", "APP", "DS/S", "DS/P", "APP + DS/P", "VS/APM", "Cheese", "GbE", "wAPP", "Area", "eTR", "±eTR"]; -int chartsIndex = 0; -final NumberFormat timeInSec = NumberFormat("#,###.###s."); -final NumberFormat f2 = NumberFormat.decimalPatternDigits(locale: LocaleSettings.currentLocale.languageCode, decimalDigits: 2); -final NumberFormat secs = NumberFormat("00.###"); -final NumberFormat f4 = NumberFormat.decimalPatternDigits(locale: LocaleSettings.currentLocale.languageCode, decimalDigits: 4); -final DateFormat dateFormat = DateFormat.yMMMd(LocaleSettings.currentLocale.languageCode).add_Hms(); +List _historyShortTitles = ["TR", "Glicko", "RD", "APM", "PPS", "VS", "APP", "DS/S", "DS/P", "APP + DS/P", "VS/APM", "Cheese", "GbE", "wAPP", "Area", "eTR", "±eTR"]; +int _chartsIndex = 0; +final NumberFormat _timeInSec = NumberFormat("#,###.###s."); +final NumberFormat _secs = NumberFormat("00.###"); +final NumberFormat _f2 = NumberFormat.decimalPatternDigits(locale: LocaleSettings.currentLocale.languageCode, decimalDigits: 2); +final NumberFormat _f4 = NumberFormat.decimalPatternDigits(locale: LocaleSettings.currentLocale.languageCode, decimalDigits: 4); +final DateFormat _dateFormat = DateFormat.yMMMd(LocaleSettings.currentLocale.languageCode).add_Hms(); class MainView extends StatefulWidget { final String? player; @@ -51,9 +51,9 @@ Future copyToClipboard(String text) async { String get40lTime(int microseconds){ if (microseconds > 60000000) { - return "${(microseconds/1000000/60).floor()}:${(secs.format(microseconds /1000000 % 60))}"; + return "${(microseconds/1000000/60).floor()}:${(_secs.format(microseconds /1000000 % 60))}"; } else{ - return timeInSec.format(microseconds / 1000000); + return _timeInSec.format(microseconds / 1000000); } } @@ -543,7 +543,7 @@ class _TLRecords extends StatelessWidget { style: bigScreen ? const TextStyle(fontFamily: "Eurostile Round Extended", fontSize: 28) : const TextStyle(fontSize: 28)), title: Text("vs. ${value.endContext.firstWhere((element) => element.userId != userID).username}"), - subtitle: Text(dateFormat.format(value.timestamp)), + subtitle: Text(_dateFormat.format(value.timestamp)), trailing: Table(defaultColumnWidth: const IntrinsicColumnWidth(), defaultVerticalAlignment: TableCellVerticalAlignment.baseline, textBaseline: TextBaseline.alphabetic, @@ -552,9 +552,9 @@ class _TLRecords extends StatelessWidget { 2: FixedColumnWidth(50), }, children: [ - TableRow(children: [Text(f2.format(value.endContext.firstWhere((element) => element.userId == userID).secondary), textAlign: TextAlign.right, style: const TextStyle(height: 1.1)), const Text(" :", style: TextStyle(height: 1.1)), Text(f2.format(value.endContext.firstWhere((element) => element.userId != userID).secondary), textAlign: TextAlign.right, style: const TextStyle(height: 1.1)), const Text(" APM", textAlign: TextAlign.right, style: TextStyle(height: 1.1))]), - TableRow(children: [Text(f2.format(value.endContext.firstWhere((element) => element.userId == userID).tertiary), textAlign: TextAlign.right, style: const TextStyle(height: 1.1)), const Text(" :", style: TextStyle(height: 1.1)), Text(f2.format(value.endContext.firstWhere((element) => element.userId != userID).tertiary), textAlign: TextAlign.right, style: const TextStyle(height: 1.1)), const Text(" PPS", textAlign: TextAlign.right, style: TextStyle(height: 1.1))]), - TableRow(children: [Text(f2.format(value.endContext.firstWhere((element) => element.userId == userID).extra), textAlign: TextAlign.right, style: const TextStyle(height: 1.1)), const Text(" :", style: TextStyle(height: 1.1)), Text(f2.format(value.endContext.firstWhere((element) => element.userId != userID).extra), textAlign: TextAlign.right, style: const TextStyle(height: 1.1)), const Text(" VS", textAlign: TextAlign.right, style: TextStyle(height: 1.1))]), + TableRow(children: [Text(_f2.format(value.endContext.firstWhere((element) => element.userId == userID).secondary), textAlign: TextAlign.right, style: const TextStyle(height: 1.1)), const Text(" :", style: TextStyle(height: 1.1)), Text(_f2.format(value.endContext.firstWhere((element) => element.userId != userID).secondary), textAlign: TextAlign.right, style: const TextStyle(height: 1.1)), const Text(" APM", textAlign: TextAlign.right, style: TextStyle(height: 1.1))]), + TableRow(children: [Text(_f2.format(value.endContext.firstWhere((element) => element.userId == userID).tertiary), textAlign: TextAlign.right, style: const TextStyle(height: 1.1)), const Text(" :", style: TextStyle(height: 1.1)), Text(_f2.format(value.endContext.firstWhere((element) => element.userId != userID).tertiary), textAlign: TextAlign.right, style: const TextStyle(height: 1.1)), const Text(" PPS", textAlign: TextAlign.right, style: TextStyle(height: 1.1))]), + TableRow(children: [Text(_f2.format(value.endContext.firstWhere((element) => element.userId == userID).extra), textAlign: TextAlign.right, style: const TextStyle(height: 1.1)), const Text(" :", style: TextStyle(height: 1.1)), Text(_f2.format(value.endContext.firstWhere((element) => element.userId != userID).extra), textAlign: TextAlign.right, style: const TextStyle(height: 1.1)), const Text(" VS", textAlign: TextAlign.right, style: TextStyle(height: 1.1))]), ],), onTap: (){Navigator.push( context, @@ -582,13 +582,13 @@ class _History extends StatelessWidget{ children: [ DropdownButton( items: chartsData, - value: chartsData[chartsIndex].value, + value: chartsData[_chartsIndex].value, onChanged: (value) { - chartsIndex = chartsData.indexWhere((element) => element.value == value); + _chartsIndex = chartsData.indexWhere((element) => element.value == value); update(); } ), - if(chartsData[chartsIndex].value!.length > 1) _HistoryChartThigy(data: chartsData[chartsIndex].value!, title: "ss", yAxisTitle: historyShortTitles[chartsIndex], bigScreen: bigScreen, leftSpace: bigScreen? 80 : 45, yFormat: bigScreen? f2 : NumberFormat.compact(),) + if(chartsData[_chartsIndex].value!.length > 1) _HistoryChartThigy(data: chartsData[_chartsIndex].value!, title: "ss", yAxisTitle: _historyShortTitles[_chartsIndex], bigScreen: bigScreen, leftSpace: bigScreen? 80 : 45, yFormat: bigScreen? _f2 : NumberFormat.compact(),) else Center(child: Text(t.notEnoughData, style: const TextStyle(fontFamily: "Eurostile Round Extended", fontSize: 28))) ], ), @@ -634,7 +634,7 @@ class _HistoryChartThigy extends StatelessWidget{ ) : Container(); }))), lineTouchData: LineTouchData(touchTooltipData: LineTouchTooltipData( fitInsideHorizontally: true, fitInsideVertically: true, getTooltipItems: (touchedSpots) { - return [for (var v in touchedSpots) LineTooltipItem("${f4.format(v.y)} $yAxisTitle \n", const TextStyle(), children: [TextSpan(text: dateFormat.format(DateTime.fromMillisecondsSinceEpoch(v.x.floor())))])]; + return [for (var v in touchedSpots) LineTooltipItem("${_f4.format(v.y)} $yAxisTitle \n", const TextStyle(), children: [TextSpan(text: _dateFormat.format(DateTime.fromMillisecondsSinceEpoch(v.x.floor())))])]; },)) ) ), @@ -688,7 +688,7 @@ class _RecordThingy extends StatelessWidget { playerStatLabel: "Leaderboard Placement", isScreenBig: bigScreen, higherIsBetter: false), - Text(t.obtainDate(date: dateFormat.format(record!.timestamp!)), + Text(t.obtainDate(date: _dateFormat.format(record!.timestamp!)), textAlign: TextAlign.center, style: const TextStyle( fontFamily: "Eurostile Round", @@ -940,7 +940,7 @@ class _OtherThingy extends StatelessWidget { ] ) ), - subtitle: Text(dateFormat.format(news.timestamp)), + subtitle: Text(_dateFormat.format(news.timestamp)), ); case "personalbest": return ListTile( @@ -955,7 +955,7 @@ class _OtherThingy extends StatelessWidget { ] ) ), - subtitle: Text(dateFormat.format(news.timestamp)), + subtitle: Text(_dateFormat.format(news.timestamp)), leading: Image.asset( "res/icons/improvement-local.png", height: 48, @@ -977,7 +977,7 @@ class _OtherThingy extends StatelessWidget { ] ) ), - subtitle: Text(dateFormat.format(news.timestamp)), + subtitle: Text(_dateFormat.format(news.timestamp)), leading: Image.asset( "res/tetrio_badges/${news.data["type"]}.png", height: 48, @@ -999,7 +999,7 @@ class _OtherThingy extends StatelessWidget { ] ) ), - subtitle: Text(dateFormat.format(news.timestamp)), + subtitle: Text(_dateFormat.format(news.timestamp)), leading: Image.asset( "res/tetrio_tl_alpha_ranks/${news.data["rank"]}.png", height: 48, @@ -1020,7 +1020,7 @@ class _OtherThingy extends StatelessWidget { ] ) ), - subtitle: Text(dateFormat.format(news.timestamp)), + subtitle: Text(_dateFormat.format(news.timestamp)), leading: Image.asset( "res/icons/supporter-tag.png", height: 48, @@ -1041,7 +1041,7 @@ class _OtherThingy extends StatelessWidget { ] ) ), - subtitle: Text(dateFormat.format(news.timestamp)), + subtitle: Text(_dateFormat.format(news.timestamp)), leading: Image.asset( "res/icons/supporter-tag.png", height: 48, @@ -1054,7 +1054,7 @@ class _OtherThingy extends StatelessWidget { default: return ListTile( title: Text(t.newsParts.unknownNews(type: news.type)), - subtitle: Text(dateFormat.format(news.timestamp)), + subtitle: Text(_dateFormat.format(news.timestamp)), ); } } diff --git a/lib/views/rank_averages_view.dart b/lib/views/rank_averages_view.dart index 2d83e1c..ffafe15 100644 --- a/lib/views/rank_averages_view.dart +++ b/lib/views/rank_averages_view.dart @@ -5,18 +5,20 @@ import 'package:flutter/material.dart'; import 'package:intl/intl.dart'; import 'package:tetra_stats/data_objects/tetrio.dart'; import 'package:tetra_stats/gen/strings.g.dart'; -import 'package:tetra_stats/views/main_view.dart' show MainView, f4, f2; +import 'package:tetra_stats/views/main_view.dart' show MainView; import 'package:window_manager/window_manager.dart'; -var chartsShortTitlesDropdowns = [for (MapEntry e in chartsShortTitles.entries) DropdownMenuItem(value: e.key, child: Text(e.value),)]; -Stats chartsX = Stats.tr; -Stats chartsY = Stats.apm; -List itemStats = [for (MapEntry e in chartsShortTitles.entries) DropdownMenuItem(value: e.key, child: Text(e.value))]; -Stats sortBy = Stats.tr; -bool reversed = false; -List itemCountries = [for (MapEntry e in t.countries.entries) DropdownMenuItem(value: e.key, child: Text(e.value))]; -String country = ""; -late String oldWindowTitle; +var _chartsShortTitlesDropdowns = [for (MapEntry e in chartsShortTitles.entries) DropdownMenuItem(value: e.key, child: Text(e.value),)]; +Stats _chartsX = Stats.tr; +Stats _chartsY = Stats.apm; +List _itemStats = [for (MapEntry e in chartsShortTitles.entries) DropdownMenuItem(value: e.key, child: Text(e.value))]; +Stats _sortBy = Stats.tr; +bool _reversed = false; +List _itemCountries = [for (MapEntry e in t.countries.entries) DropdownMenuItem(value: e.key, child: Text(e.value))]; +String _country = ""; +late String _oldWindowTitle; +final NumberFormat _f2 = NumberFormat.decimalPatternDigits(locale: LocaleSettings.currentLocale.languageCode, decimalDigits: 2); +final NumberFormat _f4 = NumberFormat.decimalPatternDigits(locale: LocaleSettings.currentLocale.languageCode, decimalDigits: 4); class RankView extends StatefulWidget { final List rank; @@ -35,7 +37,7 @@ class RankState extends State with SingleTickerProviderStateMixin { _scrollController = ScrollController(); _tabController = TabController(length: 6, vsync: this); if (!kIsWeb && !Platform.isAndroid && !Platform.isIOS){ - windowManager.getTitle().then((value) => oldWindowTitle = value); + windowManager.getTitle().then((value) => _oldWindowTitle = value); windowManager.setTitle("Tetra Stats: ${widget.rank[1]["everyone"] ? t.everyoneAverages : t.rankAverages(rank: widget.rank[0].rank.toUpperCase())}"); } super.initState(); @@ -45,7 +47,7 @@ class RankState extends State with SingleTickerProviderStateMixin { void dispose() { _tabController.dispose(); _scrollController.dispose(); - if (!kIsWeb && !Platform.isAndroid && !Platform.isIOS) windowManager.setTitle(oldWindowTitle); + if (!kIsWeb && !Platform.isAndroid && !Platform.isIOS) windowManager.setTitle(_oldWindowTitle); super.dispose(); } @@ -57,7 +59,7 @@ class RankState extends State with SingleTickerProviderStateMixin { Widget build(BuildContext context) { final t = Translations.of(context); bool bigScreen = MediaQuery.of(context).size.width > 768; - List they = TetrioPlayersLeaderboard("lol", []).getStatRanking(widget.rank[1]["entries"]!, sortBy, reversed: reversed, country: country); + List they = TetrioPlayersLeaderboard("lol", []).getStatRanking(widget.rank[1]["entries"]!, _sortBy, reversed: _reversed, country: _country); return Scaffold( appBar: AppBar( title: Text(widget.rank[1]["everyone"] ? t.everyoneAverages : t.rankAverages(rank: widget.rank[0].rank.toUpperCase())), @@ -135,10 +137,10 @@ class RankState extends State with SingleTickerProviderStateMixin { style: const TextStyle(fontSize: 22))), DropdownButton( - items: chartsShortTitlesDropdowns, - value: chartsX, + items: _chartsShortTitlesDropdowns, + value: _chartsX, onChanged: (value) { - chartsX = value; + _chartsX = value; _justUpdate(); }), ], @@ -156,10 +158,10 @@ class RankState extends State with SingleTickerProviderStateMixin { style: const TextStyle(fontSize: 22)), ), DropdownButton( - items: chartsShortTitlesDropdowns, - value: chartsY, + items: _chartsShortTitlesDropdowns, + value: _chartsY, onChanged: (value) { - chartsY = value; + _chartsY = value; _justUpdate(); }), ], @@ -186,9 +188,9 @@ class RankState extends State with SingleTickerProviderStateMixin { for (TetrioPlayerFromLeaderboard entry in widget.rank[1]["entries"]) _MyScatterSpot( - entry.getStatByEnum(chartsX) + entry.getStatByEnum(_chartsX) as double, - entry.getStatByEnum(chartsY) + entry.getStatByEnum(_chartsY) as double, entry.userId, entry.username, @@ -211,7 +213,7 @@ class RankState extends State with SingleTickerProviderStateMixin { children: [ TextSpan( text: - "${f4.format(touchedSpot.x)} ${chartsShortTitles[chartsX]}\n${f4.format(touchedSpot.y)} ${chartsShortTitles[chartsY]}", + "${_f4.format(touchedSpot.x)} ${chartsShortTitles[_chartsX]}\n${_f4.format(touchedSpot.y)} ${chartsShortTitles[_chartsY]}", style: const TextStyle( fontFamily: "Eurostile Round")) @@ -266,10 +268,10 @@ class RankState extends State with SingleTickerProviderStateMixin { children: [ Text("${t.sortBy}: ", style: const TextStyle(color: Colors.white, fontSize: 25)), DropdownButton( - items: itemStats, - value: sortBy, + items: _itemStats, + value: _sortBy, onChanged: ((value) { - sortBy = value; + _sortBy = value; setState(() {}); }), ), @@ -283,10 +285,10 @@ class RankState extends State with SingleTickerProviderStateMixin { Text("${t.reversed}: ", style: const TextStyle(color: Colors.white, fontSize: 25)), Padding(padding: const EdgeInsets.fromLTRB(0, 5.5, 0, 7.5), child: Checkbox( - value: reversed, + value: _reversed, checkColor: Colors.black, onChanged: ((value) { - reversed = value!; + _reversed = value!; setState(() {}); }), ), @@ -300,10 +302,10 @@ class RankState extends State with SingleTickerProviderStateMixin { children: [ Text("${t.country}: ", style: const TextStyle(color: Colors.white, fontSize: 25)), DropdownButton( - items: itemCountries, - value: country, + items: _itemCountries, + value: _country, onChanged: ((value) { - country = value; + _country = value; setState(() {}); }), ), @@ -319,11 +321,11 @@ class RankState extends State with SingleTickerProviderStateMixin { bool bigScreen = MediaQuery.of(context).size.width > 768; return ListTile( title: Text(they[index].username, style: const TextStyle(fontFamily: "Eurostile Round Extended")), - subtitle: Text(sortBy == Stats.tr ? "${f2.format(they[index].apm)} APM, ${f2.format(they[index].pps)} PPS, ${f2.format(they[index].vs)} VS, ${f2.format(they[index].nerdStats.app)} APP, ${f2.format(they[index].nerdStats.vsapm)} VS/APM" : "${f4.format(they[index].getStatByEnum(sortBy))} ${chartsShortTitles[sortBy]}"), + subtitle: Text(_sortBy == Stats.tr ? "${_f2.format(they[index].apm)} APM, ${_f2.format(they[index].pps)} PPS, ${_f2.format(they[index].vs)} VS, ${_f2.format(they[index].nerdStats.app)} APP, ${_f2.format(they[index].nerdStats.vsapm)} VS/APM" : "${_f4.format(they[index].getStatByEnum(_sortBy))} ${chartsShortTitles[_sortBy]}"), trailing: Row( mainAxisSize: MainAxisSize.min, children: [ - Text("${f2.format(they[index].rating)} TR", style: bigScreen ? const TextStyle(fontSize: 28) : null), + Text("${_f2.format(they[index].rating)} TR", style: bigScreen ? const TextStyle(fontSize: 28) : null), Image.asset("res/tetrio_tl_alpha_ranks/${they[index].rank}.png", height: bigScreen ? 48 : 16), ], ), diff --git a/lib/views/ranks_averages_view.dart b/lib/views/ranks_averages_view.dart index 517880c..6be8fbe 100644 --- a/lib/views/ranks_averages_view.dart +++ b/lib/views/ranks_averages_view.dart @@ -4,8 +4,8 @@ import 'package:flutter/material.dart'; import 'package:intl/intl.dart'; import 'package:tetra_stats/gen/strings.g.dart'; import 'package:tetra_stats/views/rank_averages_view.dart'; -import 'package:tetra_stats/views/tl_leaderboard_view.dart'; import 'package:window_manager/window_manager.dart'; +import 'main_view.dart'; // lol class RankAveragesView extends StatefulWidget { const RankAveragesView({Key? key}) : super(key: key); diff --git a/lib/views/tl_leaderboard_view.dart b/lib/views/tl_leaderboard_view.dart index c64bc9a..dd34a02 100644 --- a/lib/views/tl_leaderboard_view.dart +++ b/lib/views/tl_leaderboard_view.dart @@ -10,13 +10,14 @@ import 'package:tetra_stats/views/rank_averages_view.dart'; import 'package:tetra_stats/views/ranks_averages_view.dart'; import 'package:window_manager/window_manager.dart'; -final TetrioService teto = TetrioService(); -List itemStats = [for (MapEntry e in chartsShortTitles.entries) DropdownMenuItem(value: e.key, child: Text(e.value))]; -Stats sortBy = Stats.tr; +final TetrioService _teto = TetrioService(); +List _itemStats = [for (MapEntry e in chartsShortTitles.entries) DropdownMenuItem(value: e.key, child: Text(e.value))]; +Stats _sortBy = Stats.tr; bool reversed = false; -List itemCountries = [for (MapEntry e in t.countries.entries) DropdownMenuItem(value: e.key, child: Text(e.value))]; -String country = ""; -late String oldWindowTitle; +List _itemCountries = [for (MapEntry e in t.countries.entries) DropdownMenuItem(value: e.key, child: Text(e.value))]; +String _country = ""; +late String _oldWindowTitle; +final NumberFormat _f4 = NumberFormat.decimalPatternDigits(locale: LocaleSettings.currentLocale.languageCode, decimalDigits: 4); class TLLeaderboardView extends StatefulWidget { const TLLeaderboardView({Key? key}) : super(key: key); @@ -28,20 +29,20 @@ class TLLeaderboardView extends StatefulWidget { class TLLeaderboardState extends State { @override void initState() { - if (!kIsWeb && !Platform.isAndroid && !Platform.isIOS) windowManager.getTitle().then((value) => oldWindowTitle = value); + if (!kIsWeb && !Platform.isAndroid && !Platform.isIOS) windowManager.getTitle().then((value) => _oldWindowTitle = value); super.initState(); } @override void dispose() { - if (!kIsWeb && !Platform.isAndroid && !Platform.isIOS) windowManager.setTitle(oldWindowTitle); + if (!kIsWeb && !Platform.isAndroid && !Platform.isIOS) windowManager.setTitle(_oldWindowTitle); super.dispose(); } @override Widget build(BuildContext context) { final t = Translations.of(context); - final NumberFormat f2 = NumberFormat.decimalPattern(LocaleSettings.currentLocale.languageCode)..maximumFractionDigits = 2; + final NumberFormat _f2 = NumberFormat.decimalPattern(LocaleSettings.currentLocale.languageCode)..maximumFractionDigits = 2; return Scaffold( appBar: AppBar( title: Text(t.tlLeaderboard), @@ -64,7 +65,7 @@ class TLLeaderboardState extends State { backgroundColor: Colors.black, body: SafeArea( child: FutureBuilder( - future: teto.fetchTLLeaderboard(), + future: _teto.fetchTLLeaderboard(), builder: (context, snapshot) { switch (snapshot.connectionState) { case ConnectionState.none: @@ -72,7 +73,7 @@ class TLLeaderboardState extends State { case ConnectionState.active: return const Center(child: Text('Fetching...')); case ConnectionState.done: - final allPlayers = snapshot.data?.getStatRanking(snapshot.data!.leaderboard, sortBy, reversed: reversed, country: country); + final allPlayers = snapshot.data?.getStatRanking(snapshot.data!.leaderboard, _sortBy, reversed: reversed, country: _country); if (!kIsWeb && !Platform.isAndroid && !Platform.isIOS) windowManager.setTitle("Tetra Stats: ${t.tlLeaderboard} - ${t.players(n: allPlayers!.length)}"); return NestedScrollView( headerSliverBuilder: (context, value) { @@ -124,8 +125,8 @@ class TLLeaderboardState extends State { children: [ Text("${t.sortBy}: ", style: const TextStyle(color: Colors.white, fontSize: 25)), - DropdownButton(items: itemStats, value: sortBy, onChanged: ((value) { - sortBy = value; + DropdownButton(items: _itemStats, value: _sortBy, onChanged: ((value) { + _sortBy = value; setState(() {}); }),), ], @@ -155,8 +156,8 @@ class TLLeaderboardState extends State { children: [ Text("${t.country}: ", style: const TextStyle(color: Colors.white, fontSize: 25)), - DropdownButton(items: itemCountries, value: country, onChanged: ((value) { - country = value; + DropdownButton(items: _itemCountries, value: _country, onChanged: ((value) { + _country = value; setState(() {}); }),), ], @@ -174,11 +175,11 @@ class TLLeaderboardState extends State { return ListTile( leading: Text((index+1).toString(), style: bigScreen ? const TextStyle(fontFamily: "Eurostile Round Extended", fontSize: 28) : null), title: Text(allPlayers[index].username, style: const TextStyle(fontFamily: "Eurostile Round Extended")), - subtitle: Text(sortBy == Stats.tr ? "${f2.format(allPlayers[index].apm)} APM, ${f2.format(allPlayers[index].pps)} PPS, ${f2.format(allPlayers[index].vs)} VS, ${f2.format(allPlayers[index].nerdStats.app)} APP, ${f2.format(allPlayers[index].nerdStats.vsapm)} VS/APM" : "${f4.format(allPlayers[index].getStatByEnum(sortBy))} ${chartsShortTitles[sortBy]}"), + subtitle: Text(_sortBy == Stats.tr ? "${_f2.format(allPlayers[index].apm)} APM, ${_f2.format(allPlayers[index].pps)} PPS, ${_f2.format(allPlayers[index].vs)} VS, ${_f2.format(allPlayers[index].nerdStats.app)} APP, ${_f2.format(allPlayers[index].nerdStats.vsapm)} VS/APM" : "${_f4.format(allPlayers[index].getStatByEnum(_sortBy))} ${chartsShortTitles[_sortBy]}"), trailing: Row( mainAxisSize: MainAxisSize.min, children: [ - Text("${f2.format(allPlayers[index].rating)} TR", style: bigScreen ? const TextStyle(fontSize: 28) : null), + Text("${_f2.format(allPlayers[index].rating)} TR", style: bigScreen ? const TextStyle(fontSize: 28) : null), Image.asset("res/tetrio_tl_alpha_ranks/${allPlayers[index].rank}.png", height: bigScreen ? 48 : 16), ], ), diff --git a/lib/views/tl_match_view.dart b/lib/views/tl_match_view.dart index ab759ec..e4b9514 100644 --- a/lib/views/tl_match_view.dart +++ b/lib/views/tl_match_view.dart @@ -2,6 +2,7 @@ import 'dart:io'; import 'package:tetra_stats/services/crud_exceptions.dart'; +import 'package:tetra_stats/widgets/vs_graphs.dart'; import 'main_view.dart' show teto; import 'package:fl_chart/fl_chart.dart'; @@ -329,191 +330,17 @@ class TlMatchResultState extends State { fractionDigits: 3, higherIsBetter: true, ), - Wrap( - direction: Axis.horizontal, - alignment: WrapAlignment.center, - spacing: 25, - crossAxisAlignment: WrapCrossAlignment.start, - clipBehavior: Clip.hardEdge, - children: [Padding( - padding: const EdgeInsets.fromLTRB(20, 20, 20, 20), - child: SizedBox( - height: 310, - width: 310, - child: RadarChart( - RadarChartData( - radarShape: RadarShape.polygon, - tickCount: 4, - ticksTextStyle: const TextStyle(color: Colors.transparent, fontSize: 10), - radarBorderData: const BorderSide(color: Colors.transparent, width: 1), - gridBorderData: const BorderSide(color: Colors.white24, width: 1), - tickBorderData: const BorderSide(color: Colors.transparent, width: 1), - getTitle: (index, angle) { - switch (index) { - case 0: - return RadarChartTitle(text: 'APM', angle: angle, positionPercentageOffset: 0.05); - case 1: - return RadarChartTitle(text: 'PPS', angle: angle, positionPercentageOffset: 0.05); - case 2: - return RadarChartTitle(text: 'VS', angle: angle, positionPercentageOffset: 0.05); - case 3: - return RadarChartTitle(text: 'APP', angle: angle + 180, positionPercentageOffset: 0.05); - case 4: - return RadarChartTitle(text: 'DS/S', angle: angle + 180, positionPercentageOffset: 0.05); - case 5: - return RadarChartTitle(text: 'DS/P', angle: angle + 180, positionPercentageOffset: 0.05); - case 6: - return RadarChartTitle(text: 'APP+DS/P', angle: angle + 180, positionPercentageOffset: 0.05); - case 7: - return RadarChartTitle(text: 'VS/APM', angle: angle + 180, positionPercentageOffset: 0.05); - case 8: - return RadarChartTitle(text: 'Cheese', angle: angle, positionPercentageOffset: 0.05); - case 9: - return RadarChartTitle(text: 'Gb Eff.', angle: angle, positionPercentageOffset: 0.05); - default: - return const RadarChartTitle(text: ''); - } - }, - dataSets: [ - RadarDataSet( - fillColor: const Color.fromARGB( - 115, 76, 175, 79), - borderColor: Colors.green, - dataEntries: [ - RadarEntry(value: roundSelector.isNegative ? widget.record.endContext.firstWhere((element) => element.userId == widget.initPlayerId).secondary * apmWeight : widget.record.endContext.firstWhere((element) => element.userId == widget.initPlayerId).secondaryTracking[roundSelector] * apmWeight), - RadarEntry(value: roundSelector.isNegative ? widget.record.endContext.firstWhere((element) => element.userId == widget.initPlayerId).tertiary * ppsWeight : widget.record.endContext.firstWhere((element) => element.userId == widget.initPlayerId).tertiaryTracking[roundSelector] * ppsWeight), - RadarEntry(value: roundSelector.isNegative ? widget.record.endContext.firstWhere((element) => element.userId == widget.initPlayerId).extra * vsWeight : widget.record.endContext.firstWhere((element) => element.userId == widget.initPlayerId).extraTracking[roundSelector] * vsWeight), - RadarEntry(value: roundSelector.isNegative ? widget.record.endContext.firstWhere((element) => element.userId == widget.initPlayerId).nerdStats.app * appWeight : widget.record.endContext.firstWhere((element) => element.userId == widget.initPlayerId).nerdStatsTracking[roundSelector].app * appWeight), - RadarEntry(value: roundSelector.isNegative ? widget.record.endContext.firstWhere((element) => element.userId == widget.initPlayerId).nerdStats.dss * dssWeight : widget.record.endContext.firstWhere((element) => element.userId == widget.initPlayerId).nerdStatsTracking[roundSelector].dss * dssWeight), - RadarEntry(value: roundSelector.isNegative ? widget.record.endContext.firstWhere((element) => element.userId == widget.initPlayerId).nerdStats.dsp * dspWeight : widget.record.endContext.firstWhere((element) => element.userId == widget.initPlayerId).nerdStatsTracking[roundSelector].dsp * dspWeight), - RadarEntry(value: roundSelector.isNegative ? widget.record.endContext.firstWhere((element) => element.userId == widget.initPlayerId).nerdStats.appdsp * appdspWeight : widget.record.endContext.firstWhere((element) => element.userId == widget.initPlayerId).nerdStatsTracking[roundSelector].appdsp * appdspWeight), - RadarEntry(value: roundSelector.isNegative ? widget.record.endContext.firstWhere((element) => element.userId == widget.initPlayerId).nerdStats.vsapm * vsapmWeight : widget.record.endContext.firstWhere((element) => element.userId == widget.initPlayerId).nerdStatsTracking[roundSelector].vsapm * vsapmWeight), - RadarEntry(value: roundSelector.isNegative ? widget.record.endContext.firstWhere((element) => element.userId == widget.initPlayerId).nerdStats.cheese * cheeseWeight : widget.record.endContext.firstWhere((element) => element.userId == widget.initPlayerId).nerdStatsTracking[roundSelector].cheese * cheeseWeight), - RadarEntry(value: roundSelector.isNegative ? widget.record.endContext.firstWhere((element) => element.userId == widget.initPlayerId).nerdStats.gbe * gbeWeight : widget.record.endContext.firstWhere((element) => element.userId == widget.initPlayerId).nerdStatsTracking[roundSelector].gbe), - ], - ), - RadarDataSet( - fillColor: const Color.fromARGB( - 115, 244, 67, 54), - borderColor: Colors.red, - dataEntries: [ - RadarEntry(value: roundSelector.isNegative ? widget.record.endContext.firstWhere((element) => element.userId != widget.initPlayerId).secondary * apmWeight : widget.record.endContext.firstWhere((element) => element.userId != widget.initPlayerId).secondaryTracking[roundSelector] * apmWeight), - RadarEntry(value: roundSelector.isNegative ? widget.record.endContext.firstWhere((element) => element.userId != widget.initPlayerId).tertiary * ppsWeight : widget.record.endContext.firstWhere((element) => element.userId != widget.initPlayerId).tertiaryTracking[roundSelector] * ppsWeight), - RadarEntry(value: roundSelector.isNegative ? widget.record.endContext.firstWhere((element) => element.userId != widget.initPlayerId).extra * vsWeight : widget.record.endContext.firstWhere((element) => element.userId != widget.initPlayerId).extraTracking[roundSelector] * vsWeight), - RadarEntry(value: roundSelector.isNegative ? widget.record.endContext.firstWhere((element) => element.userId != widget.initPlayerId).nerdStats.app * appWeight : widget.record.endContext.firstWhere((element) => element.userId != widget.initPlayerId).nerdStatsTracking[roundSelector].app * appWeight), - RadarEntry(value: roundSelector.isNegative ? widget.record.endContext.firstWhere((element) => element.userId != widget.initPlayerId).nerdStats.dss * dssWeight : widget.record.endContext.firstWhere((element) => element.userId != widget.initPlayerId).nerdStatsTracking[roundSelector].dss * dssWeight), - RadarEntry(value: roundSelector.isNegative ? widget.record.endContext.firstWhere((element) => element.userId != widget.initPlayerId).nerdStats.dsp * dspWeight : widget.record.endContext.firstWhere((element) => element.userId != widget.initPlayerId).nerdStatsTracking[roundSelector].dsp * dspWeight), - RadarEntry(value: roundSelector.isNegative ? widget.record.endContext.firstWhere((element) => element.userId != widget.initPlayerId).nerdStats.appdsp * appdspWeight : widget.record.endContext.firstWhere((element) => element.userId != widget.initPlayerId).nerdStatsTracking[roundSelector].appdsp * appdspWeight), - RadarEntry(value: roundSelector.isNegative ? widget.record.endContext.firstWhere((element) => element.userId != widget.initPlayerId).nerdStats.vsapm * vsapmWeight : widget.record.endContext.firstWhere((element) => element.userId != widget.initPlayerId).nerdStatsTracking[roundSelector].vsapm * vsapmWeight), - RadarEntry(value: roundSelector.isNegative ? widget.record.endContext.firstWhere((element) => element.userId != widget.initPlayerId).nerdStats.cheese * cheeseWeight : widget.record.endContext.firstWhere((element) => element.userId != widget.initPlayerId).nerdStatsTracking[roundSelector].cheese * cheeseWeight), - RadarEntry(value: roundSelector.isNegative ? widget.record.endContext.firstWhere((element) => element.userId != widget.initPlayerId).nerdStats.gbe * gbeWeight : widget.record.endContext.firstWhere((element) => element.userId != widget.initPlayerId).nerdStatsTracking[roundSelector].gbe * gbeWeight), - ], - ), - RadarDataSet( - fillColor: Colors.transparent, - borderColor: Colors.transparent, - dataEntries: [ - const RadarEntry(value: 0), - const RadarEntry(value: 0), - const RadarEntry(value: 0), - const RadarEntry(value: 0), - const RadarEntry(value: 0), - const RadarEntry(value: 0), - const RadarEntry(value: 0), - const RadarEntry(value: 0), - const RadarEntry(value: 0), - const RadarEntry(value: 0), - ], - ) - ], - ), - swapAnimationDuration: const Duration( - milliseconds: 150), // Optional - swapAnimationCurve: - Curves.linear, // Optional - ), - ), - ), - Padding( - padding: const EdgeInsets.fromLTRB(20, 20, 20, 20), - child: SizedBox( - height: 310, - width: 310, - child: RadarChart(RadarChartData( - radarShape: RadarShape.polygon, - tickCount: 4, - ticksTextStyle: const TextStyle(color: Colors.white24, fontSize: 10), - radarBorderData: const BorderSide(color: Colors.transparent, width: 1), - gridBorderData: const BorderSide(color: Colors.white24, width: 1), - tickBorderData: const BorderSide(color: Colors.transparent, width: 1), - titleTextStyle: const TextStyle(height: 1.1), - getTitle: (index, angle) { - switch (index) { - case 0: - return RadarChartTitle(text: 'Opener', angle: angle, positionPercentageOffset: 0.05); - case 1: - return RadarChartTitle(text: 'Stride', angle: angle, positionPercentageOffset: 0.05); - case 2: - return RadarChartTitle(text: 'Inf Ds', angle: angle + 180, positionPercentageOffset: 0.05); - case 3: - return RadarChartTitle(text: 'Plonk', angle: angle, positionPercentageOffset: 0.05); - default: - return const RadarChartTitle(text: ''); - } - }, - dataSets: [ - RadarDataSet( - fillColor: const Color.fromARGB( - 115, 76, 175, 79), - borderColor: Colors.green, - dataEntries: [ - RadarEntry(value: roundSelector.isNegative ? widget.record.endContext.firstWhere((element) => element.userId == widget.initPlayerId).playstyle.opener : widget.record.endContext.firstWhere((element) => element.userId == widget.initPlayerId).playstyleTracking[roundSelector].opener), - RadarEntry(value: roundSelector.isNegative ? widget.record.endContext.firstWhere((element) => element.userId == widget.initPlayerId).playstyle.stride : widget.record.endContext.firstWhere((element) => element.userId == widget.initPlayerId).playstyleTracking[roundSelector].stride), - RadarEntry(value: roundSelector.isNegative ? widget.record.endContext.firstWhere((element) => element.userId == widget.initPlayerId).playstyle.infds : widget.record.endContext.firstWhere((element) => element.userId == widget.initPlayerId).playstyleTracking[roundSelector].infds), - RadarEntry(value: roundSelector.isNegative ? widget.record.endContext.firstWhere((element) => element.userId == widget.initPlayerId).playstyle.plonk : widget.record.endContext.firstWhere((element) => element.userId == widget.initPlayerId).playstyleTracking[roundSelector].plonk), - ], - ), - RadarDataSet( - fillColor: const Color.fromARGB( - 115, 244, 67, 54), - borderColor: Colors.red, - dataEntries: [ - RadarEntry(value: roundSelector.isNegative ? widget.record.endContext.firstWhere((element) => element.userId != widget.initPlayerId).playstyle.opener : widget.record.endContext.firstWhere((element) => element.userId != widget.initPlayerId).playstyleTracking[roundSelector].opener), - RadarEntry(value: roundSelector.isNegative ? widget.record.endContext.firstWhere((element) => element.userId != widget.initPlayerId).playstyle.stride : widget.record.endContext.firstWhere((element) => element.userId != widget.initPlayerId).playstyleTracking[roundSelector].stride), - RadarEntry(value: roundSelector.isNegative ? widget.record.endContext.firstWhere((element) => element.userId != widget.initPlayerId).playstyle.infds : widget.record.endContext.firstWhere((element) => element.userId != widget.initPlayerId).playstyleTracking[roundSelector].infds), - RadarEntry(value: roundSelector.isNegative ? widget.record.endContext.firstWhere((element) => element.userId != widget.initPlayerId).playstyle.plonk : widget.record.endContext.firstWhere((element) => element.userId != widget.initPlayerId).playstyleTracking[roundSelector].plonk), - ], - ), - RadarDataSet( - fillColor: Colors.transparent, - borderColor: Colors.transparent, - dataEntries: [ - const RadarEntry(value: 0), - const RadarEntry(value: 0), - const RadarEntry(value: 0), - const RadarEntry(value: 0), - ], - ), - RadarDataSet( - fillColor: Colors.transparent, - borderColor: Colors.transparent, - dataEntries: [ - const RadarEntry(value: 1), - const RadarEntry(value: 1), - const RadarEntry(value: 1), - const RadarEntry(value: 1), - ], - ) - ], - ), - swapAnimationDuration: const Duration( - milliseconds: 150), // Optional - swapAnimationCurve: - Curves.linear, // Optional - ), - ), - ) - ], + VsGraphs( + roundSelector.isNegative ? widget.record.endContext.firstWhere((element) => element.userId == widget.initPlayerId).secondary : widget.record.endContext.firstWhere((element) => element.userId == widget.initPlayerId).secondaryTracking[roundSelector], + roundSelector.isNegative ? widget.record.endContext.firstWhere((element) => element.userId == widget.initPlayerId).tertiary : widget.record.endContext.firstWhere((element) => element.userId == widget.initPlayerId).tertiaryTracking[roundSelector], + roundSelector.isNegative ? widget.record.endContext.firstWhere((element) => element.userId == widget.initPlayerId).extra : widget.record.endContext.firstWhere((element) => element.userId == widget.initPlayerId).extraTracking[roundSelector], + roundSelector.isNegative ? widget.record.endContext.firstWhere((element) => element.userId == widget.initPlayerId).nerdStats : widget.record.endContext.firstWhere((element) => element.userId == widget.initPlayerId).nerdStatsTracking[roundSelector], + roundSelector.isNegative ? widget.record.endContext.firstWhere((element) => element.userId == widget.initPlayerId).playstyle : widget.record.endContext.firstWhere((element) => element.userId == widget.initPlayerId).playstyleTracking[roundSelector], + roundSelector.isNegative ? widget.record.endContext.firstWhere((element) => element.userId != widget.initPlayerId).secondary : widget.record.endContext.firstWhere((element) => element.userId != widget.initPlayerId).secondaryTracking[roundSelector], + roundSelector.isNegative ? widget.record.endContext.firstWhere((element) => element.userId != widget.initPlayerId).tertiary : widget.record.endContext.firstWhere((element) => element.userId != widget.initPlayerId).tertiaryTracking[roundSelector], + roundSelector.isNegative ? widget.record.endContext.firstWhere((element) => element.userId != widget.initPlayerId).extra : widget.record.endContext.firstWhere((element) => element.userId != widget.initPlayerId).extraTracking[roundSelector], + roundSelector.isNegative ? widget.record.endContext.firstWhere((element) => element.userId != widget.initPlayerId).nerdStats : widget.record.endContext.firstWhere((element) => element.userId != widget.initPlayerId).nerdStatsTracking[roundSelector], + roundSelector.isNegative ? widget.record.endContext.firstWhere((element) => element.userId != widget.initPlayerId).playstyle : widget.record.endContext.firstWhere((element) => element.userId != widget.initPlayerId).playstyleTracking[roundSelector] ) ], ) diff --git a/lib/widgets/graphs.dart b/lib/widgets/graphs.dart new file mode 100644 index 0000000..cadb397 --- /dev/null +++ b/lib/widgets/graphs.dart @@ -0,0 +1,179 @@ +import 'package:fl_chart/fl_chart.dart'; +import 'package:flutter/material.dart'; +import 'package:intl/intl.dart'; +import 'package:tetra_stats/data_objects/tetrio.dart'; +import 'package:tetra_stats/gen/strings.g.dart'; + +final NumberFormat _f2 = NumberFormat.decimalPatternDigits(locale: LocaleSettings.currentLocale.languageCode, decimalDigits: 2); + +class Graphs extends StatelessWidget{ + const Graphs( + this.apm, + this.pps, + this.vs, + this.nerdStats, + this.playstyle, {super.key} + ); + + final double apm; + final double pps; + final double vs; + final NerdStats nerdStats; + final Playstyle playstyle; + + @override + Widget build(BuildContext context) { + return Wrap( + direction: Axis.horizontal, + alignment: WrapAlignment.center, + spacing: 25, + crossAxisAlignment: WrapCrossAlignment.start, + clipBehavior: Clip.hardEdge, + children: [ + Padding( + padding: const EdgeInsets.fromLTRB(18, 0, 18, 44), + child: SizedBox( + height: 310, + width: 310, + child: RadarChart( + RadarChartData( + radarShape: RadarShape.polygon, + tickCount: 4, + ticksTextStyle: const TextStyle(color: Colors.transparent, fontSize: 10), + radarBorderData: const BorderSide(color: Colors.transparent, width: 1), + gridBorderData: const BorderSide(color: Colors.white24, width: 1), + tickBorderData: const BorderSide(color: Colors.transparent, width: 1), + getTitle: (index, angle) { + switch (index) { + case 0: + return RadarChartTitle(text: 'APM', angle: angle, positionPercentageOffset: 0.05); + case 1: + return RadarChartTitle(text: 'PPS', angle: angle, positionPercentageOffset: 0.05); + case 2: + return RadarChartTitle(text: 'VS', angle: angle, positionPercentageOffset: 0.05); + case 3: + return RadarChartTitle(text: 'APP', angle: angle + 180, positionPercentageOffset: 0.05); + case 4: + return RadarChartTitle(text: 'DS/S', angle: angle + 180, positionPercentageOffset: 0.05); + case 5: + return RadarChartTitle(text: 'DS/P', angle: angle + 180, positionPercentageOffset: 0.05); + case 6: + return RadarChartTitle(text: 'APP+DS/P', angle: angle + 180, positionPercentageOffset: 0.05); + case 7: + return RadarChartTitle(text: 'VS/APM', angle: angle + 180, positionPercentageOffset: 0.05); + case 8: + return RadarChartTitle(text: 'Cheese', angle: angle, positionPercentageOffset: 0.05); + case 9: + return RadarChartTitle(text: 'Gb Eff.', angle: angle, positionPercentageOffset: 0.05); + default: + return const RadarChartTitle(text: ''); + } + }, + dataSets: [ + RadarDataSet( + dataEntries: [ + RadarEntry(value: apm * apmWeight), + RadarEntry(value: pps * ppsWeight), + RadarEntry(value: vs * vsWeight), + RadarEntry(value: nerdStats.app * appWeight), + RadarEntry(value: nerdStats.dss * dssWeight), + RadarEntry(value: nerdStats.dsp * dspWeight), + RadarEntry(value: nerdStats.appdsp * appdspWeight), + RadarEntry(value: nerdStats.vsapm * vsapmWeight), + RadarEntry(value: nerdStats.cheese * cheeseWeight), + RadarEntry(value: nerdStats.gbe * gbeWeight), + ], + ), + RadarDataSet( + fillColor: Colors.transparent, + borderColor: Colors.transparent, + dataEntries: [ + const RadarEntry(value: 0), + const RadarEntry(value: 0), + const RadarEntry(value: 0), + const RadarEntry(value: 0), + const RadarEntry(value: 0), + const RadarEntry(value: 0), + const RadarEntry(value: 0), + const RadarEntry(value: 0), + const RadarEntry(value: 0), + const RadarEntry(value: 0), + ], + ) + ], + ), + swapAnimationDuration: const Duration(milliseconds: 150), // Optional + swapAnimationCurve: Curves.linear, // Optional + ), + ), + ), + Padding( + padding: const EdgeInsets.fromLTRB(18, 0, 18, 44), + child: SizedBox( + height: 310, + width: 310, + child: RadarChart( + RadarChartData( + radarShape: RadarShape.polygon, + tickCount: 4, + ticksTextStyle: const TextStyle(color: Colors.white24, fontSize: 10), + radarBorderData: const BorderSide(color: Colors.transparent, width: 1), + gridBorderData: const BorderSide(color: Colors.white24, width: 1), + tickBorderData: const BorderSide(color: Colors.transparent, width: 1), + titleTextStyle: const TextStyle(height: 1.1), + radarTouchData: RadarTouchData(), + getTitle: (index, angle) { + switch (index) { + case 0: + return RadarChartTitle(text: 'Opener\n${_f2.format(playstyle.opener)}', angle: 0, positionPercentageOffset: 0.05); + case 1: + return RadarChartTitle(text: 'Stride\n${_f2.format(playstyle.stride)}', angle: 0, positionPercentageOffset: 0.05); + case 2: + return RadarChartTitle(text: 'Inf Ds\n${_f2.format(playstyle.infds)}', angle: angle + 180, positionPercentageOffset: 0.05); + case 3: + return RadarChartTitle(text: 'Plonk\n${_f2.format(playstyle.plonk)}', angle: 0, positionPercentageOffset: 0.05); + default: + return const RadarChartTitle(text: ''); + } + }, + dataSets: [ + RadarDataSet( + dataEntries: [ + RadarEntry(value: playstyle.opener), + RadarEntry(value: playstyle.stride), + RadarEntry(value: playstyle.infds), + RadarEntry(value: playstyle.plonk), + ], + ), + RadarDataSet( + fillColor: Colors.transparent, + borderColor: Colors.transparent, + dataEntries: [ + const RadarEntry(value: 0), + const RadarEntry(value: 0), + const RadarEntry(value: 0), + const RadarEntry(value: 0), + ], + ), + RadarDataSet( + fillColor: Colors.transparent, + borderColor: Colors.transparent, + dataEntries: [ + const RadarEntry(value: 1), + const RadarEntry(value: 1), + const RadarEntry(value: 1), + const RadarEntry(value: 1), + ], + ) + ], + ), + swapAnimationDuration: const Duration(milliseconds: 150), // Optional + swapAnimationCurve: Curves.linear, // Optional + ), + ), + ), + ], + ); + } + +} \ No newline at end of file diff --git a/lib/widgets/tl_thingy.dart b/lib/widgets/tl_thingy.dart index 25b4b99..c49e95a 100644 --- a/lib/widgets/tl_thingy.dart +++ b/lib/widgets/tl_thingy.dart @@ -1,16 +1,16 @@ import 'package:flutter/material.dart'; import 'package:intl/intl.dart'; import 'package:tetra_stats/data_objects/tetrio.dart'; -import 'package:fl_chart/fl_chart.dart'; import 'package:syncfusion_flutter_gauges/gauges.dart'; import 'package:tetra_stats/gen/strings.g.dart'; +import 'package:tetra_stats/widgets/graphs.dart'; import 'package:tetra_stats/widgets/stat_sell_num.dart'; var fDiff = NumberFormat("+#,###.###;-#,###.###"); -RangeValues _currentRangeValues = const RangeValues(0, 1); final DateFormat dateFormat = DateFormat.yMMMd(LocaleSettings.currentLocale.languageCode).add_Hms(); final NumberFormat f2 = NumberFormat.decimalPatternDigits(locale: LocaleSettings.currentLocale.languageCode, decimalDigits: 2); final NumberFormat f3 = NumberFormat.decimalPatternDigits(locale: LocaleSettings.currentLocale.languageCode, decimalDigits: 3); +late RangeValues _currentRangeValues; TetraLeagueAlpha? oldTl; late TetraLeagueAlpha currentTl; late List sortedStates; @@ -31,8 +31,13 @@ class _TLThingyState extends State { @override void initState() { + _currentRangeValues = const RangeValues(0, 1); sortedStates = widget.states.reversed.toList(); - oldTl = sortedStates[1].tlSeason1; + try{ + oldTl = sortedStates[1].tlSeason1; + }on RangeError{ + oldTl = null; + } currentTl = widget.tl; super.initState(); } @@ -52,7 +57,7 @@ class _TLThingyState extends State { ? [ if (widget.showTitle) Text(t.tetraLeague, style: TextStyle(fontFamily: "Eurostile Round Extended", fontSize: bigScreen ? 42 : 28)), if (oldTl != null) Text(t.comparingWith(date: dateFormat.format(oldTl!.timestamp))), - RangeSlider(values: _currentRangeValues, max: widget.states.length.toDouble(), + if (oldTl != null) RangeSlider(values: _currentRangeValues, max: widget.states.length.toDouble(), labels: RangeLabels( _currentRangeValues.start.round().toString(), _currentRangeValues.end.round().toString(), @@ -400,158 +405,7 @@ class _TLThingyState extends State { ), ), ), - if (currentTl.nerdStats != null) - Wrap( - direction: Axis.horizontal, - alignment: WrapAlignment.center, - spacing: 25, - crossAxisAlignment: WrapCrossAlignment.start, - clipBehavior: Clip.hardEdge, - children: [ - Padding( - padding: const EdgeInsets.fromLTRB(18, 0, 18, 44), - child: SizedBox( - height: 310, - width: 310, - child: RadarChart( - RadarChartData( - radarShape: RadarShape.polygon, - tickCount: 4, - ticksTextStyle: const TextStyle(color: Colors.transparent, fontSize: 10), - radarBorderData: const BorderSide(color: Colors.transparent, width: 1), - gridBorderData: const BorderSide(color: Colors.white24, width: 1), - tickBorderData: const BorderSide(color: Colors.transparent, width: 1), - getTitle: (index, angle) { - switch (index) { - case 0: - return RadarChartTitle(text: 'APM', angle: angle, positionPercentageOffset: 0.05); - case 1: - return RadarChartTitle(text: 'PPS', angle: angle, positionPercentageOffset: 0.05); - case 2: - return RadarChartTitle(text: 'VS', angle: angle, positionPercentageOffset: 0.05); - case 3: - return RadarChartTitle(text: 'APP', angle: angle + 180, positionPercentageOffset: 0.05); - case 4: - return RadarChartTitle(text: 'DS/S', angle: angle + 180, positionPercentageOffset: 0.05); - case 5: - return RadarChartTitle(text: 'DS/P', angle: angle + 180, positionPercentageOffset: 0.05); - case 6: - return RadarChartTitle(text: 'APP+DS/P', angle: angle + 180, positionPercentageOffset: 0.05); - case 7: - return RadarChartTitle(text: 'VS/APM', angle: angle + 180, positionPercentageOffset: 0.05); - case 8: - return RadarChartTitle(text: 'Cheese', angle: angle, positionPercentageOffset: 0.05); - case 9: - return RadarChartTitle(text: 'Gb Eff.', angle: angle, positionPercentageOffset: 0.05); - default: - return const RadarChartTitle(text: ''); - } - }, - dataSets: [ - RadarDataSet( - dataEntries: [ - RadarEntry(value: currentTl.apm! * apmWeight), - RadarEntry(value: currentTl.pps! * ppsWeight), - RadarEntry(value: currentTl.vs! * vsWeight), - RadarEntry(value: currentTl.nerdStats!.app * appWeight), - RadarEntry(value: currentTl.nerdStats!.dss * dssWeight), - RadarEntry(value: currentTl.nerdStats!.dsp * dspWeight), - RadarEntry(value: currentTl.nerdStats!.appdsp * appdspWeight), - RadarEntry(value: currentTl.nerdStats!.vsapm * vsapmWeight), - RadarEntry(value: currentTl.nerdStats!.cheese * cheeseWeight), - RadarEntry(value: currentTl.nerdStats!.gbe * gbeWeight), - ], - ), - RadarDataSet( - fillColor: Colors.transparent, - borderColor: Colors.transparent, - dataEntries: [ - const RadarEntry(value: 0), - const RadarEntry(value: 0), - const RadarEntry(value: 0), - const RadarEntry(value: 0), - const RadarEntry(value: 0), - const RadarEntry(value: 0), - const RadarEntry(value: 0), - const RadarEntry(value: 0), - const RadarEntry(value: 0), - const RadarEntry(value: 0), - ], - ) - ], - ), - swapAnimationDuration: const Duration(milliseconds: 150), // Optional - swapAnimationCurve: Curves.linear, // Optional - ), - ), - ), - Padding( - padding: const EdgeInsets.fromLTRB(18, 0, 18, 44), - child: SizedBox( - height: 310, - width: 310, - child: RadarChart( - RadarChartData( - radarShape: RadarShape.polygon, - tickCount: 4, - ticksTextStyle: const TextStyle(color: Colors.white24, fontSize: 10), - radarBorderData: const BorderSide(color: Colors.transparent, width: 1), - gridBorderData: const BorderSide(color: Colors.white24, width: 1), - tickBorderData: const BorderSide(color: Colors.transparent, width: 1), - titleTextStyle: const TextStyle(height: 1.1), - radarTouchData: RadarTouchData(), - getTitle: (index, angle) { - switch (index) { - case 0: - return RadarChartTitle(text: 'Opener\n${f2.format(currentTl.playstyle!.opener)}', angle: 0, positionPercentageOffset: 0.05); - case 1: - return RadarChartTitle(text: 'Stride\n${f2.format(currentTl.playstyle!.stride)}', angle: 0, positionPercentageOffset: 0.05); - case 2: - return RadarChartTitle(text: 'Inf Ds\n${f2.format(currentTl.playstyle!.infds)}', angle: angle + 180, positionPercentageOffset: 0.05); - case 3: - return RadarChartTitle(text: 'Plonk\n${f2.format(currentTl.playstyle!.plonk)}', angle: 0, positionPercentageOffset: 0.05); - default: - return const RadarChartTitle(text: ''); - } - }, - dataSets: [ - RadarDataSet( - dataEntries: [ - RadarEntry(value: currentTl.playstyle!.opener), - RadarEntry(value: currentTl.playstyle!.stride), - RadarEntry(value: currentTl.playstyle!.infds), - RadarEntry(value: currentTl.playstyle!.plonk), - ], - ), - RadarDataSet( - fillColor: Colors.transparent, - borderColor: Colors.transparent, - dataEntries: [ - const RadarEntry(value: 0), - const RadarEntry(value: 0), - const RadarEntry(value: 0), - const RadarEntry(value: 0), - ], - ), - RadarDataSet( - fillColor: Colors.transparent, - borderColor: Colors.transparent, - dataEntries: [ - const RadarEntry(value: 1), - const RadarEntry(value: 1), - const RadarEntry(value: 1), - const RadarEntry(value: 1), - ], - ) - ], - ), - swapAnimationDuration: const Duration(milliseconds: 150), // Optional - swapAnimationCurve: Curves.linear, // Optional - ), - ), - ), - ], - ) + if (currentTl.nerdStats != null) Graphs(currentTl.apm!, currentTl.pps!, currentTl.vs!, currentTl.nerdStats!, currentTl.playstyle!) ] : [ Text(t.neverPlayedTL, style: const TextStyle(fontFamily: "Eurostile Round Extended", fontSize: 28)), diff --git a/lib/widgets/vs_graphs.dart b/lib/widgets/vs_graphs.dart new file mode 100644 index 0000000..d40e809 --- /dev/null +++ b/lib/widgets/vs_graphs.dart @@ -0,0 +1,211 @@ +import 'package:fl_chart/fl_chart.dart'; +import 'package:flutter/material.dart'; +import 'package:tetra_stats/data_objects/tetrio.dart'; + +class VsGraphs extends StatelessWidget{ + final double greenAPM; + final double greenPPS; + final double greenVS; + final NerdStats greenNerdStats; + final Playstyle greenPlaystyle; + final double redAPM; + final double redPPS; + final double redVS; + final NerdStats redNerdStats; + final Playstyle redPlaystyle; + + const VsGraphs(this.greenAPM, this.greenPPS, this.greenVS, this.greenNerdStats, this.greenPlaystyle, this.redAPM, this.redPPS, this.redVS, this.redNerdStats, this.redPlaystyle, {super.key}); + + @override + Widget build(BuildContext context) { + return Wrap( + direction: Axis.horizontal, + alignment: WrapAlignment.center, + spacing: 25, + crossAxisAlignment: WrapCrossAlignment.start, + clipBehavior: Clip.hardEdge, + children: [ + Padding( + padding: const EdgeInsets.fromLTRB(18, 0, 18, 44), + child: SizedBox( + height: 310, + width: 310, + child: RadarChart( + RadarChartData( + radarShape: RadarShape.polygon, + tickCount: 4, + ticksTextStyle: const TextStyle(color: Colors.transparent, fontSize: 10), + radarBorderData: const BorderSide(color: Colors.transparent, width: 1), + gridBorderData: const BorderSide(color: Colors.white24, width: 1), + tickBorderData: const BorderSide(color: Colors.transparent, width: 1), + getTitle: (index, angle) { + switch (index) { + case 0: + return RadarChartTitle( + text: 'APM', + angle: angle, + positionPercentageOffset: 0.05 + ); + case 1: + return RadarChartTitle( + text: 'PPS', + angle: angle, + positionPercentageOffset: 0.05 + ); + case 2: + return RadarChartTitle(text: 'VS', angle: angle, positionPercentageOffset: 0.05); + case 3: + return RadarChartTitle(text: 'APP', angle: angle + 180, positionPercentageOffset: 0.05); + case 4: + return RadarChartTitle(text: 'DS/S', angle: angle + 180, positionPercentageOffset: 0.05); + case 5: + return RadarChartTitle(text: 'DS/P', angle: angle + 180, positionPercentageOffset: 0.05); + case 6: + return RadarChartTitle(text: 'APP+DS/P', angle: angle + 180, positionPercentageOffset: 0.05); + case 7: + return RadarChartTitle(text: 'VS/APM', angle: angle + 180, positionPercentageOffset: 0.05); + case 8: + return RadarChartTitle(text: 'Cheese', angle: angle, positionPercentageOffset: 0.05); + case 9: + return RadarChartTitle(text: 'Gb Eff.', angle: angle, positionPercentageOffset: 0.05); + default: + return const RadarChartTitle(text: ''); + } + }, + dataSets: [ + RadarDataSet( + fillColor: const Color.fromARGB(115, 76, 175, 79), + borderColor: Colors.green, + dataEntries: [ + RadarEntry(value: greenAPM * apmWeight), + RadarEntry(value: greenPPS * ppsWeight), + RadarEntry(value: greenVS * vsWeight), + RadarEntry(value: greenNerdStats.app * appWeight), + RadarEntry(value: greenNerdStats.dss * dssWeight), + RadarEntry(value: greenNerdStats.dsp * dspWeight), + RadarEntry(value: greenNerdStats.appdsp * appdspWeight), + RadarEntry(value: greenNerdStats.vsapm * vsapmWeight), + RadarEntry(value: greenNerdStats.cheese * cheeseWeight), + RadarEntry(value: greenNerdStats.gbe * gbeWeight), + ], + ), + RadarDataSet( + fillColor: const Color.fromARGB(115, 244, 67, 54), + borderColor: Colors.red, + dataEntries: [ + RadarEntry(value: redAPM * apmWeight), + RadarEntry(value: redPPS * ppsWeight), + RadarEntry(value: redVS * vsWeight), + RadarEntry(value: redNerdStats.app * appWeight), + RadarEntry(value: redNerdStats.dss * dssWeight), + RadarEntry(value: redNerdStats.dsp * dspWeight), + RadarEntry(value: redNerdStats.appdsp * appdspWeight), + RadarEntry(value: redNerdStats.vsapm * vsapmWeight), + RadarEntry(value: redNerdStats.cheese * cheeseWeight), + RadarEntry(value: redNerdStats.gbe * gbeWeight), + ], + ), + RadarDataSet( + fillColor: Colors.transparent, + borderColor: Colors.transparent, + dataEntries: [ + const RadarEntry(value: 0), + const RadarEntry(value: 0), + const RadarEntry(value: 0), + const RadarEntry(value: 0), + const RadarEntry(value: 0), + const RadarEntry(value: 0), + const RadarEntry(value: 0), + const RadarEntry(value: 0), + const RadarEntry(value: 0), + const RadarEntry(value: 0), + ], + ) + ], + ), + swapAnimationDuration: const Duration(milliseconds: 150), + swapAnimationCurve: Curves.linear, + ), + ), + ), + Padding( + padding: const EdgeInsets.fromLTRB(18, 0, 18, 44), + child: SizedBox( + height: 310, + width: 310, + child: RadarChart( + RadarChartData( + radarShape: RadarShape.polygon, + tickCount: 4, + ticksTextStyle: const TextStyle(color: Colors.white24, fontSize: 10), + radarBorderData: const BorderSide(color: Colors.transparent, width: 1), + gridBorderData: const BorderSide(color: Colors.white24, width: 1), + tickBorderData: const BorderSide(color: Colors.transparent, width: 1), + titleTextStyle: const TextStyle(height: 1.1), + radarTouchData: RadarTouchData(), + getTitle: (index, angle) { + switch (index) { + case 0: + return RadarChartTitle(text: 'Opener',angle: angle, positionPercentageOffset: 0.05); + case 1: + return RadarChartTitle(text: 'Stride', angle: angle, positionPercentageOffset: 0.05); + case 2: + return RadarChartTitle(text: 'Inf Ds', angle: angle + 180, positionPercentageOffset: 0.05); + case 3: + return RadarChartTitle(text: 'Plonk', angle: angle, positionPercentageOffset: 0.05); + default: + return const RadarChartTitle(text: ''); + } + }, + dataSets: [ + RadarDataSet( + fillColor: const Color.fromARGB(115, 76, 175, 79), + borderColor: Colors.green, + dataEntries: [ + RadarEntry(value: greenPlaystyle.opener), + RadarEntry(value: greenPlaystyle.stride), + RadarEntry(value: greenPlaystyle.infds), + RadarEntry(value: greenPlaystyle.plonk), + ], + ), + RadarDataSet( + fillColor: const Color.fromARGB(115, 244, 67, 54), + borderColor: Colors.red, + dataEntries: [ + RadarEntry(value: redPlaystyle.opener), + RadarEntry(value: redPlaystyle.stride), + RadarEntry(value: redPlaystyle.infds), + RadarEntry(value: redPlaystyle.plonk), + ], + ), + RadarDataSet( + fillColor: Colors.transparent, + borderColor: Colors.transparent, + dataEntries: [ + const RadarEntry(value: 0), + const RadarEntry(value: 0), + const RadarEntry(value: 0), + const RadarEntry(value: 0), + ], + ), + RadarDataSet( + fillColor: Colors.transparent, + borderColor: Colors.transparent, + dataEntries: [ + const RadarEntry(value: 1), + const RadarEntry(value: 1), + const RadarEntry(value: 1), + const RadarEntry(value: 1), + ], + ) + ], + ), + swapAnimationDuration: const Duration(milliseconds: 150), // Optional + swapAnimationCurve: Curves.linear, // Optional + ), + ), + ), + ], + ); + } +} \ No newline at end of file