Delta for Tetra League
This commit is contained in:
parent
3199bd26ec
commit
fd78cf2301
|
@ -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);
|
||||
}
|
||||
}
|
||||
|
|
|
@ -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!),
|
||||
),
|
||||
)
|
||||
|
|
|
@ -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,),
|
||||
],
|
||||
),
|
||||
),
|
||||
|
|
|
@ -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,
|
||||
|
|
|
@ -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,)
|
||||
])
|
||||
],
|
||||
),
|
||||
|
|
|
@ -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(
|
||||
|
|
Loading…
Reference in New Issue