1.6.4, many fixes
This commit is contained in:
parent
2376c0eb58
commit
67da831cd2
|
@ -1,10 +1,12 @@
|
|||
// p1nkl0bst3r data objects
|
||||
|
||||
class Cutoffs{
|
||||
DateTime ts;
|
||||
Map<String, double> tr;
|
||||
Map<String, double> glicko;
|
||||
Map<String, double> gxe;
|
||||
|
||||
Cutoffs(this.tr, this.glicko);
|
||||
Cutoffs(this.ts, this.tr, this.glicko, this.gxe);
|
||||
}
|
||||
|
||||
class TopTr{
|
||||
|
|
|
@ -42,26 +42,26 @@ const Map<String, double> rankCutoffs = {
|
|||
"z": -1,
|
||||
"": 0.5
|
||||
};
|
||||
const Map<String, double> rankTargets = {
|
||||
"x": 24503.75, // where that comes from?
|
||||
"u": 23038,
|
||||
"ss": 21583,
|
||||
"s+": 20128,
|
||||
"s": 18673,
|
||||
"s-": 16975,
|
||||
"a+": 15035,
|
||||
"a": 13095,
|
||||
"a-": 11155,
|
||||
"b+": 9215,
|
||||
"b": 7275,
|
||||
"b-": 5335,
|
||||
"c+": 3880,
|
||||
"c": 2425,
|
||||
"c-": 1213,
|
||||
"d+": 606,
|
||||
"d": 0,
|
||||
};
|
||||
DateTime seasonStart = DateTime.utc(2024, 08, 16, 18);
|
||||
// const Map<String, double> rankTargets = {
|
||||
// "x": 24503.75, // where that comes from?
|
||||
// "u": 23038,
|
||||
// "ss": 21583,
|
||||
// "s+": 20128,
|
||||
// "s": 18673,
|
||||
// "s-": 16975,
|
||||
// "a+": 15035,
|
||||
// "a": 13095,
|
||||
// "a-": 11155,
|
||||
// "b+": 9215,
|
||||
// "b": 7275,
|
||||
// "b-": 5335,
|
||||
// "c+": 3880,
|
||||
// "c": 2425,
|
||||
// "c-": 1213,
|
||||
// "d+": 606,
|
||||
// "d": 0,
|
||||
// };
|
||||
// DateTime seasonStart = DateTime.utc(2024, 08, 16, 18);
|
||||
//DateTime seasonEnd = DateTime.utc(2024, 07, 26, 15);
|
||||
enum Stats {
|
||||
tr,
|
||||
|
@ -123,7 +123,8 @@ const Map<Stats, String> chartsShortTitles = {
|
|||
Stats.openerMinusInfDS: "Opener - Inf. DS"
|
||||
};
|
||||
|
||||
const Map<String, Color> rankColors = { // thanks osk for const rankColors at https://ch.tetr.io/res/js/base.js:418
|
||||
const Map<String, Color> rankColors = { // thanks osk for const rankColors at https://ch.tetr.io/res/js/base.js:458
|
||||
'x+': Color(0xFF643C8D),
|
||||
'x': Color(0xFFFF45FF),
|
||||
'u': Color(0xFFFF3813),
|
||||
'ss': Color(0xFFDB8B1F),
|
||||
|
@ -1422,10 +1423,10 @@ class TetraLeague {
|
|||
timestamp = ts;
|
||||
gamesPlayed = json['gamesplayed'] ?? 0;
|
||||
gamesWon = json['gameswon'] ?? 0;
|
||||
tr = json['tr'] != null ? json['tr'].toDouble() : -1;
|
||||
tr = json['tr'] != null ? json['tr'].toDouble() : json['rating'] != null ? json['rating'].toDouble() : -1;
|
||||
glicko = json['glicko']?.toDouble();
|
||||
rd = json['rd'] != null ? json['rd']!.toDouble() : noTrRd;
|
||||
gxe = json['gxe'].toDouble();
|
||||
gxe = json['gxe'] != null ? json['gxe'].toDouble() : -1;
|
||||
rank = json['rank'] != null ? json['rank']!.toString() : 'z';
|
||||
bestRank = json['bestrank'] != null ? json['bestrank']!.toString() : 'z';
|
||||
apm = json['apm']?.toDouble();
|
||||
|
@ -1721,6 +1722,11 @@ class TetrioPlayersLeaderboard {
|
|||
|
||||
TetrioPlayersLeaderboard(this.type, this.leaderboard);
|
||||
|
||||
@override
|
||||
String toString(){
|
||||
return "$type leaderboard: ${leaderboard.length} players";
|
||||
}
|
||||
|
||||
List<TetrioPlayerFromLeaderboard> getStatRanking(List<TetrioPlayerFromLeaderboard> leaderboard, Stats stat, {bool reversed = false, String country = ""}){
|
||||
List<TetrioPlayerFromLeaderboard> lb = List.from(leaderboard);
|
||||
if (country.isNotEmpty){
|
||||
|
@ -2425,6 +2431,10 @@ class TetrioPlayersLeaderboard {
|
|||
leaderboard.add(TetrioPlayerFromLeaderboard.fromJson(entry, ts));
|
||||
}
|
||||
}
|
||||
|
||||
addPlayers(List<TetrioPlayerFromLeaderboard> list){
|
||||
leaderboard.addAll(list);
|
||||
}
|
||||
}
|
||||
|
||||
class TetrioPlayerFromLeaderboard {
|
||||
|
|
|
@ -1,3 +1,5 @@
|
|||
import 'dart:math';
|
||||
|
||||
import 'package:http/http.dart' as http;
|
||||
|
||||
class UserAgentClient extends http.BaseClient {
|
||||
|
@ -9,6 +11,7 @@ class UserAgentClient extends http.BaseClient {
|
|||
@override
|
||||
Future<http.StreamedResponse> send(http.BaseRequest request) {
|
||||
request.headers['user-agent'] = userAgent;
|
||||
request.headers['X-Session-ID'] = "${Random().nextInt(1<<32)}";
|
||||
return _inner.send(request);
|
||||
}
|
||||
}
|
|
@ -411,12 +411,7 @@ class TetrioService extends DB {
|
|||
Cutoffs? cached = _cache.get("", Cutoffs);
|
||||
if (cached != null) return cached;
|
||||
|
||||
Uri url;
|
||||
if (kIsWeb) {
|
||||
url = Uri.https('ts.dan63.by', 'oskware_bridge.php', {"endpoint": "TLCutoffs"});
|
||||
} else {
|
||||
url = Uri.https('api.p1nkl0bst3r.xyz', 'rankcutoff', {"users": null});
|
||||
}
|
||||
Uri url = Uri.https('ts.dan63.by', 'beanserver_blaster/cutoffs.json', {"users": null});
|
||||
|
||||
try{
|
||||
final response = await client.get(url);
|
||||
|
@ -424,13 +419,14 @@ class TetrioService extends DB {
|
|||
switch (response.statusCode) {
|
||||
case 200:
|
||||
Map<String, dynamic> rawData = jsonDecode(response.body);
|
||||
Map<String, dynamic> data = rawData["cutoffs"] as Map<String, dynamic>;
|
||||
Cutoffs result = Cutoffs({}, {});
|
||||
Map<String, dynamic> data = rawData["data"] as Map<String, dynamic>;
|
||||
Cutoffs result = Cutoffs(DateTime.fromMillisecondsSinceEpoch(rawData["created"]), {}, {}, {});
|
||||
for (String rank in data.keys){
|
||||
result.tr[rank] = data[rank]["rating"];
|
||||
result.tr[rank] = data[rank]["tr"];
|
||||
result.glicko[rank] = data[rank]["glicko"];
|
||||
result.gxe[rank] = data[rank]["gxe"];
|
||||
}
|
||||
_cache.store(result, rawData["ts"] + 300000);
|
||||
_cache.store(result, rawData["cache_until"]);
|
||||
return result;
|
||||
case 404:
|
||||
developer.log("fetchCutoffs: Cutoffs are gone", name: "services/tetrio_crud", error: response.statusCode);
|
||||
|
@ -466,7 +462,7 @@ class TetrioService extends DB {
|
|||
if (kIsWeb) {
|
||||
url = Uri.https('ts.dan63.by', 'oskware_bridge.php', {"endpoint": "TLTopOne"});
|
||||
} else {
|
||||
url = Uri.https('ch.tetr.io', 'api/users/lists/league', {"after": "25000", "limit": "1"});
|
||||
url = Uri.https('ch.tetr.io', 'api/users/by/league', {"after": "25000:0:0", "limit": "1"});
|
||||
}
|
||||
|
||||
try{
|
||||
|
@ -475,7 +471,7 @@ class TetrioService extends DB {
|
|||
switch (response.statusCode) {
|
||||
case 200:
|
||||
var rawJson = jsonDecode(response.body);
|
||||
TetrioPlayerFromLeaderboard result = TetrioPlayerFromLeaderboard.fromJson(rawJson["data"]["users"][0], DateTime.fromMillisecondsSinceEpoch(rawJson["cache"]["cached_at"]));
|
||||
TetrioPlayerFromLeaderboard result = TetrioPlayerFromLeaderboard.fromJson(rawJson["data"]["entries"][0], DateTime.fromMillisecondsSinceEpoch(rawJson["cache"]["cached_at"]));
|
||||
_cache.store(result, rawJson["cache"]["cached_until"]);
|
||||
return result;
|
||||
case 404:
|
||||
|
@ -640,15 +636,17 @@ class TetrioService extends DB {
|
|||
}
|
||||
|
||||
/// Retrieves full Tetra League leaderboard from Tetra Channel api. Returns a leaderboard object. Throws an exception if fails to retrieve.
|
||||
Future<TetrioPlayersLeaderboard> fetchTLLeaderboard() async {
|
||||
TetrioPlayersLeaderboard? cached = _cache.get("league", TetrioPlayersLeaderboard);
|
||||
Future<TetrioPlayersLeaderboard> fetchTLLeaderboard({double? after}) async {
|
||||
TetrioPlayersLeaderboard? cached = _cache.get("league${after != null ? after.toString() : ""}", TetrioPlayersLeaderboard);
|
||||
if (cached != null) return cached;
|
||||
|
||||
Uri url;
|
||||
if (kIsWeb) {
|
||||
url = Uri.https('ts.dan63.by', 'oskware_bridge.php', {"endpoint": "TLLeaderboard"});
|
||||
} else {
|
||||
url = Uri.https('ch.tetr.io', 'api/users/by/league');
|
||||
url = Uri.https('ch.tetr.io', 'api/users/by/league', {
|
||||
"limit": "100",
|
||||
if (after != null) "after": "$after:0:0"
|
||||
});
|
||||
}
|
||||
try{
|
||||
final response = await client.get(url);
|
||||
|
@ -688,6 +686,20 @@ class TetrioService extends DB {
|
|||
}
|
||||
}
|
||||
|
||||
Stream<TetrioPlayersLeaderboard> fetchFullLeaderboard() async* {
|
||||
late double after;
|
||||
int lbLength = 100;
|
||||
TetrioPlayersLeaderboard leaderboard = await fetchTLLeaderboard();
|
||||
after = leaderboard.leaderboard.last.tr;
|
||||
while (lbLength == 100){
|
||||
TetrioPlayersLeaderboard pseudoLb = await fetchTLLeaderboard(after: after);
|
||||
leaderboard.addPlayers(pseudoLb.leaderboard);
|
||||
lbLength = pseudoLb.leaderboard.length;
|
||||
after = pseudoLb.leaderboard.last.tr;
|
||||
yield leaderboard;
|
||||
}
|
||||
}
|
||||
|
||||
// i want to know progress, so i trying to figure out this thing:
|
||||
// Stream<TetrioPlayersLeaderboard> fetchTLLeaderboardAsStream() async {
|
||||
// TetrioPlayersLeaderboard? cached = _cache.get("league", TetrioPlayersLeaderboard);
|
||||
|
|
|
@ -11,6 +11,7 @@ import 'package:intl/intl.dart';
|
|||
import 'package:shared_preferences/shared_preferences.dart';
|
||||
import 'package:flutter/services.dart';
|
||||
import 'package:syncfusion_flutter_charts/charts.dart';
|
||||
import 'package:tetra_stats/data_objects/tetra_stats.dart';
|
||||
import 'package:tetra_stats/data_objects/tetrio.dart';
|
||||
import 'package:tetra_stats/gen/strings.g.dart';
|
||||
import 'package:tetra_stats/main.dart' show prefs, teto;
|
||||
|
@ -156,8 +157,8 @@ class _MainState extends State<MainView> with TickerProviderStateMixin {
|
|||
if (!kIsWeb && !Platform.isAndroid && !Platform.isIOS) await windowManager.setTitle(title);
|
||||
|
||||
// Requesting Tetra League (alpha), records, news and top TR of player
|
||||
late List<dynamic> requests;
|
||||
late Summaries summaries;
|
||||
List<dynamic> requests;
|
||||
Summaries summaries = await teto.fetchSummaries(_searchFor);
|
||||
late TetraLeagueBetaStream tlStream;
|
||||
late News news;
|
||||
// late SingleplayerStream recentSprint;
|
||||
|
@ -166,20 +167,20 @@ class _MainState extends State<MainView> with TickerProviderStateMixin {
|
|||
// late SingleplayerStream blitz;
|
||||
late SingleplayerStream recentZenith;
|
||||
late SingleplayerStream recentZenithEX;
|
||||
// late TetrioPlayerFromLeaderboard? topOne;
|
||||
late TetrioPlayerFromLeaderboard? topOne;
|
||||
// late TopTr? topTR;
|
||||
requests = await Future.wait([ // all at once (8 requests to oskware in total)
|
||||
requests = await Future.wait([
|
||||
teto.fetchSummaries(_searchFor),
|
||||
teto.fetchTLStream(_searchFor),
|
||||
teto.fetchNews(_searchFor),
|
||||
teto.fetchStream(_searchFor, "zenith/recent"),
|
||||
teto.fetchStream(_searchFor, "zenithex/recent"),
|
||||
//teto.fetchStream(_searchFor, "40l/top"),
|
||||
//teto.fetchStream(_searchFor, "blitz/top"),
|
||||
teto.fetchCutoffs(),
|
||||
(summaries.league.rank != "z" ? summaries.league.rank == "x+" : summaries.league.percentileRank == "x+") ? teto.fetchTopOneFromTheLeaderboard() : Future.delayed(Duration.zero, ()=>null),
|
||||
]);
|
||||
//prefs.getBool("showPositions") != true ? teto.fetchCutoffs() : Future.delayed(Duration.zero, ()=><Map<String, double>>[]),
|
||||
//(me.tlSeason1.rank != "z" ? me.tlSeason1.rank == "x" : me.tlSeason1.percentileRank == "x") ? teto.fetchTopOneFromTheLeaderboard() : Future.delayed(Duration.zero, ()=>null),
|
||||
//(me.tlSeason1.gamesPlayed > 9) ? teto.fetchTopTR(_searchFor) : Future.delayed(Duration.zero, () => null) // can retrieve this only if player has TR
|
||||
|
||||
//(summaries.league.gamesPlayed > 9) ? teto.fetchTopTR(_searchFor) : Future.delayed(Duration.zero, () => null) // can retrieve this only if player has TR
|
||||
summaries = requests[0] as Summaries;
|
||||
tlStream = requests[1] as TetraLeagueBetaStream;
|
||||
// records = requests[1] as UserRecords;
|
||||
|
@ -189,7 +190,7 @@ class _MainState extends State<MainView> with TickerProviderStateMixin {
|
|||
// recent = requests[3] as SingleplayerStream;
|
||||
// sprint = requests[4] as SingleplayerStream;
|
||||
// blitz = requests[5] as SingleplayerStream;
|
||||
// topOne = requests[7] as TetrioPlayerFromLeaderboard?;
|
||||
topOne = requests[6] as TetrioPlayerFromLeaderboard?;
|
||||
// topTR = requests[8] as TopTr?; // No TR - no Top TR
|
||||
|
||||
meAmongEveryone = teto.getCachedLeaderboardPositions(me.userId);
|
||||
|
@ -202,17 +203,17 @@ class _MainState extends State<MainView> with TickerProviderStateMixin {
|
|||
if (meAmongEveryone != null) teto.cacheLeaderboardPositions(me.userId, meAmongEveryone!);
|
||||
}
|
||||
}
|
||||
//Map<String, double>? cutoffs = prefs.getBool("showPositions") == true ? everyone!.cutoffs : (requests[6] as Cutoffs?)?.tr;
|
||||
//Map<String, double>? cutoffsGlicko = prefs.getBool("showPositions") == true ? everyone!.cutoffsGlicko : (requests[6] as Cutoffs?)?.glicko;
|
||||
Map<String, double>? cutoffs = (requests[5] as Cutoffs?)?.tr;
|
||||
Map<String, double>? cutoffsGlicko = (requests[5] as Cutoffs?)?.glicko;
|
||||
|
||||
// if (me.tlSeason1.gamesPlayed > 9) {
|
||||
// thatRankCutoff = cutoffs?[me.tlSeason1.rank != "z" ? me.tlSeason1.rank : me.tlSeason1.percentileRank];
|
||||
// thatRankGlickoCutoff = cutoffsGlicko?[me.tlSeason1.rank != "z" ? me.tlSeason1.rank : me.tlSeason1.percentileRank];
|
||||
// nextRankCutoff = (me.tlSeason1.rank != "z" ? me.tlSeason1.rank == "x" : me.tlSeason1.percentileRank == "x") ? topOne?.tr??25000 : cutoffs?[ranks.elementAtOrNull(ranks.indexOf(me.tlSeason1.rank != "z" ? me.tlSeason1.rank : me.tlSeason1.percentileRank)+1)];
|
||||
// nextRankGlickoCutoff = (me.tlSeason1.rank != "z" ? me.tlSeason1.rank == "x" : me.tlSeason1.percentileRank == "x") ? topOne?.glicko??double.infinity : cutoffsGlicko?[ranks.elementAtOrNull(ranks.indexOf(me.tlSeason1.rank != "z" ? me.tlSeason1.rank : me.tlSeason1.percentileRank)+1)];
|
||||
// }
|
||||
if (summaries.league.gamesPlayed > 9) {
|
||||
thatRankCutoff = cutoffs?[summaries.league.rank != "z" ? summaries.league.rank : summaries.league.percentileRank];
|
||||
thatRankGlickoCutoff = cutoffsGlicko?[summaries.league.rank != "z" ? summaries.league.rank : summaries.league.percentileRank];
|
||||
nextRankCutoff = (summaries.league.rank != "z" ? summaries.league.rank == "x+" : summaries.league.percentileRank == "x+") ? topOne?.tr??25000 : cutoffs?[ranks.elementAtOrNull(ranks.indexOf(summaries.league.rank != "z" ? summaries.league.rank : summaries.league.percentileRank)+1)];
|
||||
nextRankGlickoCutoff = (summaries.league.rank != "z" ? summaries.league.rank == "x+" : summaries.league.percentileRank == "x+") ? topOne?.glicko??double.infinity : cutoffsGlicko?[ranks.elementAtOrNull(ranks.indexOf(summaries.league.rank != "z" ? summaries.league.rank : summaries.league.percentileRank)+1)];
|
||||
}
|
||||
|
||||
// if (everyone != null && me.tlSeason1.gamesPlayed > 9) rankAverages = everyone?.averages[me.tlSeason1.percentileRank]?[0];
|
||||
// if (everyone != null && summaries.league.gamesPlayed > 9) rankAverages = everyone?.averages[summaries.league.percentileRank]?[0];
|
||||
|
||||
// Making list of Tetra League matches
|
||||
bool isTracking = await teto.isPlayerTracking(me.userId);
|
||||
|
@ -270,7 +271,7 @@ class _MainState extends State<MainView> with TickerProviderStateMixin {
|
|||
}
|
||||
}
|
||||
|
||||
//states.addAll(await teto.getPlayer(me.userId));
|
||||
states.addAll(await teto.getPlayer(me.userId));
|
||||
for (var element in states) { // For graphs I need only unique entries
|
||||
if (element.tlSeason1 != null && uniqueTL.isNotEmpty && uniqueTL.last != element.tlSeason1) uniqueTL.add(element.tlSeason1!);
|
||||
if (uniqueTL.isEmpty) uniqueTL.add(element.tlSeason1!);
|
||||
|
@ -475,12 +476,12 @@ class _MainState extends State<MainView> with TickerProviderStateMixin {
|
|||
//lastMatchPlayed: snapshot.data![11],
|
||||
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,
|
||||
//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,
|
||||
thatRankCutoff: thatRankCutoff,
|
||||
thatRankCutoffGlicko: thatRankGlickoCutoff,
|
||||
//thatRankTarget: snapshot.data![1].league.rank != "z" ? rankTargets[snapshot.data![1].league.rank] : null,
|
||||
nextRankCutoff: nextRankCutoff,
|
||||
nextRankCutoffGlicko: nextRankGlickoCutoff,
|
||||
//nextRankTarget: (snapshot.data![1].league.rank != "z" && snapshot.data![1].league.rank != "x") ? rankTargets[ranks.elementAtOrNull(ranks.indexOf(snapshot.data![1].league.rank)+1)] : null,
|
||||
//averages: rankAverages,
|
||||
//lbPositions: meAmongEveryone
|
||||
),
|
||||
|
@ -516,12 +517,12 @@ class _MainState extends State<MainView> with TickerProviderStateMixin {
|
|||
//lastMatchPlayed: snapshot.data![11],
|
||||
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,
|
||||
//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,
|
||||
thatRankCutoff: thatRankCutoff,
|
||||
thatRankCutoffGlicko: thatRankGlickoCutoff,
|
||||
//thatRankTarget: snapshot.data![1].league.rank != "z" ? rankTargets[snapshot.data![1].league.rank] : null,
|
||||
nextRankCutoff: nextRankCutoff,
|
||||
nextRankCutoffGlicko: nextRankGlickoCutoff,
|
||||
//nextRankTarget: (snapshot.data![1].league.rank != "z" && snapshot.data![1].league.rank != "x") ? rankTargets[ranks.elementAtOrNull(ranks.indexOf(snapshot.data![1].league.rank)+1)] : null,
|
||||
//averages: rankAverages,
|
||||
//lbPositions: meAmongEveryone
|
||||
),
|
||||
|
|
|
@ -170,7 +170,7 @@ class DestinationLeaderboards extends StatefulWidget{
|
|||
|
||||
class _DestinationLeaderboardsState extends State<DestinationLeaderboards> {
|
||||
Cards rightCard = Cards.tetraLeague;
|
||||
Duration postSeasonLeft = seasonStart.difference(DateTime.now());
|
||||
//Duration postSeasonLeft = seasonStart.difference(DateTime.now());
|
||||
final List<String> leaderboards = ["Tetra League", "Quick Play", "Quick Play Expert"];
|
||||
|
||||
@override
|
||||
|
@ -245,7 +245,7 @@ class _DestinationGraphsState extends State<DestinationGraphs> {
|
|||
final List _historyShortTitles = ["TR", "Glicko", "RD", "APM", "PPS", "VS", "APP", "DS/S", "DS/P", "APP + DS/P", "VS/APM", "Cheese", "GbE", "wAPP", "Area", "eTR", "±eTR", "Opener", "Plonk", "Inf. DS", "Stride"];
|
||||
int _chartsIndex = 0;
|
||||
late List<DropdownMenuItem<List<_HistoryChartSpot>>> chartsData;
|
||||
Duration postSeasonLeft = seasonStart.difference(DateTime.now());
|
||||
//Duration postSeasonLeft = seasonStart.difference(DateTime.now());
|
||||
|
||||
@override
|
||||
void initState(){
|
||||
|
@ -611,7 +611,7 @@ class RecordSummary extends StatelessWidget{
|
|||
class _DestinationHomeState extends State<DestinationHome> {
|
||||
Cards rightCard = Cards.overview;
|
||||
CardMod cardMod = CardMod.info;
|
||||
Duration postSeasonLeft = seasonStart.difference(DateTime.now());
|
||||
//Duration postSeasonLeft = seasonStart.difference(DateTime.now());
|
||||
late Map<Cards, List<ButtonSegment<CardMod>>> modeButtons;
|
||||
late MapEntry? closestAverageBlitz;
|
||||
late bool blitzBetterThanClosestAverage;
|
||||
|
@ -849,7 +849,7 @@ class _DestinationHomeState extends State<DestinationHome> {
|
|||
crossAxisAlignment: CrossAxisAlignment.center,
|
||||
children: [
|
||||
Text(t.tetraLeague, style: const TextStyle(fontFamily: "Eurostile Round Extended", fontSize: 42)),
|
||||
Text("${t.seasonStarts} ${countdown(postSeasonLeft)}", textAlign: TextAlign.center)
|
||||
//Text("${t.seasonStarts} ${countdown(postSeasonLeft)}", textAlign: TextAlign.center)
|
||||
],
|
||||
),
|
||||
),
|
||||
|
@ -1021,7 +1021,7 @@ class _DestinationHomeState extends State<DestinationHome> {
|
|||
crossAxisAlignment: CrossAxisAlignment.center,
|
||||
children: [
|
||||
Text(t.quickPlay, style: const TextStyle(fontFamily: "Eurostile Round Extended", fontSize: 42)),
|
||||
Text("Leaderboard reset in ${countdown(postSeasonLeft)}", textAlign: TextAlign.center),
|
||||
//Text("Leaderboard reset in ${countdown(postSeasonLeft)}", textAlign: TextAlign.center),
|
||||
],
|
||||
),
|
||||
),
|
||||
|
|
|
@ -1,9 +1,14 @@
|
|||
import 'dart:io';
|
||||
import 'package:flutter/foundation.dart';
|
||||
import 'package:flutter/material.dart';
|
||||
import 'package:tetra_stats/data_objects/tetra_stats.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';
|
||||
import 'package:tetra_stats/utils/text_shadow.dart';
|
||||
import 'package:tetra_stats/views/compare_view.dart';
|
||||
import 'package:tetra_stats/views/rank_averages_view.dart';
|
||||
import 'package:tetra_stats/widgets/text_timestamp.dart';
|
||||
import 'package:window_manager/window_manager.dart';
|
||||
import 'package:tetra_stats/main.dart' show teto;
|
||||
|
||||
|
@ -17,14 +22,9 @@ class RankAveragesView extends StatefulWidget {
|
|||
late String oldWindowTitle;
|
||||
|
||||
class RanksAverages extends State<RankAveragesView> {
|
||||
Map<String, List<dynamic>> averages = {};
|
||||
|
||||
@override
|
||||
void initState() {
|
||||
teto.fetchTLLeaderboard().then((value){
|
||||
averages = value.averages;
|
||||
setState(() {});
|
||||
});
|
||||
if (!kIsWeb && !Platform.isAndroid && !Platform.isIOS){
|
||||
windowManager.getTitle().then((value) => oldWindowTitle = value);
|
||||
windowManager.setTitle("Tetra Stats: ${t.rankAveragesViewTitle}");
|
||||
|
@ -40,35 +40,110 @@ class RanksAverages extends State<RankAveragesView> {
|
|||
|
||||
@override
|
||||
Widget build(BuildContext context) {
|
||||
bool bigScreen = MediaQuery.of(context).size.width >= 700;
|
||||
return Scaffold(
|
||||
appBar: AppBar(
|
||||
title: Text(t.rankAveragesViewTitle),
|
||||
),
|
||||
backgroundColor: Colors.black,
|
||||
body: SafeArea(
|
||||
child: averages.isEmpty ? const Center(child: Text('Fetching...')) : ListView.builder(
|
||||
itemCount: averages.length,
|
||||
itemBuilder: (context, index){
|
||||
List<String> keys = averages.keys.toList();
|
||||
return ListTile(
|
||||
leading: Image.asset("res/tetrio_tl_alpha_ranks/${keys[index]}.png", height: 48),
|
||||
title: Text(t.players(n: averages[keys[index]]?[1]["players"]), style: const TextStyle(fontFamily: "Eurostile Round Extended")),
|
||||
subtitle: Text("${f2.format(averages[keys[index]]?[0].apm)} APM, ${f2.format(averages[keys[index]]?[0].pps)} PPS, ${f2.format(averages[keys[index]]?[0].vs)} VS, ${f2.format(averages[keys[index]]?[0].nerdStats.app)} APP, ${f2.format(averages[keys[index]]?[0].nerdStats.vsapm)} VS/APM",
|
||||
style: const TextStyle(fontFamily: "Eurostile Round Condensed", color: Colors.grey, fontSize: 13)),
|
||||
trailing: Text("${f2.format(averages[keys[index]]?[1]["toEnterTR"])} TR", style: const TextStyle(fontSize: 28, fontFamily: "Eurostile Round")),
|
||||
onTap: (){
|
||||
if (averages[keys[index]]?[1]["players"] > 0) {
|
||||
Navigator.push(
|
||||
context,
|
||||
MaterialPageRoute(
|
||||
builder: (context) => RankView(rank: averages[keys[index]]!),
|
||||
child: FutureBuilder<Cutoffs?>(future: teto.fetchCutoffs(), builder: (context, snapshot){
|
||||
switch (snapshot.connectionState) {
|
||||
case ConnectionState.none:
|
||||
case ConnectionState.waiting:
|
||||
case ConnectionState.active:
|
||||
return const Center(child: CircularProgressIndicator(color: Colors.white));
|
||||
case ConnectionState.done:
|
||||
if (snapshot.hasData){
|
||||
return Container(
|
||||
alignment: Alignment.center,
|
||||
child: SingleChildScrollView(
|
||||
scrollDirection: Axis.horizontal,
|
||||
child: Container(
|
||||
alignment: Alignment.center,
|
||||
width: MediaQuery.of(context).size.width,
|
||||
constraints: const BoxConstraints(maxWidth: 900, minWidth: 610),
|
||||
child: SingleChildScrollView(
|
||||
padding: const EdgeInsets.all(16),
|
||||
child: Column(
|
||||
mainAxisSize: MainAxisSize.min,
|
||||
children: [
|
||||
Table(
|
||||
defaultVerticalAlignment: TableCellVerticalAlignment.middle,
|
||||
border: TableBorder.all(color: Colors.grey.shade900),
|
||||
columnWidths: const {0: FixedColumnWidth(48)},
|
||||
children: [
|
||||
TableRow(
|
||||
children: [
|
||||
Text(t.rank, textAlign: TextAlign.center, style: const TextStyle(fontFamily: "Eurostile Round", fontSize: 14, fontWeight: FontWeight.w500, color: Colors.white)),
|
||||
Padding(
|
||||
padding: const EdgeInsets.only(right: 8.0),
|
||||
child: Text("TR", textAlign: TextAlign.right, style: TextStyle(fontFamily: bigScreen ? "Eurostile Round" : "Eurostile Round Condensed", fontSize: 28, fontWeight: FontWeight.w500, color: Colors.white)),
|
||||
),
|
||||
Padding(
|
||||
padding: const EdgeInsets.only(right: 8.0),
|
||||
child: Text("Glicko", textAlign: TextAlign.right, style: TextStyle(fontFamily: bigScreen ? "Eurostile Round" : "Eurostile Round Condensed", fontSize: 28, fontWeight: FontWeight.w500, color: Colors.white)),
|
||||
),
|
||||
Padding(
|
||||
padding: const EdgeInsets.only(right: 8.0),
|
||||
child: Text("Glixare", textAlign: TextAlign.right, style: TextStyle(fontFamily: bigScreen ? "Eurostile Round" : "Eurostile Round Condensed", fontSize: 28, fontWeight: FontWeight.w500, color: Colors.white)),
|
||||
),
|
||||
Padding(
|
||||
padding: const EdgeInsets.only(right: 8.0),
|
||||
child: Text("S1 TR", textAlign: TextAlign.right, style: TextStyle(fontFamily: bigScreen ? "Eurostile Round" : "Eurostile Round Condensed", fontSize: 28, fontWeight: FontWeight.w500, color: Colors.white)),
|
||||
),
|
||||
]
|
||||
),
|
||||
for (String rank in snapshot.data!.tr.keys) TableRow(
|
||||
decoration: BoxDecoration(gradient: LinearGradient(colors: [rankColors[rank]!.withAlpha(100), rankColors[rank]!.withAlpha(200)])),
|
||||
children: [
|
||||
Container(decoration: BoxDecoration(boxShadow: [BoxShadow(color: Colors.black.withAlpha(132), blurRadius: 32.0, blurStyle: BlurStyle.inner)]), child: Image.asset("res/tetrio_tl_alpha_ranks/$rank.png", height: 48)),
|
||||
Padding(
|
||||
padding: const EdgeInsets.only(right: 8.0),
|
||||
child: Text(f2.format(snapshot.data!.tr[rank]), textAlign: TextAlign.right, style: TextStyle(fontFamily: bigScreen ? "Eurostile Round" : "Eurostile Round Condensed", fontSize: 28, fontWeight: FontWeight.w500, color: Colors.white, shadows: textShadow)),
|
||||
),
|
||||
Padding(
|
||||
padding: const EdgeInsets.only(right: 8.0),
|
||||
child: Text(f2.format(snapshot.data!.glicko[rank]), textAlign: TextAlign.right, style: TextStyle(fontFamily: bigScreen ? "Eurostile Round" : "Eurostile Round Condensed", fontSize: 28, fontWeight: FontWeight.w500, color: Colors.white, shadows: textShadow)),
|
||||
),
|
||||
Padding(
|
||||
padding: const EdgeInsets.only(right: 8.0),
|
||||
child: Text(f2.format(snapshot.data!.gxe[rank]), textAlign: TextAlign.right, style: TextStyle(fontFamily: bigScreen ? "Eurostile Round" : "Eurostile Round Condensed", fontSize: 28, fontWeight: FontWeight.w500, color: Colors.white, shadows: textShadow)),
|
||||
),
|
||||
Padding(
|
||||
padding: const EdgeInsets.only(right: 8.0),
|
||||
child: Text(f2.format(snapshot.data!.gxe[rank]!*250), textAlign: TextAlign.right, style: TextStyle(fontFamily: bigScreen ? "Eurostile Round" : "Eurostile Round Condensed", fontSize: 28, fontWeight: FontWeight.w500, color: Colors.white, shadows: textShadow)),
|
||||
),
|
||||
]
|
||||
)
|
||||
],
|
||||
),
|
||||
Text(t.sprintAndBlitsRelevance(date: timestamp(snapshot.data!.ts)))
|
||||
],
|
||||
),
|
||||
);
|
||||
}
|
||||
},
|
||||
),
|
||||
),
|
||||
),
|
||||
);
|
||||
})
|
||||
),
|
||||
}
|
||||
if (snapshot.hasError){
|
||||
return Center(child:
|
||||
Column(
|
||||
mainAxisSize: MainAxisSize.min,
|
||||
children: [
|
||||
Text(snapshot.error.toString(), style: const TextStyle(fontFamily: "Eurostile Round", fontSize: 42, fontWeight: FontWeight.bold), textAlign: TextAlign.center),
|
||||
if (snapshot.stackTrace != null) Padding(
|
||||
padding: const EdgeInsets.only(top: 8.0),
|
||||
child: Text(snapshot.stackTrace.toString(), style: const TextStyle(fontFamily: "Eurostile Round", fontSize: 18), textAlign: TextAlign.center),
|
||||
),
|
||||
],
|
||||
)
|
||||
);
|
||||
}
|
||||
return const Text("end of FutureBuilder");
|
||||
}
|
||||
})
|
||||
),
|
||||
);
|
||||
}
|
||||
}
|
||||
|
|
|
@ -61,7 +61,7 @@ class TLProgress extends StatelessWidget{
|
|||
if (tlData.nextAt > 0 && nextRankTRcutoff != null) const TextSpan(text: "\n"),
|
||||
if (nextRankTRcutoff != null) TextSpan(text: "${f2.format(nextRankTRcutoff)} (${comparef2.format(nextRankTRcutoff!-tlData.tr)}) TR"),
|
||||
if ((tlData.nextAt > 0 || nextRankTRcutoff != null) && nextRankGlickoCutoff != null) const TextSpan(text: "\n"),
|
||||
if (nextRankGlickoCutoff != null) TextSpan(text: (tlData.standing < tlData.nextAt || ((nextRankGlickoCutoff!-tlData.glicko!)/glickoForWin < 0.5 && ((tlData.rank != "x" && tlData.rank != "z") || tlData.percentileRank != "x"))) ? t.promotionOnNextWin : t.numOfVictories(wins: f2.format((nextRankGlickoCutoff!-tlData.glicko!)/glickoForWin)), style: TextStyle(color: (tlData.standing < tlData.nextAt || ((nextRankGlickoCutoff!-tlData.glicko!)/glickoForWin < 0.5 && tlData.percentileRank != "x")) ? Colors.greenAccent : null))
|
||||
if (nextRankGlickoCutoff != null) TextSpan(text: (tlData.standing < tlData.nextAt || ((nextRankGlickoCutoff!-tlData.glicko!)/glickoForWin < 0.5 && ((tlData.rank != "x+" && tlData.rank != "z") || tlData.percentileRank != "x+"))) ? t.promotionOnNextWin : t.numOfVictories(wins: f2.format((nextRankGlickoCutoff!-tlData.glicko!)/glickoForWin)), style: TextStyle(color: (tlData.standing < tlData.nextAt || ((nextRankGlickoCutoff!-tlData.glicko!)/glickoForWin < 0.5 && tlData.percentileRank != "x+")) ? Colors.greenAccent : null))
|
||||
]
|
||||
)
|
||||
)
|
||||
|
|
|
@ -148,7 +148,7 @@ class _ZenithThingyState extends State<ZenithThingy> {
|
|||
const Positioned(left: 25, top: 20, child: Text("otal time", style: TextStyle(fontFamily: "Eurostile Round Extended"))),
|
||||
Padding(
|
||||
padding: const EdgeInsets.only(left: 10.0),
|
||||
child: Text("${getMoreNormalTime(record!.stats.finalTime)}%", style: TextStyle(
|
||||
child: Text("${getMoreNormalTime(record!.stats.finalTime)}", style: TextStyle(
|
||||
shadows: textShadow,
|
||||
fontFamily: "Eurostile Round Extended",
|
||||
fontSize: 36,
|
||||
|
@ -158,7 +158,6 @@ class _ZenithThingyState extends State<ZenithThingy> {
|
|||
)
|
||||
],
|
||||
),
|
||||
Text("Total time: ${getMoreNormalTime(record!.stats.finalTime)}", style: const TextStyle(color: Colors.white, fontFamily: "Eurostile Round Extended"), textAlign: TextAlign.center),
|
||||
Table(
|
||||
columnWidths: const {
|
||||
0: FixedColumnWidth(36)
|
||||
|
|
|
@ -2,7 +2,7 @@ name: tetra_stats
|
|||
description: Track your and other player stats in TETR.IO
|
||||
publish_to: 'none'
|
||||
|
||||
version: 1.6.3+29
|
||||
version: 1.6.4+30
|
||||
|
||||
environment:
|
||||
sdk: '>=3.0.0'
|
||||
|
|
Loading…
Reference in New Issue