TLThingy bug fix + progress bar now can appoximate number of wins/losses
This commit is contained in:
parent
7ffe909c2d
commit
6195705dcb
|
@ -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);
|
||||
}
|
|
@ -1856,11 +1856,12 @@ class TetrioPlayersLeaderboard {
|
|||
"avgStride": avgStride,
|
||||
"avgInfDS": avgInfDS,
|
||||
"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
|
||||
}];
|
||||
}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),
|
||||
{"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"]
|
||||
};
|
||||
|
||||
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) {
|
||||
type = t;
|
||||
timestamp = ts;
|
||||
|
|
|
@ -86,6 +86,8 @@ class _MainState extends State<MainView> with TickerProviderStateMixin {
|
|||
TetraLeagueAlpha? rankAverages;
|
||||
double? thatRankCutoff;
|
||||
double? nextRankCutoff;
|
||||
double? thatRankGlickoCutoff;
|
||||
double? nextRankGlickoCutoff;
|
||||
String _searchFor = "6098518e3d5155e6ec429cdc"; // who we looking for
|
||||
String _titleNickname = "";
|
||||
/// 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) {
|
||||
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)];
|
||||
nextRankGlickoCutoff = everyone!.cutoffsGlicko[ranks.elementAtOrNull(ranks.indexOf(me.tlSeason1.rank != "z" ? me.tlSeason1.rank : me.tlSeason1.percentileRank)+1)];
|
||||
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
|
||||
if (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
|
||||
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")),
|
||||
|
@ -455,9 +459,11 @@ class _MainState extends State<MainView> with TickerProviderStateMixin {
|
|||
bot: snapshot.data![0].role == "bot",
|
||||
guest: snapshot.data![0].role == "anon",
|
||||
thatRankCutoff: thatRankCutoff,
|
||||
thatRankCutoffGlicko: thatRankGlickoCutoff,
|
||||
thatRankTarget: snapshot.data![0].tlSeason1.rank != "z" ? rankTargets[snapshot.data![0].tlSeason1.rank] : null,
|
||||
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,
|
||||
lbPositions: meAmongEveryone
|
||||
),
|
||||
|
@ -934,26 +940,44 @@ class _HistoryChartThigyState extends State<_HistoryChartThigy> {
|
|||
child: SfCartesianChart(
|
||||
tooltipBehavior: _tooltipBehavior,
|
||||
zoomPanBehavior: _zoomPanBehavior,
|
||||
primaryXAxis: DateTimeAxis(),
|
||||
primaryXAxis: _gamesPlayedInsteadOfDateAndTime ? NumericAxis() : DateTimeAxis(),
|
||||
primaryYAxis: NumericAxis(
|
||||
rangePadding: ChartRangePadding.additional,
|
||||
),
|
||||
series: <CartesianSeries>[
|
||||
StepLineSeries<_HistoryChartSpot, DateTime>(
|
||||
if (_gamesPlayedInsteadOfDateAndTime) StepLineSeries<_HistoryChartSpot, int>(
|
||||
enableTooltip: true,
|
||||
// splineType: SplineType.cardinal,
|
||||
// cardinalSplineTension: 0.2,
|
||||
dataSource: widget.data,
|
||||
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,
|
||||
yValueMapper: (_HistoryChartSpot data, _) => data.stat,
|
||||
// trendlines:<Trendline>[
|
||||
// Trendline(
|
||||
// period: (widget.data.length/175).floor(),
|
||||
// type: TrendlineType.movingAverage,
|
||||
// color: Colors.blue)
|
||||
// ],
|
||||
trendlines:<Trendline>[
|
||||
Trendline(
|
||||
isVisible: _smooth,
|
||||
period: (widget.data.length/175).floor(),
|
||||
type: TrendlineType.movingAverage,
|
||||
color: Colors.blue)
|
||||
],
|
||||
),
|
||||
],
|
||||
),
|
||||
|
|
|
@ -200,7 +200,7 @@ class RankState extends State<RankView> with SingleTickerProviderStateMixin {
|
|||
direction: Axis.horizontal,
|
||||
alignment: WrapAlignment.center,
|
||||
crossAxisAlignment: WrapCrossAlignment.end,
|
||||
spacing: 25,
|
||||
spacing: 20,
|
||||
children: [
|
||||
Column(
|
||||
children: [
|
||||
|
|
|
@ -98,7 +98,7 @@ class GaugetNum extends StatelessWidget {
|
|||
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)))
|
||||
]
|
||||
),
|
||||
|
|
|
@ -3,27 +3,26 @@ import 'dart:math';
|
|||
import 'package:flutter/material.dart';
|
||||
import 'package:intl/intl.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/gen/strings.g.dart';
|
||||
import 'package:tetra_stats/utils/numers_formats.dart';
|
||||
|
||||
class TLProgress extends StatelessWidget{
|
||||
final double tr;
|
||||
final String rank;
|
||||
final int position;
|
||||
final TetraLeagueAlpha tlData;
|
||||
final String? nextRank;
|
||||
final String? previousRank;
|
||||
final int nextRankPosition;
|
||||
final int previousRankPosition;
|
||||
final double? nextRankTRcutoff;
|
||||
final double? previousRankTRcutoff;
|
||||
final double? nextRankGlickoCutoff;
|
||||
final double? previousGlickoCutoff;
|
||||
final double? nextRankTRcutoffTarget;
|
||||
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(){
|
||||
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){
|
||||
|
@ -32,45 +31,51 @@ class TLProgress extends StatelessWidget{
|
|||
|
||||
@override
|
||||
Widget build(BuildContext context) {
|
||||
// return Container(
|
||||
// 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,
|
||||
// ),
|
||||
// );
|
||||
final glickoForWin = rate(tlData.glicko!, tlData.rd!, 0.06, [[tlData.glicko!, tlData.rd!, 1]], {})[0]-tlData.glicko!;
|
||||
return Padding(
|
||||
padding: const EdgeInsets.all(8.0),
|
||||
child: SfLinearGauge(
|
||||
minimum: 0,
|
||||
maximum: 1,
|
||||
interval: 1,
|
||||
ranges: [
|
||||
if (previousRankTRcutoff != null && nextRankTRcutoff != null) LinearGaugeRange(endValue: getBarTR(tr)!, color: Colors.cyanAccent, position: LinearElementPosition.cross),
|
||||
if (position != -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)
|
||||
child: Column(
|
||||
mainAxisSize: MainAxisSize.min,
|
||||
children: [
|
||||
SfLinearGauge(
|
||||
minimum: 0,
|
||||
maximum: 1,
|
||||
interval: 1,
|
||||
ranges: [
|
||||
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
|
||||
)
|
||||
);
|
||||
}
|
||||
|
|
|
@ -14,10 +14,6 @@ import 'package:tetra_stats/widgets/tl_progress_bar.dart';
|
|||
var fDiff = NumberFormat("+#,###.###;-#,###.###");
|
||||
var intFDiff = NumberFormat("+#,###;-#,###");
|
||||
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 {
|
||||
final TetraLeagueAlpha tl;
|
||||
|
@ -30,10 +26,12 @@ class TLThingy extends StatefulWidget {
|
|||
final PlayerLeaderboardPosition? lbPositions;
|
||||
final TetraLeagueAlpha? averages;
|
||||
final double? thatRankCutoff;
|
||||
final double? thatRankCutoffGlicko;
|
||||
final double? thatRankTarget;
|
||||
final double? nextRankCutoff;
|
||||
final double? nextRankCutoffGlicko;
|
||||
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
|
||||
State<TLThingy> createState() => _TLThingyState();
|
||||
|
@ -41,6 +39,10 @@ class TLThingy extends StatefulWidget {
|
|||
|
||||
class _TLThingyState extends State<TLThingy> {
|
||||
late bool oskKagariGimmick;
|
||||
late TetraLeagueAlpha? oldTl;
|
||||
late TetraLeagueAlpha currentTl;
|
||||
late RangeValues _currentRangeValues;
|
||||
late List<TetrioPlayer> sortedStates;
|
||||
|
||||
@override
|
||||
void initState() {
|
||||
|
@ -161,14 +163,13 @@ class _TLThingyState extends State<TLThingy> {
|
|||
// ),
|
||||
// ),
|
||||
TLProgress(
|
||||
tr: currentTl.rating,
|
||||
rank: currentTl.rank != "z" ? currentTl.rank : currentTl.percentileRank,
|
||||
position: currentTl.standing,
|
||||
nextRankPosition: currentTl.nextAt,
|
||||
previousRankPosition: currentTl.prevAt,
|
||||
tlData: currentTl,
|
||||
previousRankTRcutoff: widget.thatRankCutoff,
|
||||
previousGlickoCutoff: widget.thatRankCutoffGlicko,
|
||||
previousRank: widget.tl.prevRank,
|
||||
previousRankTRcutoffTarget: widget.thatRankTarget,
|
||||
nextRankTRcutoff: widget.nextRankCutoff,
|
||||
nextRankGlickoCutoff: widget.nextRankCutoffGlicko,
|
||||
nextRankTRcutoffTarget: widget.nextRankTarget,
|
||||
nextRank: widget.tl.nextRank
|
||||
),
|
||||
|
|
Loading…
Reference in New Issue