TLThingy bug fix + progress bar now can appoximate number of wins/losses

This commit is contained in:
dan63047 2024-05-02 02:12:52 +03:00
parent 7ffe909c2d
commit 6195705dcb
7 changed files with 265 additions and 67 deletions

View File

@ -0,0 +1,147 @@
import 'dart:math';
// I reimplemented kenany/glicko2-lite in dart lol
// Don't look here lol
List<double> scale(double rating, double rd, double options) {
double mu = (rating - options) / 173.7178;
double phi = rd / 173.7178;
return [ mu, phi ];
}
double g(phi) {
return 1 / sqrt(1 + 3 * pow(phi, 2) / pow(pi, 2));
}
double e(double mu, double muj, double phij) {
return 1 / (1 + exp(-g(phij) * (mu - muj)));
}
List<Map<String, double>> scaleOpponents(double mu, List<List<double>> opponents, double rating) {
return opponents.map((opp) {
var scaled = scale(opp[0], opp[1], rating);
return {
"muj": scaled[0],
"phij": scaled[1],
"gphij": g(scaled[1]),
"emmp": e(mu, scaled[0], scaled[1]),
"score": opp[2]
};
}).toList();
}
double updateRating(List<Map<String, double>> opponents) {
double value = pow(opponents.first["gphij"]!, 2) * opponents.first["emmp"]! * (1 - opponents.first["emmp"]!);
opponents.skip(1).forEach((element) {
value += pow(element["gphij"]!, 2) * element["emmp"]! * (1 - element["emmp"]!);
});
return 1 / value;
}
double computeDelta(v, List<Map<String, double>> opponents) {
double value = opponents.first["gphij"]! * (opponents.first["score"]! - opponents.first["emmp"]!);
opponents.skip(1).forEach((element) {
value += opponents.first["gphij"]! * (opponents.first["score"]! - opponents.first["emmp"]!);
});
return v * value;
}
Function volF(double phi, double v, double delta, double a, double tau) {
num phi2 = pow(phi, 2);
num d2 = pow(delta, 2);
return (x) {
double ex = exp(x);
double a2 = phi2 + v + ex;
double p2 = (x - a) / pow(tau, 2);
double p1 = (ex * (d2 - phi2 - v - ex)) / (2 * pow(a2, 2));
return p1 - p2;
};
}
double computeVolatility(double sigma, double phi, double v, double delta, double options) {
// 5.1
double a = log(pow(sigma, 2));
Function f = volF(phi, v, delta, a, options);
// 5.2
double b;
if (pow(delta, 2) > pow(phi, 2) + v) {
b = log(pow(delta, 2) - pow(phi, 2) - v);
}
else {
double k = 1;
while (f(a - k * options) < 0) {
k++;
}
b = a - k * options;
}
// 5.3
double fa = f(a);
double fb = f(b);
// 5.4
while ((b - a).abs() > 0.000001) {
double c = a + (a - b) * fa / (fb - fa);
double fc = f(c);
if (fc * fb <= 0) {
a = b;
fa = fb;
}
else {
fa /= 2;
}
b = c;
fb = fc;
}
// 5.5
return exp(a / 2);
}
double phiStar(sigmap, phi) {
return sqrt(pow(sigmap, 2) + pow(phi, 2));
}
Map<String, double> newRating(phis, mu, v, opponents) {
double phip = 1 / sqrt(1 / pow(phis, 2) + 1 / v);
double value = opponents.first["gphij"]! * (opponents.first["score"]! - opponents.first["emmp"]!);
opponents.skip(1).forEach((element) {
value += element["gphij"]! * (element["score"]! - element["emmp"]!);
});
double mup = mu + pow(phip, 2) * value;
return { "mu": mup, "phi": phip };
}
List<double> unscale(mup, phip, options) {
double rating = 173.7178 * mup + options["rating"];
double rd = 173.7178 * phip;
return [ rating, rd ];
}
List<double> rate(double rating, double rd, double sigma, List<List<double>> opponents, Map<String, double> options) {
Map<String, double> opts = { "rating": options["rating"]??1500, "tau": options["tau"]??0.5 };
// Step 2
List<double> scaled = scale(rating, rd, opts["rating"]!);
List<Map<String, double>> scaledOpponents = scaleOpponents(scaled[0], opponents, opts["rating"]!);
// Step 3
double v = updateRating(scaledOpponents);
// Step 4
double delta = computeDelta(v, scaledOpponents);
// Step 5
double sigmap = computeVolatility(sigma, scaled[1], v, delta, opts["tau"]!);
// Step 6
double phis = phiStar(sigmap, scaled[1]);
// Step 7
Map<String, double> updated = newRating(phis, scaled[0], v, scaledOpponents);
return unscale(updated['mu'], updated['phi'], opts)..add(sigmap);
}

