fixed brand new thing + refactoring

More refactoring on the way
This commit is contained in:
dan63047 2023-10-27 01:38:03 +03:00
parent c2f73ce1fb
commit 7ec3d76c7f
11 changed files with 547 additions and 818 deletions

View File

@ -16,6 +16,7 @@ import 'package:tetra_stats/views/tracked_players_view.dart';
import 'package:tetra_stats/views/calc_view.dart'; import 'package:tetra_stats/views/calc_view.dart';
late final PackageInfo packageInfo; late final PackageInfo packageInfo;
late SharedPreferences prefs;
void main() async { void main() async {
if (kIsWeb) { if (kIsWeb) {

View File

@ -1,10 +1,10 @@
import 'dart:io'; import 'dart:io';
import 'package:fl_chart/fl_chart.dart';
import 'package:flutter/foundation.dart'; import 'package:flutter/foundation.dart';
import 'package:flutter/material.dart'; import 'package:flutter/material.dart';
import 'package:intl/intl.dart'; import 'package:intl/intl.dart';
import 'package:tetra_stats/data_objects/tetrio.dart'; import 'package:tetra_stats/data_objects/tetrio.dart';
import 'package:tetra_stats/gen/strings.g.dart'; import 'package:tetra_stats/gen/strings.g.dart';
import 'package:tetra_stats/widgets/graphs.dart';
import 'package:window_manager/window_manager.dart'; import 'package:window_manager/window_manager.dart';
double? apm; double? apm;
@ -131,165 +131,7 @@ class CalcState extends State<CalcView> {
_ListEntry(value: nerdStats!.nyaapp, label: t.statCellNum.nyaapp.replaceAll(RegExp(r'\n'), " "), fractionDigits: 3), _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: nerdStats!.area, label: t.statCellNum.area.replaceAll(RegExp(r'\n'), " "), fractionDigits: 3),
_ListEntry(value: estTr!.esttr, label: t.statCellNum.estOfTR, fractionDigits: 3), _ListEntry(value: estTr!.esttr, label: t.statCellNum.estOfTR, fractionDigits: 3),
Wrap( Graphs(apm!, pps!, vs!, nerdStats!, playstyle!),
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
),
),
),
],
)
], ],
)), )),
), ),

View File

