Delta for Tetra League

This commit is contained in:
dan63047 2023-06-28 19:50:40 +03:00
parent 3199bd26ec
commit fd78cf2301
6 changed files with 215 additions and 65 deletions

View File

@ -100,7 +100,7 @@ class TetrioPlayer {
country = json['country'];
supporterTier = json['supporter_tier'];
verified = json['verified'];
tlSeason1 = TetraLeagueAlpha.fromJson(json['league']);
tlSeason1 = TetraLeagueAlpha.fromJson(json['league'], stateTime);
avatarRevision = json['avatar_revision'];
bannerRevision = json['banner_revision'];
bio = json['bio'];
@ -479,12 +479,13 @@ class EstTr {
late double esttr;
late double srarea;
late double statrank;
late double estglicko;
EstTr(this._apm, this._pps, this._vs, this._rd, this._app, this._dss, this._dsp, this._gbe) {
srarea = (_apm * 0) + (_pps * 135) + (_vs * 0) + (_app * 290) + (_dss * 0) + (_dsp * 700) + (_gbe * 0);
statrank = 11.2 * atan((srarea - 93) / 130) + 1;
if (statrank <= 0) statrank = 0.001;
double estglicko = (4.0867 * srarea + 186.68);
estglicko = (4.0867 * srarea + 186.68);
double temp = (1500 - estglicko) * pi;
double temp2 = pow((15.9056943314 * (pow(_rd, 2)) + 3527584.25978), 0.5) as double;
double temp3 = 1 + pow(10, (temp / temp2)) as double;
@ -644,6 +645,7 @@ class EndContextMulti {
}
class TetraLeagueAlpha {
late DateTime timestamp;
late int gamesPlayed;
late int gamesWon;
late String bestRank;
@ -692,7 +694,8 @@ class TetraLeagueAlpha {
double get winrate => gamesWon / gamesPlayed;
TetraLeagueAlpha.fromJson(Map<String, dynamic> json) {
TetraLeagueAlpha.fromJson(Map<String, dynamic> json, ts) {
timestamp = ts;
gamesPlayed = json['gamesplayed'];
gamesWon = json['gameswon'];
rating = json['rating'].toDouble();
@ -833,14 +836,16 @@ class Distinguishment {
class TetrioPlayersLeaderboard {
late String type;
late DateTime timestamp;
late List<TetrioPlayerFromLeaderboard> leaderboard;
TetrioPlayersLeaderboard(this.type, this.leaderboard);
TetrioPlayersLeaderboard.fromJson(Map<String, dynamic> json, String type) {
TetrioPlayersLeaderboard.fromJson(Map<String, dynamic> json, String type, DateTime ts) {
type = type;
timestamp = ts;
for (Map<String, dynamic> entry in json['users']) {
leaderboard.add(TetrioPlayerFromLeaderboard.fromJson(entry));
leaderboard.add(TetrioPlayerFromLeaderboard.fromJson(entry, ts));
}
}
}
@ -857,7 +862,7 @@ class TetrioPlayerFromLeaderboard {
TetrioPlayerFromLeaderboard(this.userId, this.username, this.role, this.xp, this.country, this.supporter, this.verified, this.league);
TetrioPlayerFromLeaderboard.fromJson(Map<String, dynamic> json) {
TetrioPlayerFromLeaderboard.fromJson(Map<String, dynamic> json, DateTime ts) {
userId = json['_id'];
username = json['username'];
role = json['role'];
@ -865,6 +870,6 @@ class TetrioPlayerFromLeaderboard {
country = json['country '];
supporter = json['supporter'];
verified = json['verified'];
league = TetraLeagueAlpha.fromJson(json['league']);
league = TetraLeagueAlpha.fromJson(json['league'], ts);
}
}

View File

@ -10,7 +10,7 @@ List<DropdownMenuItem<TetrioPlayer>>? greenSideStates;
TetrioPlayer? theRedSide;
List<DropdownMenuItem<TetrioPlayer>>? redSideStates;
final TetrioService teto = TetrioService();
final DateFormat dateFormat = DateFormat.yMMMd().add_Hms();
final DateFormat dateFormat = DateFormat.yMd().add_Hm();
class CompareView extends StatefulWidget {
final TetrioPlayer greenSide;
@ -794,6 +794,23 @@ class CompareState extends State<CompareView> {
fractionDigits: 2,
higherIsBetter: true,
),
CompareThingy(
label: "By Est. TR",
greenSide: getWinrateByTR(
theGreenSide!.tlSeason1.estTr!.estglicko,
theGreenSide!.tlSeason1.rd!,
theRedSide!.tlSeason1.estTr!.estglicko,
theRedSide!.tlSeason1.rd!) *
100,
redSide: getWinrateByTR(
theRedSide!.tlSeason1.estTr!.estglicko,
theRedSide!.tlSeason1.rd!,
theGreenSide!.tlSeason1.estTr!.estglicko,
theGreenSide!.tlSeason1.rd!) *
100,
fractionDigits: 2,
higherIsBetter: true,
),
],
)
],
@ -858,6 +875,7 @@ class PlayerSelector extends StatelessWidget {
child: DropdownButton(
items: states,
value: player,
//style: TextStyle(overflow: TextOverflow.clip),
onChanged: (value) => change(value!),
),
)

View File

@ -118,28 +118,35 @@ class _MainState extends State<MainView> with SingleTickerProviderStateMixin {
List<TetraLeagueAlphaRecord> tlMatches = [];
bool isTracking = await teto.isPlayerTracking(me.userId);
List<TetrioPlayer> states = [];
TetraLeagueAlpha? compareWith = null;
var uniqueTL = Set();
if (isTracking){
teto.storeState(me);
teto.saveTLMatchesFromStream(await teto.getTLStream(me.userId));
states.addAll(await teto.getPlayer(me.userId));
states.forEach((element) {
if (uniqueTL.isNotEmpty && uniqueTL.last != element.tlSeason1) uniqueTL.add(element.tlSeason1);
if (uniqueTL.isEmpty) uniqueTL.add(element.tlSeason1);
});
compareWith = uniqueTL.toList()[uniqueTL.length - 2];
chartsData = <DropdownMenuItem<List<FlSpot>>>[
DropdownMenuItem(value: [for (var state in states) if (state.tlSeason1.gamesPlayed > 9) FlSpot(state.state.millisecondsSinceEpoch.toDouble(), state.tlSeason1.rating)], child: const Text("Tetra Rating")),
DropdownMenuItem(value: [for (var state in states) if (state.tlSeason1.gamesPlayed > 9) FlSpot(state.state.millisecondsSinceEpoch.toDouble(), state.tlSeason1.glicko!)], child: const Text("Glicko")),
DropdownMenuItem(value: [for (var state in states) if (state.tlSeason1.gamesPlayed > 9) FlSpot(state.state.millisecondsSinceEpoch.toDouble(), state.tlSeason1.rd!)], child: const Text("Rating Deviation")),
DropdownMenuItem(value: [for (var state in states) if (state.tlSeason1.apm != null) FlSpot(state.state.millisecondsSinceEpoch.toDouble(), state.tlSeason1.apm!)], child: const Text("Attack Per Minute")),
DropdownMenuItem(value: [for (var state in states) if (state.tlSeason1.pps != null) FlSpot(state.state.millisecondsSinceEpoch.toDouble(), state.tlSeason1.pps!)], child: const Text("Pieces Per Second")),
DropdownMenuItem(value: [for (var state in states) if (state.tlSeason1.vs != null) FlSpot(state.state.millisecondsSinceEpoch.toDouble(), state.tlSeason1.vs!)], child: const Text("Versus Score")),
DropdownMenuItem(value: [for (var state in states) if (state.tlSeason1.nerdStats != null) FlSpot(state.state.millisecondsSinceEpoch.toDouble(), state.tlSeason1.nerdStats!.app)], child: const Text("Attack Per Piece")),
DropdownMenuItem(value: [for (var state in states) if (state.tlSeason1.nerdStats != null) FlSpot(state.state.millisecondsSinceEpoch.toDouble(), state.tlSeason1.nerdStats!.dss)], child: const Text("Downstack Per Second")),
DropdownMenuItem(value: [for (var state in states) if (state.tlSeason1.nerdStats != null) FlSpot(state.state.millisecondsSinceEpoch.toDouble(), state.tlSeason1.nerdStats!.dsp)], child: const Text("Downstack Per Piece")),
DropdownMenuItem(value: [for (var state in states) if (state.tlSeason1.nerdStats != null) FlSpot(state.state.millisecondsSinceEpoch.toDouble(), state.tlSeason1.nerdStats!.appdsp)], child: const Text("APP + DS/P")),
DropdownMenuItem(value: [for (var state in states) if (state.tlSeason1.nerdStats != null) FlSpot(state.state.millisecondsSinceEpoch.toDouble(), state.tlSeason1.nerdStats!.vsapm)], child: const Text("VS/APM")),
DropdownMenuItem(value: [for (var state in states) if (state.tlSeason1.nerdStats != null) FlSpot(state.state.millisecondsSinceEpoch.toDouble(), state.tlSeason1.nerdStats!.cheese)], child: const Text("Cheese Index")),
DropdownMenuItem(value: [for (var state in states) if (state.tlSeason1.nerdStats != null) FlSpot(state.state.millisecondsSinceEpoch.toDouble(), state.tlSeason1.nerdStats!.gbe)], child: const Text("Garbage Efficiency")),
DropdownMenuItem(value: [for (var state in states) if (state.tlSeason1.nerdStats != null) FlSpot(state.state.millisecondsSinceEpoch.toDouble(), state.tlSeason1.nerdStats!.nyaapp)], child: const Text("Weighted APP")),
DropdownMenuItem(value: [for (var state in states) if (state.tlSeason1.nerdStats != null) FlSpot(state.state.millisecondsSinceEpoch.toDouble(), state.tlSeason1.nerdStats!.area)], child: const Text("Area")),
DropdownMenuItem(value: [for (var state in states) if (state.tlSeason1.estTr != null) FlSpot(state.state.millisecondsSinceEpoch.toDouble(), state.tlSeason1.estTr!.esttr)], child: const Text("Est. of TR")),
DropdownMenuItem(value: [for (var state in states) if (state.tlSeason1.esttracc != null) FlSpot(state.state.millisecondsSinceEpoch.toDouble(), state.tlSeason1.esttracc!)], child: const Text("Accuracy of Est.")),
DropdownMenuItem(value: [for (var tl in uniqueTL) if (tl.gamesPlayed > 9) FlSpot(tl.timestamp.millisecondsSinceEpoch.toDouble(), tl.rating)], child: const Text("Tetra Rating")),
DropdownMenuItem(value: [for (var tl in uniqueTL) if (tl.gamesPlayed > 9) FlSpot(tl.timestamp.millisecondsSinceEpoch.toDouble(), tl.glicko!)], child: const Text("Glicko")),
DropdownMenuItem(value: [for (var tl in uniqueTL) if (tl.gamesPlayed > 9) FlSpot(tl.timestamp.millisecondsSinceEpoch.toDouble(), tl.rd!)], child: const Text("Rating Deviation")),
DropdownMenuItem(value: [for (var tl in uniqueTL) if (tl.apm != null) FlSpot(tl.timestamp.millisecondsSinceEpoch.toDouble(), tl.apm!)], child: const Text("Attack Per Minute")),
DropdownMenuItem(value: [for (var tl in uniqueTL) if (tl.pps != null) FlSpot(tl.timestamp.millisecondsSinceEpoch.toDouble(), tl.pps!)], child: const Text("Pieces Per Second")),
DropdownMenuItem(value: [for (var tl in uniqueTL) if (tl.vs != null) FlSpot(tl.timestamp.millisecondsSinceEpoch.toDouble(), tl.vs!)], child: const Text("Versus Score")),
DropdownMenuItem(value: [for (var tl in uniqueTL) if (tl.nerdStats != null) FlSpot(tl.timestamp.millisecondsSinceEpoch.toDouble(), tl.nerdStats!.app)], child: const Text("Attack Per Piece")),
DropdownMenuItem(value: [for (var tl in uniqueTL) if (tl.nerdStats != null) FlSpot(tl.timestamp.millisecondsSinceEpoch.toDouble(), tl.nerdStats!.dss)], child: const Text("Downstack Per Second")),
DropdownMenuItem(value: [for (var tl in uniqueTL) if (tl.nerdStats != null) FlSpot(tl.timestamp.millisecondsSinceEpoch.toDouble(), tl.nerdStats!.dsp)], child: const Text("Downstack Per Piece")),
DropdownMenuItem(value: [for (var tl in uniqueTL) if (tl.nerdStats != null) FlSpot(tl.timestamp.millisecondsSinceEpoch.toDouble(), tl.nerdStats!.appdsp)], child: const Text("APP + DS/P")),
DropdownMenuItem(value: [for (var tl in uniqueTL) if (tl.nerdStats != null) FlSpot(tl.timestamp.millisecondsSinceEpoch.toDouble(), tl.nerdStats!.vsapm)], child: const Text("VS/APM")),
DropdownMenuItem(value: [for (var tl in uniqueTL) if (tl.nerdStats != null) FlSpot(tl.timestamp.millisecondsSinceEpoch.toDouble(), tl.nerdStats!.cheese)], child: const Text("Cheese Index")),
DropdownMenuItem(value: [for (var tl in uniqueTL) if (tl.nerdStats != null) FlSpot(tl.timestamp.millisecondsSinceEpoch.toDouble(), tl.nerdStats!.gbe)], child: const Text("Garbage Efficiency")),
DropdownMenuItem(value: [for (var tl in uniqueTL) if (tl.nerdStats != null) FlSpot(tl.timestamp.millisecondsSinceEpoch.toDouble(), tl.nerdStats!.nyaapp)], child: const Text("Weighted APP")),
DropdownMenuItem(value: [for (var tl in uniqueTL) if (tl.nerdStats != null) FlSpot(tl.timestamp.millisecondsSinceEpoch.toDouble(), tl.nerdStats!.area)], child: const Text("Area")),
DropdownMenuItem(value: [for (var tl in uniqueTL) if (tl.estTr != null) FlSpot(tl.timestamp.millisecondsSinceEpoch.toDouble(), tl.estTr!.esttr)], child: const Text("Est. of TR")),
DropdownMenuItem(value: [for (var tl in uniqueTL) if (tl.esttracc != null) FlSpot(tl.timestamp.millisecondsSinceEpoch.toDouble(), tl.esttracc!)], child: const Text("Accuracy of Est.")),
];
tlMatches.addAll(await teto.getTLMatchesbyPlayerID(me.userId));
for (var match in tlStream.records) {
@ -155,7 +162,7 @@ class _MainState extends State<MainView> with SingleTickerProviderStateMixin {
tlMatches = tlStream.records;
}
Map<String, dynamic> records = await teto.fetchRecords(me.userId);
return [me, records, states, tlMatches, isTracking];
return [me, records, states, tlMatches, compareWith, isTracking];
}
void _justUpdate() {
@ -289,7 +296,8 @@ class _MainState extends State<MainView> with SingleTickerProviderStateMixin {
children: [
TLThingy(
tl: snapshot.data![0].tlSeason1,
userID: snapshot.data![0].userId),
userID: snapshot.data![0].userId,
oldTl: snapshot.data![4],),
_TLRecords(userID: snapshot.data![0].userId, data: snapshot.data![3]),
_History(states: snapshot.data![2], update: _justUpdate),
_RecordThingy(
@ -588,7 +596,8 @@ class _RecordThingy extends StatelessWidget {
StatCellNum(
playerStat: record!.rank!,
playerStatLabel: "Leaderboard Placement",
isScreenBig: bigScreen),
isScreenBig: bigScreen,
higherIsBetter: false),
Text("Obtained ${dateFormat.format(record!.timestamp!)}",
textAlign: TextAlign.center,
style: const TextStyle(
@ -608,46 +617,55 @@ class _RecordThingy extends StatelessWidget {
StatCellNum(
playerStat: record!.endContext!.level,
playerStatLabel: "Level",
isScreenBig: bigScreen),
isScreenBig: bigScreen,
higherIsBetter: true,),
if (record!.stream.contains("blitz"))
StatCellNum(
playerStat: record!.endContext!.spp,
playerStatLabel: "Score\nPer Piece",
fractionDigits: 2,
isScreenBig: bigScreen),
isScreenBig: bigScreen,
higherIsBetter: true,),
StatCellNum(
playerStat: record!.endContext!.piecesPlaced,
playerStatLabel: "Pieces\nPlaced",
isScreenBig: bigScreen),
isScreenBig: bigScreen,
higherIsBetter: true,),
StatCellNum(
playerStat: record!.endContext!.pps,
playerStatLabel: "Pieces\nPer Second",
fractionDigits: 2,
isScreenBig: bigScreen),
isScreenBig: bigScreen,
higherIsBetter: true,),
StatCellNum(
playerStat: record!.endContext!.finesse.faults,
playerStatLabel: "Finesse\nFaults",
isScreenBig: bigScreen),
isScreenBig: bigScreen,
higherIsBetter: false,),
StatCellNum(
playerStat:
record!.endContext!.finessePercentage * 100,
playerStatLabel: "Finesse\nPercentage",
fractionDigits: 2,
isScreenBig: bigScreen),
isScreenBig: bigScreen,
higherIsBetter: true,),
StatCellNum(
playerStat: record!.endContext!.inputs,
playerStatLabel: "Key\nPresses",
isScreenBig: bigScreen),
isScreenBig: bigScreen,
higherIsBetter: false,),
StatCellNum(
playerStat: record!.endContext!.kpp,
playerStatLabel: "KP Per\nPiece",
fractionDigits: 2,
isScreenBig: bigScreen),
isScreenBig: bigScreen,
higherIsBetter: false,),
StatCellNum(
playerStat: record!.endContext!.kps,
playerStatLabel: "KP Per\nSecond",
fractionDigits: 2,
isScreenBig: bigScreen),
isScreenBig: bigScreen,
higherIsBetter: true,),
],
),
),

View File

@ -8,9 +8,11 @@ class StatCellNum extends StatelessWidget {
required this.playerStatLabel,
required this.isScreenBig,
this.alertWidgets,
this.fractionDigits});
this.fractionDigits, this.oldPlayerStat, required this.higherIsBetter});
final num playerStat;
final num? oldPlayerStat;
final bool higherIsBetter;
final String playerStatLabel;
final bool isScreenBig;
final List<Widget>? alertWidgets;
@ -29,6 +31,11 @@ class StatCellNum extends StatelessWidget {
fontSize: isScreenBig ? 32 : 24,
),
),
if (oldPlayerStat != null) Text(NumberFormat("+#,###.###;-#,###.###").format(playerStat - oldPlayerStat!), style: TextStyle(
color: higherIsBetter ?
oldPlayerStat! > playerStat ? Colors.red : Colors.green :
oldPlayerStat! < playerStat ? Colors.red : Colors.green
),),
alertWidgets == null
? Text(
playerStatLabel,

View File

@ -3,6 +3,7 @@ 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/services/tetrio_crud.dart';
import 'package:tetra_stats/widgets/stat_sell_num.dart';
var fDiff = NumberFormat("+#,###.###;-#,###.###");
@ -12,7 +13,8 @@ final NumberFormat f3 = NumberFormat.decimalPatternDigits(decimalDigits: 3);
class TLThingy extends StatelessWidget {
final TetraLeagueAlpha tl;
final String userID;
const TLThingy({Key? key, required this.tl, required this.userID}) : super(key: key);
final TetraLeagueAlpha? oldTl;
const TLThingy({Key? key, required this.tl, required this.userID, this.oldTl}) : super(key: key);
@override
Widget build(BuildContext context) {
@ -26,6 +28,7 @@ class TLThingy extends StatelessWidget {
children: (tl.gamesPlayed > 0)
? [
Text("Tetra League", style: TextStyle(fontFamily: "Eurostile Round Extended", fontSize: bigScreen ? 42 : 28)),
if (oldTl != null) Text("Comparing with data from ${DateFormat.yMMMd().add_Hms().format(oldTl!.timestamp)}"),
if (tl.gamesPlayed >= 10)
Wrap(
direction: Axis.horizontal,
@ -39,6 +42,15 @@ class TLThingy extends StatelessWidget {
Column(
children: [
Text("${f2.format(tl.rating)} TR", style: TextStyle(fontFamily: "Eurostile Round Extended", fontSize: bigScreen ? 42 : 28)),
if (oldTl != null) Text(
"${fDiff.format(tl.rating - oldTl!.rating)} TR",
textAlign: TextAlign.center,
style: TextStyle(
color: tl.rating - oldTl!.rating < 0 ?
Colors.red :
Colors.green
),
),
Text(
"Top ${f2.format(tl.percentile * 100)}% (${tl.percentileRank.toUpperCase()}) • Top Rank: ${tl.bestRank.toUpperCase()} • Glicko: ${f2.format(tl.glicko!)}±${f2.format(tl.rd!)}${tl.decaying ? ' • Decaying' : ''}",
textAlign: TextAlign.center,
@ -80,15 +92,15 @@ class TLThingy extends StatelessWidget {
clipBehavior: Clip.hardEdge,
children: [
if (tl.apm != null)
StatCellNum(playerStat: tl.apm!, isScreenBig: bigScreen, fractionDigits: 2, playerStatLabel: "Attack\nPer Minute"),
StatCellNum(playerStat: tl.apm!, isScreenBig: bigScreen, fractionDigits: 2, playerStatLabel: "Attack\nPer Minute", higherIsBetter: true, oldPlayerStat: oldTl?.apm),
if (tl.pps != null)
StatCellNum(playerStat: tl.pps!, isScreenBig: bigScreen, fractionDigits: 2, playerStatLabel: "Pieces\nPer Second"),
if (tl.apm != null) StatCellNum(playerStat: tl.vs!, isScreenBig: bigScreen, fractionDigits: 2, playerStatLabel: "Versus\nScore"),
if (tl.standing > 0) StatCellNum(playerStat: tl.standing, isScreenBig: bigScreen, playerStatLabel: "Leaderboard\nplacement"),
if (tl.standingLocal > 0) StatCellNum(playerStat: tl.standingLocal, isScreenBig: bigScreen, playerStatLabel: "Country LB\nplacement"),
StatCellNum(playerStat: tl.gamesPlayed, isScreenBig: bigScreen, playerStatLabel: "Games\nplayed"),
StatCellNum(playerStat: tl.gamesWon, isScreenBig: bigScreen, playerStatLabel: "Games\nwon"),
StatCellNum(playerStat: tl.winrate * 100, isScreenBig: bigScreen, fractionDigits: 2, playerStatLabel: "Winrate\nprecentage"),
StatCellNum(playerStat: tl.pps!, isScreenBig: bigScreen, fractionDigits: 2, playerStatLabel: "Pieces\nPer Second", higherIsBetter: true, oldPlayerStat: oldTl?.pps),
if (tl.vs != null) StatCellNum(playerStat: tl.vs!, isScreenBig: bigScreen, fractionDigits: 2, playerStatLabel: "Versus\nScore", higherIsBetter: true, oldPlayerStat: oldTl?.vs),
if (tl.standing > 0) StatCellNum(playerStat: tl.standing, isScreenBig: bigScreen, playerStatLabel: "Leaderboard\nplacement", higherIsBetter: false, oldPlayerStat: oldTl?.standing),
if (tl.standingLocal > 0) StatCellNum(playerStat: tl.standingLocal, isScreenBig: bigScreen, playerStatLabel: "Country LB\nplacement", higherIsBetter: false, oldPlayerStat: oldTl?.standingLocal),
StatCellNum(playerStat: tl.gamesPlayed, isScreenBig: bigScreen, playerStatLabel: "Games\nplayed", higherIsBetter: true, oldPlayerStat: oldTl?.gamesPlayed),
StatCellNum(playerStat: tl.gamesWon, isScreenBig: bigScreen, playerStatLabel: "Games\nwon", higherIsBetter: true, oldPlayerStat: oldTl?.gamesWon),
StatCellNum(playerStat: tl.winrate * 100, isScreenBig: bigScreen, fractionDigits: 2, playerStatLabel: "Winrate\nprecentage", higherIsBetter: true, oldPlayerStat: oldTl != null ? oldTl!.winrate*100 : null),
],
),
),
@ -116,7 +128,7 @@ class TLThingy extends StatelessWidget {
showLabels: false,
showTicks: false,
radiusFactor: 2.1,
centerY: 0.3,
centerY: 0.4,
minimum: 0,
maximum: 1,
ranges: [
@ -136,7 +148,37 @@ class TLThingy extends StatelessWidget {
knobStyle: const KnobStyle(color: Colors.transparent),
gradient: const LinearGradient(colors: [Colors.transparent, Colors.white], begin: Alignment.bottomCenter, end: Alignment.topCenter, stops: [0.5, 1]),)
],
annotations: [GaugeAnnotation(widget: Text(f3.format(tl.nerdStats!.app), style: const TextStyle(fontFamily: "Eurostile Round Extended", fontSize: 36)))],
annotations: [GaugeAnnotation(
widget: TextButton(child: Text(f3.format(tl.nerdStats!.app),
style: const TextStyle(fontFamily: "Eurostile Round Extended", fontSize: 36, color: Colors.white)),
onPressed: (){
showDialog(
context: context,
builder: (BuildContext context) => AlertDialog(
title: const Text("Attack Per Piece",
style: TextStyle(
fontFamily: "Eurostile Round Extended")),
content: SingleChildScrollView(
child: ListBody(children: [
const Text("Main efficiency metric. Tells how many attack you producing per piece"),
Text("Raw value: ${tl.nerdStats!.app}")
]),
),
actions: <Widget>[
TextButton(
child: const Text('OK'),
onPressed: () {
Navigator.of(context).pop();
},
)
],
));
},), verticalAlignment: GaugeAlignment.far, positionFactor: 0.05,),
if (oldTl != null) GaugeAnnotation(widget: Text(fDiff.format(tl.nerdStats!.app - oldTl!.nerdStats!.app), style: TextStyle(
color: tl.nerdStats!.app - oldTl!.nerdStats!.app < 0 ?
Colors.red :
Colors.green
),), positionFactor: 0.05,)],
)],),
),
SizedBox(
@ -150,7 +192,7 @@ class TLThingy extends StatelessWidget {
showTicks: false,
showLabels: false,
radiusFactor: 2.1,
centerY: 0.3,
centerY: 0.4,
minimum: 1.8,
maximum: 2.4,
ranges: [
@ -168,7 +210,36 @@ class TLThingy extends StatelessWidget {
knobStyle: const KnobStyle(color: Colors.transparent),
gradient: const LinearGradient(colors: [Colors.transparent, Colors.white], begin: Alignment.bottomCenter, end: Alignment.topCenter, stops: [0.5, 1]),)
],
annotations: [GaugeAnnotation(widget: Text(f3.format(tl.nerdStats!.vsapm), style: const TextStyle(fontFamily: "Eurostile Round Extended", fontSize: 36)))],
annotations: [GaugeAnnotation(
widget: TextButton(child: Text(f3.format(tl.nerdStats!.vsapm),
style: const TextStyle(fontFamily: "Eurostile Round Extended", fontSize: 36, color: Colors.white)),
onPressed: (){
showDialog(
context: context,
builder: (BuildContext context) => AlertDialog(
title: const Text("VS / APM",
style: TextStyle(
fontFamily: "Eurostile Round Extended")),
content: const SingleChildScrollView(
child: ListBody(children: [
Text("Basically, tells how much and how efficient you using garbage in your attacks")
]),
),
actions: <Widget>[
TextButton(
child: const Text('OK'),
onPressed: () {
Navigator.of(context).pop();
},
)
],
));
},), verticalAlignment: GaugeAlignment.far, positionFactor: 0.05,),
if (oldTl != null) GaugeAnnotation(widget: Text(fDiff.format(tl.nerdStats!.vsapm - oldTl!.nerdStats!.vsapm), style: TextStyle(
color: tl.nerdStats!.vsapm - oldTl!.nerdStats!.vsapm < 0 ?
Colors.red :
Colors.green
),), positionFactor: 0.05,)],
)],),
),]),
),
@ -179,37 +250,48 @@ class TLThingy extends StatelessWidget {
crossAxisAlignment: WrapCrossAlignment.start,
clipBehavior: Clip.hardEdge,
children: [
//StatCellNum(playerStat: tl.nerdStats!.app, isScreenBig: bigScreen, fractionDigits: 3, playerStatLabel: "Attack\nPer Piece"),
//StatCellNum(playerStat: tl.nerdStats!.vsapm, isScreenBig: bigScreen, fractionDigits: 3, playerStatLabel: "VS/APM"),
StatCellNum(playerStat: tl.nerdStats!.dss, isScreenBig: bigScreen, fractionDigits: 3, playerStatLabel: "Downstack\nPer Second",
alertWidgets: [const Text("Downstack per Second measures how many garbage lines you clear in a second."),
const Text("Formula: (VS / 100) - (APM / 60)"),
Text("(${tl.vs} / 100) - (${tl.apm} / 60) = ${tl.nerdStats!.dss}"),],
),
Text("Raw value: ${tl.nerdStats!.dss}"),],
higherIsBetter: true,
oldPlayerStat: oldTl?.nerdStats?.dss,),
StatCellNum(playerStat: tl.nerdStats!.dsp, isScreenBig: bigScreen, fractionDigits: 3, playerStatLabel: "Downstack\nPer Piece",
alertWidgets: [const Text("Downstack per Piece measures how many garbage lines you clear per piece."),
const Text("Formula: DS/S / PPS"),
Text("${tl.nerdStats!.dss} / ${tl.pps} = ${tl.nerdStats!.dsp}"),],),
Text("Raw value: ${tl.nerdStats!.dsp}"),],
higherIsBetter: true,
oldPlayerStat: oldTl?.nerdStats?.dsp,),
StatCellNum(playerStat: tl.nerdStats!.appdsp, isScreenBig: bigScreen, fractionDigits: 3, playerStatLabel: "APP + DS/P",
alertWidgets: [const Text("Just a sum of Attack per Piece and Downstack per Piece."),
const Text("Formula: APP + DS/P"),
Text("${tl.nerdStats!.app} + ${tl.nerdStats!.dsp} = ${tl.nerdStats!.appdsp}"),]),
Text("Raw value: ${tl.nerdStats!.appdsp}"),],
higherIsBetter: true,
oldPlayerStat: oldTl?.nerdStats?.appdsp,),
StatCellNum(playerStat: tl.nerdStats!.cheese, isScreenBig: bigScreen, fractionDigits: 2, playerStatLabel: "Cheese\nIndex",
alertWidgets: [const Text("Cheese Index is an approximation how much clean / cheese garbage player sends. Lower = more clean. Higher = more cheese.\nInvented by kerrmunism"),
const Text("Formula: (DS/P * 150) + ((VS/APM - 2) * 50) + (0.6 - APP) * 125"),
Text("(${tl.nerdStats!.dsp} * 150) + ((${tl.nerdStats!.vsapm} - 2) * 50) + (0.6 - ${tl.nerdStats!.app}) * 125 = ${tl.nerdStats!.cheese}"),]),
Text("Raw value: ${tl.nerdStats!.cheese}"),],
higherIsBetter: true,
oldPlayerStat: oldTl?.nerdStats?.cheese,),
StatCellNum(playerStat: tl.nerdStats!.gbe, isScreenBig: bigScreen, fractionDigits: 3, playerStatLabel: "Garbage\nEfficiency",
alertWidgets: [const Text("Garbage Efficiency measures how well player uses their garbage. Higher = better or they use their garbage more. Lower = they mostly send their garbage back at cheese or rarely clear garbage.\nInvented by Zepheniah and Dragonboy."),
const Text("Formula: ((APP * DS/S) / PPS) * 2"),
Text("((${tl.nerdStats!.app} * ${tl.nerdStats!.dss}) / ${tl.pps}) * 2 = ${tl.nerdStats!.gbe}"),]),
Text("Raw value: ${tl.nerdStats!.gbe}"),],
higherIsBetter: true,
oldPlayerStat: oldTl?.nerdStats?.gbe,),
StatCellNum(playerStat: tl.nerdStats!.nyaapp, isScreenBig: bigScreen, fractionDigits: 3, playerStatLabel: "Weighted\nAPP",
alertWidgets: [const Text("Essentially, a measure of your ability to send cheese while still maintaining a high APP.\nInvented by Wertj."),
const Text("Formula: APP - 5 * tan(radians((Cheese Index / -30) + 1))"),
Text("${tl.nerdStats!.app} - 5 * tan(radians((${tl.nerdStats!.cheese} / -30) + 1)) = ${tl.nerdStats!.nyaapp}"),]),
Text("Raw value: ${tl.nerdStats!.nyaapp}"),],
higherIsBetter: true,
oldPlayerStat: oldTl?.nerdStats?.nyaapp,),
StatCellNum(playerStat: tl.nerdStats!.area, isScreenBig: bigScreen, fractionDigits: 1, playerStatLabel: "Area",
alertWidgets: [const Text("How much space your shape takes up on the graph, if you exclude the cheese and vs/apm sections"),
const Text("Formula: APM * 1 + PPS * 45 + VS * 0.444 + APP * 185 + DS/S * 175 + DS/P * 450 + Garbage Effi * 315"),
Text("${tl.apm} * 1 + ${tl.pps} * 45 + ${tl.vs} * 0.444 + ${tl.nerdStats!.app} * 185 + ${tl.nerdStats!.dss} * 175 + ${tl.nerdStats!.dsp} * 450 + ${tl.nerdStats!.gbe} * 315 = ${tl.nerdStats!.area}"),])
Text("Raw value: ${tl.nerdStats!.area}"),],
higherIsBetter: true,
oldPlayerStat: oldTl?.nerdStats?.area,)
])
],
),