View File

@ -1856,11 +1856,12 @@ class TetrioPlayersLeaderboard {
"avgStride": avgStride, "avgStride": avgStride,
"avgInfDS": avgInfDS, "avgInfDS": avgInfDS,
"toEnterTR": rank.toLowerCase() != "z" ? leaderboard[(leaderboard.length * rankCutoffs[rank]!).floor()-1].rating : lowestTR, "toEnterTR": rank.toLowerCase() != "z" ? leaderboard[(leaderboard.length * rankCutoffs[rank]!).floor()-1].rating : lowestTR,
"toEnterGlicko": rank.toLowerCase() != "z" ? leaderboard[(leaderboard.length * rankCutoffs[rank]!).floor()-1].glicko : 0,
"entries": filtredLeaderboard "entries": filtredLeaderboard
}]; }];
}else{ }else{
return [TetraLeagueAlpha(timestamp: DateTime.now(), apm: 0, pps: 0, vs: 0, glicko: 0, rd: noTrRd, gamesPlayed: 0, gamesWon: 0, bestRank: rank, decaying: false, rating: 0, rank: rank, percentileRank: rank, percentile: rankCutoffs[rank]!, standing: -1, standingLocal: -1, nextAt: -1, prevAt: -1), return [TetraLeagueAlpha(timestamp: DateTime.now(), apm: 0, pps: 0, vs: 0, glicko: 0, rd: noTrRd, gamesPlayed: 0, gamesWon: 0, bestRank: rank, decaying: false, rating: 0, rank: rank, percentileRank: rank, percentile: rankCutoffs[rank]!, standing: -1, standingLocal: -1, nextAt: -1, prevAt: -1),
{"players": filtredLeaderboard.length, "lowestTR": 0, "toEnterTR": 0}]; {"players": filtredLeaderboard.length, "lowestTR": 0, "toEnterTR": 0, "toEnterGlicko": 0}];
} }
} }
@ -1929,6 +1930,26 @@ class TetrioPlayersLeaderboard {
'd': getAverageOfRank("d")[1]["toEnterTR"] 'd': getAverageOfRank("d")[1]["toEnterTR"]
}; };
Map<String, double> get cutoffsGlicko => {
'x': getAverageOfRank("x")[1]["toEnterGlicko"],
'u': getAverageOfRank("u")[1]["toEnterGlicko"],
'ss': getAverageOfRank("ss")[1]["toEnterGlicko"],
's+': getAverageOfRank("s+")[1]["toEnterGlicko"],
's': getAverageOfRank("s")[1]["toEnterGlicko"],
's-': getAverageOfRank("s-")[1]["toEnterGlicko"],
'a+': getAverageOfRank("a+")[1]["toEnterGlicko"],
'a': getAverageOfRank("a")[1]["toEnterGlicko"],
'a-': getAverageOfRank("a-")[1]["toEnterGlicko"],
'b+': getAverageOfRank("b+")[1]["toEnterGlicko"],
'b': getAverageOfRank("b")[1]["toEnterGlicko"],
'b-': getAverageOfRank("b-")[1]["toEnterGlicko"],
'c+': getAverageOfRank("c+")[1]["toEnterGlicko"],
'c': getAverageOfRank("c")[1]["toEnterGlicko"],
'c-': getAverageOfRank("c-")[1]["toEnterGlicko"],
'd+': getAverageOfRank("d+")[1]["toEnterGlicko"],
'd': getAverageOfRank("d")[1]["toEnterGlicko"]
};
TetrioPlayersLeaderboard.fromJson(List<dynamic> json, String t, DateTime ts) { TetrioPlayersLeaderboard.fromJson(List<dynamic> json, String t, DateTime ts) {
type = t; type = t;
timestamp = ts; timestamp = ts;

View File

@ -86,6 +86,8 @@ class _MainState extends State<MainView> with TickerProviderStateMixin {
TetraLeagueAlpha? rankAverages; TetraLeagueAlpha? rankAverages;
double? thatRankCutoff; double? thatRankCutoff;
double? nextRankCutoff; double? nextRankCutoff;
double? thatRankGlickoCutoff;
double? nextRankGlickoCutoff;
String _searchFor = "6098518e3d5155e6ec429cdc"; // who we looking for String _searchFor = "6098518e3d5155e6ec429cdc"; // who we looking for
String _titleNickname = ""; String _titleNickname = "";
/// Each dropdown menu item contains list of dots for the graph /// Each dropdown menu item contains list of dots for the graph
@ -198,8 +200,11 @@ class _MainState extends State<MainView> with TickerProviderStateMixin {
} }
if (me.tlSeason1.gamesPlayed > 9) { if (me.tlSeason1.gamesPlayed > 9) {
thatRankCutoff = everyone!.cutoffs[me.tlSeason1.rank != "z" ? me.tlSeason1.rank : me.tlSeason1.percentileRank]; thatRankCutoff = everyone!.cutoffs[me.tlSeason1.rank != "z" ? me.tlSeason1.rank : me.tlSeason1.percentileRank];
thatRankGlickoCutoff = everyone!.cutoffsGlicko[me.tlSeason1.rank != "z" ? me.tlSeason1.rank : me.tlSeason1.percentileRank];
nextRankCutoff = everyone!.cutoffs[ranks.elementAtOrNull(ranks.indexOf(me.tlSeason1.rank != "z" ? me.tlSeason1.rank : me.tlSeason1.percentileRank)+1)]; nextRankCutoff = everyone!.cutoffs[ranks.elementAtOrNull(ranks.indexOf(me.tlSeason1.rank != "z" ? me.tlSeason1.rank : me.tlSeason1.percentileRank)+1)];
nextRankGlickoCutoff = everyone!.cutoffsGlicko[ranks.elementAtOrNull(ranks.indexOf(me.tlSeason1.rank != "z" ? me.tlSeason1.rank : me.tlSeason1.percentileRank)+1)];
nextRankCutoff = nextRankCutoff??25000; nextRankCutoff = nextRankCutoff??25000;
nextRankGlickoCutoff = nextRankGlickoCutoff??double.infinity;
} }
} }
@ -272,7 +277,6 @@ class _MainState extends State<MainView> with TickerProviderStateMixin {
// Also i need previous Tetra League State for comparison if avaliable // Also i need previous Tetra League State for comparison if avaliable
if (uniqueTL.length >= 2){ if (uniqueTL.length >= 2){
compareWith = uniqueTL.toList().elementAtOrNull(uniqueTL.length - 2); compareWith = uniqueTL.toList().elementAtOrNull(uniqueTL.length - 2);
//chartsData = [for (var tl in uniqueTL) _HistoryChartSpot(tl.timestamp, tl.gamesPlayed, tl.rank, [tl.rating, tl.glicko, tl.rd, tl.apm, tl.pps, tl.vs, tl.nerdStats?.app, tl.nerdStats?.dss, tl.nerdStats?.dsp, tl.nerdStats?.appdsp, tl.nerdStats?.vsapm, tl.nerdStats?.cheese, tl.nerdStats?.gbe, tl.nerdStats?.nyaapp, tl.nerdStats?.area, tl.estTr?.esttr, tl.esttracc, tl.playstyle?.opener, tl.playstyle?.plonk, tl.playstyle?.infds, tl.playstyle?.stride])];
chartsData = <DropdownMenuItem<List<_HistoryChartSpot>>>[ // Dumping charts data into dropdown menu items, while cheking if every entry is valid chartsData = <DropdownMenuItem<List<_HistoryChartSpot>>>[ // Dumping charts data into dropdown menu items, while cheking if every entry is valid
DropdownMenuItem(value: [for (var tl in uniqueTL) if (tl.gamesPlayed > 9) _HistoryChartSpot(tl.timestamp, tl.gamesPlayed, tl.rank, tl.rating)], child: Text(t.statCellNum.tr)), DropdownMenuItem(value: [for (var tl in uniqueTL) if (tl.gamesPlayed > 9) _HistoryChartSpot(tl.timestamp, tl.gamesPlayed, tl.rank, tl.rating)], child: Text(t.statCellNum.tr)),
DropdownMenuItem(value: [for (var tl in uniqueTL) if (tl.gamesPlayed > 9) _HistoryChartSpot(tl.timestamp, tl.gamesPlayed, tl.rank, tl.glicko!)], child: const Text("Glicko")), DropdownMenuItem(value: [for (var tl in uniqueTL) if (tl.gamesPlayed > 9) _HistoryChartSpot(tl.timestamp, tl.gamesPlayed, tl.rank, tl.glicko!)], child: const Text("Glicko")),
@ -455,9 +459,11 @@ class _MainState extends State<MainView> with TickerProviderStateMixin {
bot: snapshot.data![0].role == "bot", bot: snapshot.data![0].role == "bot",
guest: snapshot.data![0].role == "anon", guest: snapshot.data![0].role == "anon",
thatRankCutoff: thatRankCutoff, thatRankCutoff: thatRankCutoff,
thatRankCutoffGlicko: thatRankGlickoCutoff,
thatRankTarget: snapshot.data![0].tlSeason1.rank != "z" ? rankTargets[snapshot.data![0].tlSeason1.rank] : null, thatRankTarget: snapshot.data![0].tlSeason1.rank != "z" ? rankTargets[snapshot.data![0].tlSeason1.rank] : null,
nextRankCutoff: nextRankCutoff, nextRankCutoff: nextRankCutoff,
nextRankTarget: snapshot.data![0].tlSeason1.rank != "z" || snapshot.data![0].tlSeason1.rank != "x" ? rankTargets[ranks.elementAtOrNull(ranks.indexOf(snapshot.data![0].tlSeason1.rank)+1)] : null, nextRankCutoffGlicko: nextRankGlickoCutoff,
nextRankTarget: (snapshot.data![0].tlSeason1.rank != "z" && snapshot.data![0].tlSeason1.rank != "x") ? rankTargets[ranks.elementAtOrNull(ranks.indexOf(snapshot.data![0].tlSeason1.rank)+1)] : null,
averages: rankAverages, averages: rankAverages,
lbPositions: meAmongEveryone lbPositions: meAmongEveryone
), ),
@ -934,26 +940,44 @@ class _HistoryChartThigyState extends State<_HistoryChartThigy> {
child: SfCartesianChart( child: SfCartesianChart(
tooltipBehavior: _tooltipBehavior, tooltipBehavior: _tooltipBehavior,
zoomPanBehavior: _zoomPanBehavior, zoomPanBehavior: _zoomPanBehavior,
primaryXAxis: DateTimeAxis(), primaryXAxis: _gamesPlayedInsteadOfDateAndTime ? NumericAxis() : DateTimeAxis(),
primaryYAxis: NumericAxis( primaryYAxis: NumericAxis(
rangePadding: ChartRangePadding.additional, rangePadding: ChartRangePadding.additional,
), ),
series: <CartesianSeries>[ series: <CartesianSeries>[
StepLineSeries<_HistoryChartSpot, DateTime>( if (_gamesPlayedInsteadOfDateAndTime) StepLineSeries<_HistoryChartSpot, int>(
enableTooltip: true, enableTooltip: true,
// splineType: SplineType.cardinal, // splineType: SplineType.cardinal,
// cardinalSplineTension: 0.2, // cardinalSplineTension: 0.2,
dataSource: widget.data, dataSource: widget.data,
animationDuration: 0, animationDuration: 0,
opacity: 1, opacity: _smooth ? 0 : 1,
xValueMapper: (_HistoryChartSpot data, _) => data.gamesPlayed,
yValueMapper: (_HistoryChartSpot data, _) => data.stat,
trendlines:<Trendline>[
Trendline(
isVisible: _smooth,
period: (widget.data.length/175).floor(),
type: TrendlineType.movingAverage,
color: Colors.blue)
],
)
else StepLineSeries<_HistoryChartSpot, DateTime>(
enableTooltip: true,
// splineType: SplineType.cardinal,
// cardinalSplineTension: 0.2,
dataSource: widget.data,
animationDuration: 0,
opacity: _smooth ? 0 : 1,
xValueMapper: (_HistoryChartSpot data, _) => data.timestamp, xValueMapper: (_HistoryChartSpot data, _) => data.timestamp,
yValueMapper: (_HistoryChartSpot data, _) => data.stat, yValueMapper: (_HistoryChartSpot data, _) => data.stat,
// trendlines:<Trendline>[ trendlines:<Trendline>[
// Trendline( Trendline(
// period: (widget.data.length/175).floor(), isVisible: _smooth,
// type: TrendlineType.movingAverage, period: (widget.data.length/175).floor(),
// color: Colors.blue) type: TrendlineType.movingAverage,
// ], color: Colors.blue)
],
), ),
], ],
), ),

View File

@ -200,7 +200,7 @@ class RankState extends State<RankView> with SingleTickerProviderStateMixin {
direction: Axis.horizontal, direction: Axis.horizontal,
alignment: WrapAlignment.center, alignment: WrapAlignment.center,
crossAxisAlignment: WrapCrossAlignment.end, crossAxisAlignment: WrapCrossAlignment.end,
spacing: 25, spacing: 20,
children: [ children: [
Column( Column(
children: [ children: [

View File

@ -98,7 +98,7 @@ class GaugetNum extends StatelessWidget {
oldPlayerStat! > playerStat ? Colors.redAccent : Colors.greenAccent : oldPlayerStat! > playerStat ? Colors.redAccent : Colors.greenAccent :
oldPlayerStat! < playerStat ? Colors.redAccent : Colors.greenAccent oldPlayerStat! < playerStat ? Colors.redAccent : Colors.greenAccent
),), ),),
if ((oldTl != null && oldTl!.gamesPlayed > 0) && pos != null) const TextSpan(text: ""), if (oldPlayerStat != null && pos != null) const TextSpan(text: ""),
if (pos != null) TextSpan(text: pos!.position >= 1000 ? "${t.top} ${f2.format(pos!.percentage*100)}%" : "${pos!.position}", style: TextStyle(color: getColorOfRank(pos!.position))) if (pos != null) TextSpan(text: pos!.position >= 1000 ? "${t.top} ${f2.format(pos!.percentage*100)}%" : "${pos!.position}", style: TextStyle(color: getColorOfRank(pos!.position)))
] ]
), ),

View File

@ -3,27 +3,26 @@ import 'dart:math';
import 'package:flutter/material.dart'; import 'package:flutter/material.dart';
import 'package:intl/intl.dart'; import 'package:intl/intl.dart';
import 'package:syncfusion_flutter_gauges/gauges.dart'; import 'package:syncfusion_flutter_gauges/gauges.dart';
import 'package:tetra_stats/data_objects/glicko.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/utils/numers_formats.dart'; import 'package:tetra_stats/utils/numers_formats.dart';
class TLProgress extends StatelessWidget{ class TLProgress extends StatelessWidget{
final double tr; final TetraLeagueAlpha tlData;
final String rank;
final int position;
final String? nextRank; final String? nextRank;
final String? previousRank; final String? previousRank;
final int nextRankPosition;
final int previousRankPosition;
final double? nextRankTRcutoff; final double? nextRankTRcutoff;
final double? previousRankTRcutoff; final double? previousRankTRcutoff;
final double? nextRankGlickoCutoff;
final double? previousGlickoCutoff;
final double? nextRankTRcutoffTarget; final double? nextRankTRcutoffTarget;
final double? previousRankTRcutoffTarget; final double? previousRankTRcutoffTarget;
const TLProgress({super.key, required this.tr, required this.rank, required this.position, required this.nextRankPosition, required this.previousRankPosition, this.nextRank, this.previousRank, this.nextRankTRcutoff, this.previousRankTRcutoff, this.nextRankTRcutoffTarget, this.previousRankTRcutoffTarget}); const TLProgress({super.key, required this.tlData, this.nextRank, this.previousRank, this.nextRankTRcutoff, this.previousRankTRcutoff, this.nextRankGlickoCutoff, this.previousGlickoCutoff, this.nextRankTRcutoffTarget, this.previousRankTRcutoffTarget});
double getBarPosition(){ double getBarPosition(){
return min(max(0, 1 - (position - nextRankPosition)/(previousRankPosition - nextRankPosition)), 1); return min(max(0, 1 - (tlData.standing - tlData.nextAt)/(tlData.prevAt - tlData.nextAt)), 1);
} }
double? getBarTR(double tr){ double? getBarTR(double tr){
@ -32,45 +31,51 @@ class TLProgress extends StatelessWidget{
@override @override
Widget build(BuildContext context) { Widget build(BuildContext context) {
// return Container( final glickoForWin = rate(tlData.glicko!, tlData.rd!, 0.06, [[tlData.glicko!, tlData.rd!, 1]], {})[0]-tlData.glicko!;
// alignment: Alignment.centerLeft,
// height: 50,
// width: MediaQuery.of(context).size.width,
// color: Colors.blue,
// child: Container(
// width: MediaQuery.of(context).size.width / 2,
// height: 50,
// color: Colors.red,
// ),
// );
return Padding( return Padding(
padding: const EdgeInsets.all(8.0), padding: const EdgeInsets.all(8.0),
child: SfLinearGauge( child: Column(
minimum: 0, mainAxisSize: MainAxisSize.min,
maximum: 1, children: [
interval: 1, SfLinearGauge(
ranges: [ minimum: 0,
if (previousRankTRcutoff != null && nextRankTRcutoff != null) LinearGaugeRange(endValue: getBarTR(tr)!, color: Colors.cyanAccent, position: LinearElementPosition.cross), maximum: 1,
if (position != -1) LinearGaugeRange(endValue: getBarPosition(), color: Colors.cyanAccent, position: LinearElementPosition.cross), interval: 1,
if (previousRankTRcutoff != null && previousRankTRcutoffTarget != null) LinearGaugeRange(endValue: getBarTR(previousRankTRcutoffTarget!)!, color: Colors.greenAccent, position: LinearElementPosition.inside), ranges: [
if (nextRankTRcutoff != null && nextRankTRcutoffTarget != null) LinearGaugeRange(startValue: getBarTR(nextRankTRcutoffTarget!)!, endValue: 1, color: Colors.yellowAccent, position: LinearElementPosition.inside) if (previousRankTRcutoff != null && nextRankTRcutoff != null) LinearGaugeRange(endValue: getBarTR(tlData.rating)!, color: Colors.cyanAccent, position: LinearElementPosition.cross)
else if (tlData.standing != -1) LinearGaugeRange(endValue: getBarPosition(), color: Colors.cyanAccent, position: LinearElementPosition.cross),
if (previousRankTRcutoff != null && previousRankTRcutoffTarget != null) LinearGaugeRange(endValue: getBarTR(previousRankTRcutoffTarget!)!, color: Colors.greenAccent, position: LinearElementPosition.inside),
if (nextRankTRcutoff != null && nextRankTRcutoffTarget != null) LinearGaugeRange(startValue: getBarTR(nextRankTRcutoffTarget!)!, endValue: 1, color: Colors.yellowAccent, position: LinearElementPosition.inside)
],
markerPointers: [
LinearShapePointer(value: (previousRankTRcutoff != null && nextRankTRcutoff != null) ? getBarTR(tlData.rating)! : getBarPosition(), position: LinearElementPosition.cross, shapeType: LinearShapePointerType.diamond, color: Colors.white, height: 20),
LinearWidgetPointer(offset: 4, position: LinearElementPosition.outside, value: (previousRankTRcutoff != null && nextRankTRcutoff != null) ? getBarTR(tlData.rating)! : getBarPosition(), child: Text("${NumberFormat.decimalPatternDigits(locale: LocaleSettings.currentLocale.languageCode, decimalDigits: 0).format(tlData.standing)}"))
],
isMirrored: true,
showTicks: true,
axisLabelStyle: TextStyle(),
onGenerateLabels: () => [
LinearAxisLabel(text: "${tlData.prevAt > 0 ? "${f0.format(tlData.prevAt)}" : ""}\n ${intf.format(previousRankTRcutoff)} TR", value: 0),
LinearAxisLabel(text: "${tlData.nextAt > 0 ? "${f0.format(tlData.nextAt)}" : ""}\n ${intf.format(nextRankTRcutoff)} TR", value: 1),
],
// labelFormatterCallback: (value) {
// if (value == "0") return "${f0.format(previousRankPosition)}\n 26,700 TR";
// else return f0.format(nextRankPosition);
// },
showLabels: true
),
Container(
width: MediaQuery.of(context).size.width,
height: 20,
child: Stack(
fit: StackFit.expand,
children: [
Positioned(child: Text("${f2.format(tlData.rating-previousRankTRcutoff!)} (${f2.format((tlData.glicko!-previousGlickoCutoff!)/glickoForWin)} losses)"), left: 0,),
Positioned(child: Text("${f2.format(nextRankTRcutoff!-tlData.rating)} (${f2.format((nextRankGlickoCutoff!-tlData.glicko!)/glickoForWin)} wins)"), right: 0,)
],),
)
], ],
markerPointers: [
LinearShapePointer(value: getBarPosition(), position: LinearElementPosition.cross, shapeType: LinearShapePointerType.diamond, color: Colors.white, height: 20),
LinearWidgetPointer(offset: 4, position: LinearElementPosition.outside, value: getBarPosition(), child: Text("${NumberFormat.decimalPatternDigits(locale: LocaleSettings.currentLocale.languageCode, decimalDigits: 0).format(position)}"))
],
isMirrored: true,
showTicks: true,
axisLabelStyle: TextStyle(),
onGenerateLabels: () => [
LinearAxisLabel(text: "${f0.format(previousRankPosition)}\n ${intf.format(previousRankTRcutoff)} TR", value: 0),
LinearAxisLabel(text: "${f0.format(nextRankPosition)}\n ${intf.format(nextRankTRcutoff)} TR", value: 1),
],
// labelFormatterCallback: (value) {
// if (value == "0") return "${f0.format(previousRankPosition)}\n 26,700 TR";
// else return f0.format(nextRankPosition);
// },
showLabels: true
) )
); );
} }

View File

@ -14,10 +14,6 @@ import 'package:tetra_stats/widgets/tl_progress_bar.dart';
var fDiff = NumberFormat("+#,###.###;-#,###.###"); var fDiff = NumberFormat("+#,###.###;-#,###.###");
var intFDiff = NumberFormat("+#,###;-#,###"); var intFDiff = NumberFormat("+#,###;-#,###");
final DateFormat dateFormat = DateFormat.yMMMd(LocaleSettings.currentLocale.languageCode).add_Hms(); final DateFormat dateFormat = DateFormat.yMMMd(LocaleSettings.currentLocale.languageCode).add_Hms();
late RangeValues _currentRangeValues;
TetraLeagueAlpha? oldTl;
late TetraLeagueAlpha currentTl;
late List<TetrioPlayer> sortedStates;
class TLThingy extends StatefulWidget { class TLThingy extends StatefulWidget {
final TetraLeagueAlpha tl; final TetraLeagueAlpha tl;
@ -30,10 +26,12 @@ class TLThingy extends StatefulWidget {
final PlayerLeaderboardPosition? lbPositions; final PlayerLeaderboardPosition? lbPositions;
final TetraLeagueAlpha? averages; final TetraLeagueAlpha? averages;
final double? thatRankCutoff; final double? thatRankCutoff;
final double? thatRankCutoffGlicko;
final double? thatRankTarget; final double? thatRankTarget;
final double? nextRankCutoff; final double? nextRankCutoff;
final double? nextRankCutoffGlicko;
final double? nextRankTarget; final double? nextRankTarget;
const TLThingy({super.key, required this.tl, required this.userID, required this.states, this.showTitle = true, this.bot=false, this.guest=false, this.topTR, this.lbPositions, this.averages, this.nextRankCutoff = 25000, this.thatRankCutoff = 0, this.nextRankTarget = 25000, this.thatRankTarget = 0}); const TLThingy({super.key, required this.tl, required this.userID, required this.states, this.showTitle = true, this.bot=false, this.guest=false, this.topTR, this.lbPositions, this.averages, this.nextRankCutoff = 25000, this.thatRankCutoff = 0, this.thatRankCutoffGlicko = 0, this.nextRankCutoffGlicko = double.infinity, this.nextRankTarget = 25000, this.thatRankTarget = 0});
@override @override
State<TLThingy> createState() => _TLThingyState(); State<TLThingy> createState() => _TLThingyState();
@ -41,6 +39,10 @@ class TLThingy extends StatefulWidget {
class _TLThingyState extends State<TLThingy> { class _TLThingyState extends State<TLThingy> {
late bool oskKagariGimmick; late bool oskKagariGimmick;
late TetraLeagueAlpha? oldTl;
late TetraLeagueAlpha currentTl;
late RangeValues _currentRangeValues;
late List<TetrioPlayer> sortedStates;
@override @override
void initState() { void initState() {
@ -161,14 +163,13 @@ class _TLThingyState extends State<TLThingy> {
// ), // ),
// ), // ),
TLProgress( TLProgress(
tr: currentTl.rating, tlData: currentTl,
rank: currentTl.rank != "z" ? currentTl.rank : currentTl.percentileRank,
position: currentTl.standing,
nextRankPosition: currentTl.nextAt,
previousRankPosition: currentTl.prevAt,
previousRankTRcutoff: widget.thatRankCutoff, previousRankTRcutoff: widget.thatRankCutoff,
previousGlickoCutoff: widget.thatRankCutoffGlicko,
previousRank: widget.tl.prevRank,
previousRankTRcutoffTarget: widget.thatRankTarget, previousRankTRcutoffTarget: widget.thatRankTarget,
nextRankTRcutoff: widget.nextRankCutoff, nextRankTRcutoff: widget.nextRankCutoff,
nextRankGlickoCutoff: widget.nextRankCutoffGlicko,
nextRankTRcutoffTarget: widget.nextRankTarget, nextRankTRcutoffTarget: widget.nextRankTarget,
nextRank: widget.tl.nextRank nextRank: widget.tl.nextRank
), ),