@ -1,12 +1,12 @@
import 'dart:io'; import 'dart:io';
import 'dart:math'; import 'dart:math';
import 'package:fl_chart/fl_chart.dart';
import 'package:flutter/foundation.dart'; import 'package:flutter/foundation.dart';
import 'package:flutter/material.dart'; import 'package:flutter/material.dart';
import 'package:intl/intl.dart'; import 'package:intl/intl.dart';
import 'package:tetra_stats/data_objects/tetrio.dart'; import 'package:tetra_stats/data_objects/tetrio.dart';
import 'package:tetra_stats/gen/strings.g.dart'; import 'package:tetra_stats/gen/strings.g.dart';
import 'package:tetra_stats/services/tetrio_crud.dart'; import 'package:tetra_stats/services/tetrio_crud.dart';
import 'package:tetra_stats/widgets/vs_graphs.dart';
import 'package:window_manager/window_manager.dart'; import 'package:window_manager/window_manager.dart';
enum Mode{ enum Mode{
@ -647,193 +647,7 @@ class CompareState extends State<CompareView> {
fractionDigits: 3, fractionDigits: 3,
higherIsBetter: true, higherIsBetter: true,
), ),
Wrap( 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!),
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(), const Divider(),
Padding( Padding(
padding: const EdgeInsets.only(bottom: 16), padding: const EdgeInsets.only(bottom: 16),
@ -880,8 +694,6 @@ class CompareState extends State<CompareView> {
), ),
], ],
) )
],
)
] : [Padding( ] : [Padding(
padding: const EdgeInsets.all(8.0), padding: const EdgeInsets.all(8.0),
child: Text(t.compareViewNoValues(avgR: "\$avgR"), textAlign: TextAlign.center), child: Text(t.compareViewNoValues(avgR: "\$avgR"), textAlign: TextAlign.center),

View File

@ -11,6 +11,7 @@ import 'package:flutter/services.dart';
import 'package:tetra_stats/data_objects/tetrio.dart'; import 'package:tetra_stats/data_objects/tetrio.dart';
import 'package:tetra_stats/gen/strings.g.dart'; import 'package:tetra_stats/gen/strings.g.dart';
import 'package:tetra_stats/services/tetrio_crud.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/services/crud_exceptions.dart';
import 'package:tetra_stats/views/ranks_averages_view.dart' show RankAveragesView; import 'package:tetra_stats/views/ranks_averages_view.dart' show RankAveragesView;
import 'package:tetra_stats/views/tl_leaderboard_view.dart' show TLLeaderboardView; import 'package:tetra_stats/views/tl_leaderboard_view.dart' show TLLeaderboardView;
@ -25,15 +26,14 @@ Future<List> me = Future.delayed(const Duration(seconds: 60), () => [null, null,
String _searchFor = "6098518e3d5155e6ec429cdc"; String _searchFor = "6098518e3d5155e6ec429cdc";
String _titleNickname = "dan63047"; String _titleNickname = "dan63047";
final TetrioService teto = TetrioService(); final TetrioService teto = TetrioService();
late SharedPreferences prefs;
var chartsData = <DropdownMenuItem<List<FlSpot>>>[]; var chartsData = <DropdownMenuItem<List<FlSpot>>>[];
List historyShortTitles = ["TR", "Glicko", "RD", "APM", "PPS", "VS", "APP", "DS/S", "DS/P", "APP + DS/P", "VS/APM", "Cheese", "GbE", "wAPP", "Area", "eTR", "±eTR"]; 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; int _chartsIndex = 0;
final NumberFormat timeInSec = NumberFormat("#,###.###s."); final NumberFormat _timeInSec = NumberFormat("#,###.###s.");
final NumberFormat f2 = NumberFormat.decimalPatternDigits(locale: LocaleSettings.currentLocale.languageCode, decimalDigits: 2); final NumberFormat _secs = NumberFormat("00.###");
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 NumberFormat _f4 = NumberFormat.decimalPatternDigits(locale: LocaleSettings.currentLocale.languageCode, decimalDigits: 4);
final DateFormat dateFormat = DateFormat.yMMMd(LocaleSettings.currentLocale.languageCode).add_Hms(); final DateFormat _dateFormat = DateFormat.yMMMd(LocaleSettings.currentLocale.languageCode).add_Hms();
class MainView extends StatefulWidget { class MainView extends StatefulWidget {
final String? player; final String? player;
@ -51,9 +51,9 @@ Future<void> copyToClipboard(String text) async {
String get40lTime(int microseconds){ String get40lTime(int microseconds){
if (microseconds > 60000000) { if (microseconds > 60000000) {
return "${(microseconds/1000000/60).floor()}:${(secs.format(microseconds /1000000 % 60))}"; return "${(microseconds/1000000/60).floor()}:${(_secs.format(microseconds /1000000 % 60))}";
} else{ } 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) : style: bigScreen ? const TextStyle(fontFamily: "Eurostile Round Extended", fontSize: 28) :
const TextStyle(fontSize: 28)), const TextStyle(fontSize: 28)),
title: Text("vs. ${value.endContext.firstWhere((element) => element.userId != userID).username}"), 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(), trailing: Table(defaultColumnWidth: const IntrinsicColumnWidth(),
defaultVerticalAlignment: TableCellVerticalAlignment.baseline, defaultVerticalAlignment: TableCellVerticalAlignment.baseline,
textBaseline: TextBaseline.alphabetic, textBaseline: TextBaseline.alphabetic,
@ -552,9 +552,9 @@ class _TLRecords extends StatelessWidget {
2: FixedColumnWidth(50), 2: FixedColumnWidth(50),
}, },
children: [ 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).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).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).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( onTap: (){Navigator.push(
context, context,
@ -582,13 +582,13 @@ class _History extends StatelessWidget{
children: [ children: [
DropdownButton( DropdownButton(
items: chartsData, items: chartsData,
value: chartsData[chartsIndex].value, value: chartsData[_chartsIndex].value,
onChanged: (value) { onChanged: (value) {
chartsIndex = chartsData.indexWhere((element) => element.value == value); _chartsIndex = chartsData.indexWhere((element) => element.value == value);
update(); 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))) else Center(child: Text(t.notEnoughData, style: const TextStyle(fontFamily: "Eurostile Round Extended", fontSize: 28)))
], ],
), ),
@ -634,7 +634,7 @@ class _HistoryChartThigy extends StatelessWidget{
) : Container(); ) : Container();
}))), }))),
lineTouchData: LineTouchData(touchTooltipData: LineTouchTooltipData( fitInsideHorizontally: true, fitInsideVertically: true, getTooltipItems: (touchedSpots) { 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", playerStatLabel: "Leaderboard Placement",
isScreenBig: bigScreen, isScreenBig: bigScreen,
higherIsBetter: false), higherIsBetter: false),
Text(t.obtainDate(date: dateFormat.format(record!.timestamp!)), Text(t.obtainDate(date: _dateFormat.format(record!.timestamp!)),
textAlign: TextAlign.center, textAlign: TextAlign.center,
style: const TextStyle( style: const TextStyle(
fontFamily: "Eurostile Round", 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": case "personalbest":
return ListTile( 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( leading: Image.asset(
"res/icons/improvement-local.png", "res/icons/improvement-local.png",
height: 48, 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( leading: Image.asset(
"res/tetrio_badges/${news.data["type"]}.png", "res/tetrio_badges/${news.data["type"]}.png",
height: 48, 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( leading: Image.asset(
"res/tetrio_tl_alpha_ranks/${news.data["rank"]}.png", "res/tetrio_tl_alpha_ranks/${news.data["rank"]}.png",
height: 48, 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( leading: Image.asset(
"res/icons/supporter-tag.png", "res/icons/supporter-tag.png",
height: 48, 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( leading: Image.asset(
"res/icons/supporter-tag.png", "res/icons/supporter-tag.png",
height: 48, height: 48,
@ -1054,7 +1054,7 @@ class _OtherThingy extends StatelessWidget {
default: default:
return ListTile( return ListTile(
title: Text(t.newsParts.unknownNews(type: news.type)), title: Text(t.newsParts.unknownNews(type: news.type)),
subtitle: Text(dateFormat.format(news.timestamp)), subtitle: Text(_dateFormat.format(news.timestamp)),
); );
} }
} }

View File

@ -5,18 +5,20 @@ import 'package:flutter/material.dart';
import 'package:intl/intl.dart'; import 'package:intl/intl.dart';
import 'package:tetra_stats/data_objects/tetrio.dart'; import 'package:tetra_stats/data_objects/tetrio.dart';
import 'package:tetra_stats/gen/strings.g.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'; import 'package:window_manager/window_manager.dart';
var chartsShortTitlesDropdowns = <DropdownMenuItem>[for (MapEntry e in chartsShortTitles.entries) DropdownMenuItem(value: e.key, child: Text(e.value),)]; var _chartsShortTitlesDropdowns = <DropdownMenuItem>[for (MapEntry e in chartsShortTitles.entries) DropdownMenuItem(value: e.key, child: Text(e.value),)];
Stats chartsX = Stats.tr; Stats _chartsX = Stats.tr;
Stats chartsY = Stats.apm; Stats _chartsY = Stats.apm;
List<DropdownMenuItem> itemStats = [for (MapEntry e in chartsShortTitles.entries) DropdownMenuItem(value: e.key, child: Text(e.value))]; List<DropdownMenuItem> _itemStats = [for (MapEntry e in chartsShortTitles.entries) DropdownMenuItem(value: e.key, child: Text(e.value))];
Stats sortBy = Stats.tr; Stats _sortBy = Stats.tr;
bool reversed = false; bool _reversed = false;
List<DropdownMenuItem> itemCountries = [for (MapEntry e in t.countries.entries) DropdownMenuItem(value: e.key, child: Text(e.value))]; List<DropdownMenuItem> _itemCountries = [for (MapEntry e in t.countries.entries) DropdownMenuItem(value: e.key, child: Text(e.value))];
String country = ""; String _country = "";
late String oldWindowTitle; 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 { class RankView extends StatefulWidget {
final List rank; final List rank;
@ -35,7 +37,7 @@ class RankState extends State<RankView> with SingleTickerProviderStateMixin {
_scrollController = ScrollController(); _scrollController = ScrollController();
_tabController = TabController(length: 6, vsync: this); _tabController = TabController(length: 6, vsync: this);
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.rank[1]["everyone"] ? t.everyoneAverages : t.rankAverages(rank: widget.rank[0].rank.toUpperCase())}"); windowManager.setTitle("Tetra Stats: ${widget.rank[1]["everyone"] ? t.everyoneAverages : t.rankAverages(rank: widget.rank[0].rank.toUpperCase())}");
} }
super.initState(); super.initState();
@ -45,7 +47,7 @@ class RankState extends State<RankView> with SingleTickerProviderStateMixin {
void dispose() { void dispose() {
_tabController.dispose(); _tabController.dispose();
_scrollController.dispose(); _scrollController.dispose();
if (!kIsWeb && !Platform.isAndroid && !Platform.isIOS) windowManager.setTitle(oldWindowTitle); if (!kIsWeb && !Platform.isAndroid && !Platform.isIOS) windowManager.setTitle(_oldWindowTitle);
super.dispose(); super.dispose();
} }
@ -57,7 +59,7 @@ class RankState extends State<RankView> with SingleTickerProviderStateMixin {
Widget build(BuildContext context) { Widget build(BuildContext context) {
final t = Translations.of(context); final t = Translations.of(context);
bool bigScreen = MediaQuery.of(context).size.width > 768; bool bigScreen = MediaQuery.of(context).size.width > 768;
List<TetrioPlayerFromLeaderboard> they = TetrioPlayersLeaderboard("lol", []).getStatRanking(widget.rank[1]["entries"]!, sortBy, reversed: reversed, country: country); List<TetrioPlayerFromLeaderboard> they = TetrioPlayersLeaderboard("lol", []).getStatRanking(widget.rank[1]["entries"]!, _sortBy, reversed: _reversed, country: _country);
return Scaffold( return Scaffold(
appBar: AppBar( appBar: AppBar(
title: Text(widget.rank[1]["everyone"] ? t.everyoneAverages : t.rankAverages(rank: widget.rank[0].rank.toUpperCase())), title: Text(widget.rank[1]["everyone"] ? t.everyoneAverages : t.rankAverages(rank: widget.rank[0].rank.toUpperCase())),
@ -135,10 +137,10 @@ class RankState extends State<RankView> with SingleTickerProviderStateMixin {
style: style:
const TextStyle(fontSize: 22))), const TextStyle(fontSize: 22))),
DropdownButton( DropdownButton(
items: chartsShortTitlesDropdowns, items: _chartsShortTitlesDropdowns,
value: chartsX, value: _chartsX,
onChanged: (value) { onChanged: (value) {
chartsX = value; _chartsX = value;
_justUpdate(); _justUpdate();
}), }),
], ],
@ -156,10 +158,10 @@ class RankState extends State<RankView> with SingleTickerProviderStateMixin {
style: const TextStyle(fontSize: 22)), style: const TextStyle(fontSize: 22)),
), ),
DropdownButton( DropdownButton(
items: chartsShortTitlesDropdowns, items: _chartsShortTitlesDropdowns,
value: chartsY, value: _chartsY,
onChanged: (value) { onChanged: (value) {
chartsY = value; _chartsY = value;
_justUpdate(); _justUpdate();
}), }),
], ],
@ -186,9 +188,9 @@ class RankState extends State<RankView> with SingleTickerProviderStateMixin {
for (TetrioPlayerFromLeaderboard entry for (TetrioPlayerFromLeaderboard entry
in widget.rank[1]["entries"]) in widget.rank[1]["entries"])
_MyScatterSpot( _MyScatterSpot(
entry.getStatByEnum(chartsX) entry.getStatByEnum(_chartsX)
as double, as double,
entry.getStatByEnum(chartsY) entry.getStatByEnum(_chartsY)
as double, as double,
entry.userId, entry.userId,
entry.username, entry.username,
@ -211,7 +213,7 @@ class RankState extends State<RankView> with SingleTickerProviderStateMixin {
children: [ children: [
TextSpan( TextSpan(
text: 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( style: const TextStyle(
fontFamily: fontFamily:
"Eurostile Round")) "Eurostile Round"))
@ -266,10 +268,10 @@ class RankState extends State<RankView> with SingleTickerProviderStateMixin {
children: [ children: [
Text("${t.sortBy}: ", style: const TextStyle(color: Colors.white, fontSize: 25)), Text("${t.sortBy}: ", style: const TextStyle(color: Colors.white, fontSize: 25)),
DropdownButton( DropdownButton(
items: itemStats, items: _itemStats,
value: sortBy, value: _sortBy,
onChanged: ((value) { onChanged: ((value) {
sortBy = value; _sortBy = value;
setState(() {}); setState(() {});
}), }),
), ),
@ -283,10 +285,10 @@ class RankState extends State<RankView> with SingleTickerProviderStateMixin {
Text("${t.reversed}: ", style: const TextStyle(color: Colors.white, fontSize: 25)), Text("${t.reversed}: ", style: const TextStyle(color: Colors.white, fontSize: 25)),
Padding(padding: const EdgeInsets.fromLTRB(0, 5.5, 0, 7.5), Padding(padding: const EdgeInsets.fromLTRB(0, 5.5, 0, 7.5),
child: Checkbox( child: Checkbox(
value: reversed, value: _reversed,
checkColor: Colors.black, checkColor: Colors.black,
onChanged: ((value) { onChanged: ((value) {
reversed = value!; _reversed = value!;
setState(() {}); setState(() {});
}), }),
), ),
@ -300,10 +302,10 @@ class RankState extends State<RankView> with SingleTickerProviderStateMixin {
children: [ children: [
Text("${t.country}: ", style: const TextStyle(color: Colors.white, fontSize: 25)), Text("${t.country}: ", style: const TextStyle(color: Colors.white, fontSize: 25)),
DropdownButton( DropdownButton(
items: itemCountries, items: _itemCountries,
value: country, value: _country,
onChanged: ((value) { onChanged: ((value) {
country = value; _country = value;
setState(() {}); setState(() {});
}), }),
), ),
@ -319,11 +321,11 @@ class RankState extends State<RankView> with SingleTickerProviderStateMixin {
bool bigScreen = MediaQuery.of(context).size.width > 768; bool bigScreen = MediaQuery.of(context).size.width > 768;
return ListTile( return ListTile(
title: Text(they[index].username, style: const TextStyle(fontFamily: "Eurostile Round Extended")), 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( trailing: Row(
mainAxisSize: MainAxisSize.min, mainAxisSize: MainAxisSize.min,
children: [ 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), Image.asset("res/tetrio_tl_alpha_ranks/${they[index].rank}.png", height: bigScreen ? 48 : 16),
], ],
), ),

View File

@ -4,8 +4,8 @@ import 'package:flutter/material.dart';
import 'package:intl/intl.dart'; import 'package:intl/intl.dart';
import 'package:tetra_stats/gen/strings.g.dart'; import 'package:tetra_stats/gen/strings.g.dart';
import 'package:tetra_stats/views/rank_averages_view.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 'package:window_manager/window_manager.dart';
import 'main_view.dart'; // lol
class RankAveragesView extends StatefulWidget { class RankAveragesView extends StatefulWidget {
const RankAveragesView({Key? key}) : super(key: key); const RankAveragesView({Key? key}) : super(key: key);

View File

@ -10,13 +10,14 @@ import 'package:tetra_stats/views/rank_averages_view.dart';
import 'package:tetra_stats/views/ranks_averages_view.dart'; import 'package:tetra_stats/views/ranks_averages_view.dart';
import 'package:window_manager/window_manager.dart'; import 'package:window_manager/window_manager.dart';
final TetrioService teto = TetrioService(); final TetrioService _teto = TetrioService();
List<DropdownMenuItem> itemStats = [for (MapEntry e in chartsShortTitles.entries) DropdownMenuItem(value: e.key, child: Text(e.value))]; List<DropdownMenuItem> _itemStats = [for (MapEntry e in chartsShortTitles.entries) DropdownMenuItem(value: e.key, child: Text(e.value))];
Stats sortBy = Stats.tr; Stats _sortBy = Stats.tr;
bool reversed = false; bool reversed = false;
List<DropdownMenuItem> itemCountries = [for (MapEntry e in t.countries.entries) DropdownMenuItem(value: e.key, child: Text(e.value))]; List<DropdownMenuItem> _itemCountries = [for (MapEntry e in t.countries.entries) DropdownMenuItem(value: e.key, child: Text(e.value))];
String country = ""; String _country = "";
late String oldWindowTitle; late String _oldWindowTitle;
final NumberFormat _f4 = NumberFormat.decimalPatternDigits(locale: LocaleSettings.currentLocale.languageCode, decimalDigits: 4);
class TLLeaderboardView extends StatefulWidget { class TLLeaderboardView extends StatefulWidget {
const TLLeaderboardView({Key? key}) : super(key: key); const TLLeaderboardView({Key? key}) : super(key: key);
@ -28,20 +29,20 @@ class TLLeaderboardView extends StatefulWidget {
class TLLeaderboardState extends State<TLLeaderboardView> { class TLLeaderboardState extends State<TLLeaderboardView> {
@override @override
void initState() { 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(); 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();
} }
@override @override
Widget build(BuildContext context) { Widget build(BuildContext context) {
final t = Translations.of(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( return Scaffold(
appBar: AppBar( appBar: AppBar(
title: Text(t.tlLeaderboard), title: Text(t.tlLeaderboard),
@ -64,7 +65,7 @@ class TLLeaderboardState extends State<TLLeaderboardView> {
backgroundColor: Colors.black, backgroundColor: Colors.black,
body: SafeArea( body: SafeArea(
child: FutureBuilder( child: FutureBuilder(
future: teto.fetchTLLeaderboard(), future: _teto.fetchTLLeaderboard(),
builder: (context, snapshot) { builder: (context, snapshot) {
switch (snapshot.connectionState) { switch (snapshot.connectionState) {
case ConnectionState.none: case ConnectionState.none:
@ -72,7 +73,7 @@ class TLLeaderboardState extends State<TLLeaderboardView> {
case ConnectionState.active: case ConnectionState.active:
return const Center(child: Text('Fetching...')); return const Center(child: Text('Fetching...'));
case ConnectionState.done: 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)}"); if (!kIsWeb && !Platform.isAndroid && !Platform.isIOS) windowManager.setTitle("Tetra Stats: ${t.tlLeaderboard} - ${t.players(n: allPlayers!.length)}");
return NestedScrollView( return NestedScrollView(
headerSliverBuilder: (context, value) { headerSliverBuilder: (context, value) {
@ -124,8 +125,8 @@ class TLLeaderboardState extends State<TLLeaderboardView> {
children: [ children: [
Text("${t.sortBy}: ", Text("${t.sortBy}: ",
style: const TextStyle(color: Colors.white, fontSize: 25)), style: const TextStyle(color: Colors.white, fontSize: 25)),
DropdownButton(items: itemStats, value: sortBy, onChanged: ((value) { DropdownButton(items: _itemStats, value: _sortBy, onChanged: ((value) {
sortBy = value; _sortBy = value;
setState(() {}); setState(() {});
}),), }),),
], ],
@ -155,8 +156,8 @@ class TLLeaderboardState extends State<TLLeaderboardView> {
children: [ children: [
Text("${t.country}: ", Text("${t.country}: ",
style: const TextStyle(color: Colors.white, fontSize: 25)), style: const TextStyle(color: Colors.white, fontSize: 25)),
DropdownButton(items: itemCountries, value: country, onChanged: ((value) { DropdownButton(items: _itemCountries, value: _country, onChanged: ((value) {
country = value; _country = value;
setState(() {}); setState(() {});
}),), }),),
], ],
@ -174,11 +175,11 @@ class TLLeaderboardState extends State<TLLeaderboardView> {
return ListTile( return ListTile(
leading: Text((index+1).toString(), style: bigScreen ? const TextStyle(fontFamily: "Eurostile Round Extended", fontSize: 28) : null), 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")), 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( trailing: Row(
mainAxisSize: MainAxisSize.min, mainAxisSize: MainAxisSize.min,
children: [ 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), Image.asset("res/tetrio_tl_alpha_ranks/${allPlayers[index].rank}.png", height: bigScreen ? 48 : 16),
], ],
), ),

View File

@ -2,6 +2,7 @@
import 'dart:io'; import 'dart:io';
import 'package:tetra_stats/services/crud_exceptions.dart'; import 'package:tetra_stats/services/crud_exceptions.dart';
import 'package:tetra_stats/widgets/vs_graphs.dart';
import 'main_view.dart' show teto; import 'main_view.dart' show teto;
import 'package:fl_chart/fl_chart.dart'; import 'package:fl_chart/fl_chart.dart';
@ -329,191 +330,17 @@ class TlMatchResultState extends State<TlMatchResultView> {
fractionDigits: 3, fractionDigits: 3,
higherIsBetter: true, higherIsBetter: true,
), ),
Wrap( VsGraphs(
direction: Axis.horizontal, roundSelector.isNegative ? widget.record.endContext.firstWhere((element) => element.userId == widget.initPlayerId).secondary : widget.record.endContext.firstWhere((element) => element.userId == widget.initPlayerId).secondaryTracking[roundSelector],
alignment: WrapAlignment.center, roundSelector.isNegative ? widget.record.endContext.firstWhere((element) => element.userId == widget.initPlayerId).tertiary : widget.record.endContext.firstWhere((element) => element.userId == widget.initPlayerId).tertiaryTracking[roundSelector],
spacing: 25, roundSelector.isNegative ? widget.record.endContext.firstWhere((element) => element.userId == widget.initPlayerId).extra : widget.record.endContext.firstWhere((element) => element.userId == widget.initPlayerId).extraTracking[roundSelector],
crossAxisAlignment: WrapCrossAlignment.start, roundSelector.isNegative ? widget.record.endContext.firstWhere((element) => element.userId == widget.initPlayerId).nerdStats : widget.record.endContext.firstWhere((element) => element.userId == widget.initPlayerId).nerdStatsTracking[roundSelector],
clipBehavior: Clip.hardEdge, roundSelector.isNegative ? widget.record.endContext.firstWhere((element) => element.userId == widget.initPlayerId).playstyle : widget.record.endContext.firstWhere((element) => element.userId == widget.initPlayerId).playstyleTracking[roundSelector],
children: [Padding( roundSelector.isNegative ? widget.record.endContext.firstWhere((element) => element.userId != widget.initPlayerId).secondary : widget.record.endContext.firstWhere((element) => element.userId != widget.initPlayerId).secondaryTracking[roundSelector],
padding: const EdgeInsets.fromLTRB(20, 20, 20, 20), roundSelector.isNegative ? widget.record.endContext.firstWhere((element) => element.userId != widget.initPlayerId).tertiary : widget.record.endContext.firstWhere((element) => element.userId != widget.initPlayerId).tertiaryTracking[roundSelector],
child: SizedBox( roundSelector.isNegative ? widget.record.endContext.firstWhere((element) => element.userId != widget.initPlayerId).extra : widget.record.endContext.firstWhere((element) => element.userId != widget.initPlayerId).extraTracking[roundSelector],
height: 310, roundSelector.isNegative ? widget.record.endContext.firstWhere((element) => element.userId != widget.initPlayerId).nerdStats : widget.record.endContext.firstWhere((element) => element.userId != widget.initPlayerId).nerdStatsTracking[roundSelector],
width: 310, roundSelector.isNegative ? widget.record.endContext.firstWhere((element) => element.userId != widget.initPlayerId).playstyle : widget.record.endContext.firstWhere((element) => element.userId != widget.initPlayerId).playstyleTracking[roundSelector]
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
),
),
)
],
) )
], ],
) )

179
lib/widgets/graphs.dart Normal file
View File

@ -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
),
),
),
],
);
}
}

View File

@ -1,16 +1,16 @@
import 'package:flutter/material.dart'; import 'package:flutter/material.dart';
import 'package:intl/intl.dart'; import 'package:intl/intl.dart';
import 'package:tetra_stats/data_objects/tetrio.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:syncfusion_flutter_gauges/gauges.dart';
import 'package:tetra_stats/gen/strings.g.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'; import 'package:tetra_stats/widgets/stat_sell_num.dart';
var fDiff = NumberFormat("+#,###.###;-#,###.###"); var fDiff = NumberFormat("+#,###.###;-#,###.###");
RangeValues _currentRangeValues = const RangeValues(0, 1);
final DateFormat dateFormat = DateFormat.yMMMd(LocaleSettings.currentLocale.languageCode).add_Hms(); final DateFormat dateFormat = DateFormat.yMMMd(LocaleSettings.currentLocale.languageCode).add_Hms();
final NumberFormat f2 = NumberFormat.decimalPatternDigits(locale: LocaleSettings.currentLocale.languageCode, decimalDigits: 2); final NumberFormat f2 = NumberFormat.decimalPatternDigits(locale: LocaleSettings.currentLocale.languageCode, decimalDigits: 2);
final NumberFormat f3 = NumberFormat.decimalPatternDigits(locale: LocaleSettings.currentLocale.languageCode, decimalDigits: 3); final NumberFormat f3 = NumberFormat.decimalPatternDigits(locale: LocaleSettings.currentLocale.languageCode, decimalDigits: 3);
late RangeValues _currentRangeValues;
TetraLeagueAlpha? oldTl; TetraLeagueAlpha? oldTl;
late TetraLeagueAlpha currentTl; late TetraLeagueAlpha currentTl;
late List<TetrioPlayer> sortedStates; late List<TetrioPlayer> sortedStates;
@ -31,8 +31,13 @@ class _TLThingyState extends State<TLThingy> {
@override @override
void initState() { void initState() {
_currentRangeValues = const RangeValues(0, 1);
sortedStates = widget.states.reversed.toList(); sortedStates = widget.states.reversed.toList();
try{
oldTl = sortedStates[1].tlSeason1; oldTl = sortedStates[1].tlSeason1;
}on RangeError{
oldTl = null;
}
currentTl = widget.tl; currentTl = widget.tl;
super.initState(); super.initState();
} }
@ -52,7 +57,7 @@ class _TLThingyState extends State<TLThingy> {
? [ ? [
if (widget.showTitle) Text(t.tetraLeague, style: TextStyle(fontFamily: "Eurostile Round Extended", fontSize: bigScreen ? 42 : 28)), 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))), 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( labels: RangeLabels(
_currentRangeValues.start.round().toString(), _currentRangeValues.start.round().toString(),
_currentRangeValues.end.round().toString(), _currentRangeValues.end.round().toString(),
@ -400,158 +405,7 @@ class _TLThingyState extends State<TLThingy> {
), ),
), ),
), ),
if (currentTl.nerdStats != null) if (currentTl.nerdStats != null) Graphs(currentTl.apm!, currentTl.pps!, currentTl.vs!, currentTl.nerdStats!, currentTl.playstyle!)
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
),
),
),
],
)
] ]
: [ : [
Text(t.neverPlayedTL, style: const TextStyle(fontFamily: "Eurostile Round Extended", fontSize: 28)), Text(t.neverPlayedTL, style: const TextStyle(fontFamily: "Eurostile Round Extended", fontSize: 28)),

211
lib/widgets/vs_graphs.dart Normal file
View File

@ -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
),
),
),
],
);
}
}