View File

@ -176,13 +176,33 @@ class UserThingy extends StatelessWidget {
playerStatLabel: "XP Level",
isScreenBig: bigScreen,
alertWidgets: [Text("${NumberFormat.decimalPatternDigits(decimalDigits: 2).format(player.xp)} XP", style: const TextStyle(fontFamily: "Eurostile Round Extended"),), Text("Progress to next level: ${((player.level - player.level.floor()) * 100).toStringAsFixed(2)} %"), Text("Progress from 0 XP to level 5000: ${((player.xp / 67009017.7589378) * 100).toStringAsFixed(2)} %")],
higherIsBetter: true,
),
if (player.gameTime >= Duration.zero)
StatCellNum(
playerStat: player.gameTime.inHours, playerStatLabel: "Hours\nPlayed", isScreenBig: bigScreen, alertWidgets: [Text("Exact gametime: ${player.gameTime.toString()}")]),
if (player.gamesPlayed >= 0) StatCellNum(playerStat: player.gamesPlayed, isScreenBig: bigScreen, playerStatLabel: "Online\nGames"),
if (player.gamesWon >= 0) StatCellNum(playerStat: player.gamesWon, isScreenBig: bigScreen, playerStatLabel: "Games\nWon"),
if (player.friendCount > 0) StatCellNum(playerStat: player.friendCount, isScreenBig: bigScreen, playerStatLabel: "Friends"),
playerStat: player.gameTime.inHours,
playerStatLabel: "Hours\nPlayed",
isScreenBig: bigScreen,
alertWidgets: [Text("Exact gametime: ${player.gameTime.toString()}")],
higherIsBetter: true,),
if (player.gamesPlayed >= 0)
StatCellNum(
playerStat: player.gamesPlayed,
isScreenBig: bigScreen,
playerStatLabel: "Online\nGames",
higherIsBetter: true,),
if (player.gamesWon >= 0)
StatCellNum(
playerStat: player.gamesWon,
isScreenBig: bigScreen,
playerStatLabel: "Games\nWon",
higherIsBetter: true,),
if (player.friendCount > 0)
StatCellNum(
playerStat: player.friendCount,
isScreenBig: bigScreen,
playerStatLabel: "Friends",
higherIsBetter: true,),
],
)
: Text(