Full leaderboard - full capabilities
This commit is contained in:
parent
e21ec84fc1
commit
c0d395235b
|
@ -66,6 +66,8 @@ const Map<String, double> rankCutoffs = {
|
|||
enum Stats {
|
||||
tr,
|
||||
glicko,
|
||||
gxe,
|
||||
s1tr,
|
||||
rd,
|
||||
gp,
|
||||
gw,
|
||||
|
@ -95,6 +97,8 @@ enum Stats {
|
|||
|
||||
const Map<Stats, String> chartsShortTitles = {
|
||||
Stats.tr: "TR",
|
||||
Stats.gxe: "Glixare",
|
||||
Stats.s1tr: "S1 TR",
|
||||
Stats.glicko: "Glicko",
|
||||
Stats.rd: "RD",
|
||||
Stats.gp: "GP",
|
||||
|
@ -351,6 +355,10 @@ class TetrioPlayer {
|
|||
return tlSeason1?.tr;
|
||||
case Stats.glicko:
|
||||
return tlSeason1?.glicko;
|
||||
case Stats.gxe:
|
||||
return tlSeason1?.gxe;
|
||||
case Stats.s1tr:
|
||||
return tlSeason1?.s1tr;
|
||||
case Stats.rd:
|
||||
return tlSeason1?.rd;
|
||||
case Stats.gp:
|
||||
|
@ -1414,6 +1422,7 @@ class TetraLeague {
|
|||
}
|
||||
|
||||
double get winrate => gamesWon / gamesPlayed;
|
||||
double get s1tr => gxe * 250;
|
||||
|
||||
TetraLeague.fromJson(Map<String, dynamic> json, ts) {
|
||||
timestamp = ts;
|
||||
|
@ -1451,7 +1460,7 @@ class TetraLeague {
|
|||
|
||||
TetrioPlayerFromLeaderboard convertToPlayerFromLeaderboard(String id) => TetrioPlayerFromLeaderboard(
|
||||
id, "", "user", -1, null, timestamp, gamesPlayed, gamesWon,
|
||||
tr, glicko??0, rd??noTrRd, rank, bestRank, apm??0, pps??0, vs??0, decaying);
|
||||
tr, gxe, glicko??0, rd??noTrRd, rank, bestRank, apm??0, pps??0, vs??0, decaying);
|
||||
|
||||
Map<String, dynamic> toJson() {
|
||||
final Map<String, dynamic> data = <String, dynamic>{};
|
||||
|
@ -1757,6 +1766,7 @@ class TetrioPlayersLeaderboard {
|
|||
avgPPS = 0,
|
||||
avgVS = 0,
|
||||
avgTR = 0,
|
||||
avgGlixare = 0,
|
||||
avgGlicko = 0,
|
||||
avgRD = 0,
|
||||
avgAPP = 0,
|
||||
|
@ -1775,6 +1785,7 @@ class TetrioPlayersLeaderboard {
|
|||
avgStride = 0,
|
||||
avgInfDS = 0,
|
||||
lowestTR = 25000,
|
||||
lowestGlixare = double.infinity,
|
||||
lowestGlicko = double.infinity,
|
||||
lowestRD = double.infinity,
|
||||
lowestWinrate = double.infinity,
|
||||
|
@ -1797,6 +1808,7 @@ class TetrioPlayersLeaderboard {
|
|||
lowestStride = double.infinity,
|
||||
lowestInfDS = double.infinity,
|
||||
highestTR = double.negativeInfinity,
|
||||
highestGlixare = double.negativeInfinity,
|
||||
highestGlicko = double.negativeInfinity,
|
||||
highestRD = double.negativeInfinity,
|
||||
highestWinrate = double.negativeInfinity,
|
||||
|
@ -1827,6 +1839,7 @@ class TetrioPlayersLeaderboard {
|
|||
highestGamesPlayed = 0,
|
||||
highestGamesWon = 0;
|
||||
String lowestTRid = "", lowestTRnick = "",
|
||||
lowestGlixareID = "", lowestGlixareNick = "",
|
||||
lowestGlickoID = "", lowestGlickoNick = "",
|
||||
lowestRdID = "", lowestRdNick = "",
|
||||
lowestGamesPlayedID = "", lowestGamesPlayedNick = "",
|
||||
|
@ -1851,6 +1864,7 @@ class TetrioPlayersLeaderboard {
|
|||
lowestStrideID = "", lowestStrideNick = "",
|
||||
lowestInfDSid = "", lowestInfDSnick = "",
|
||||
highestTRid = "", highestTRnick = "",
|
||||
highestGlixareID = "", highestGlixareNick = "",
|
||||
highestGlickoID = "", highestGlickoNick = "",
|
||||
highestRdID = "", highestRdNick = "",
|
||||
highestGamesPlayedID = "", highestGamesPlayedNick = "",
|
||||
|
@ -1879,6 +1893,7 @@ class TetrioPlayersLeaderboard {
|
|||
avgPPS += entry.pps;
|
||||
avgVS += entry.vs;
|
||||
avgTR += entry.tr;
|
||||
avgGlixare += entry.gxe;
|
||||
if (entry.glicko != null) avgGlicko += entry.glicko!;
|
||||
if (entry.rd != null) avgRD += entry.rd!;
|
||||
avgAPP += entry.nerdStats.app;
|
||||
|
@ -1903,6 +1918,11 @@ class TetrioPlayersLeaderboard {
|
|||
lowestTRid = entry.userId;
|
||||
lowestTRnick = entry.username;
|
||||
}
|
||||
if (entry.gxe < lowestGlixare){
|
||||
lowestGlixare = entry.gxe;
|
||||
lowestGlixareID = entry.userId;
|
||||
lowestGlixareNick = entry.username;
|
||||
}
|
||||
if (entry.glicko != null && entry.glicko! < lowestGlicko){
|
||||
lowestGlicko = entry.glicko!;
|
||||
lowestGlickoID = entry.userId;
|
||||
|
@ -2023,6 +2043,11 @@ class TetrioPlayersLeaderboard {
|
|||
highestTRid = entry.userId;
|
||||
highestTRnick = entry.username;
|
||||
}
|
||||
if (entry.gxe > highestGlixare){
|
||||
highestGlixare = entry.gxe;
|
||||
highestGlixareID = entry.userId;
|
||||
highestGlixareNick = entry.username;
|
||||
}
|
||||
if (entry.glicko != null && entry.glicko! > highestGlicko){
|
||||
highestGlicko = entry.glicko!;
|
||||
highestGlickoID = entry.userId;
|
||||
|
@ -2143,6 +2168,7 @@ class TetrioPlayersLeaderboard {
|
|||
avgPPS /= filtredLeaderboard.length;
|
||||
avgVS /= filtredLeaderboard.length;
|
||||
avgTR /= filtredLeaderboard.length;
|
||||
avgGlixare /= filtredLeaderboard.length;
|
||||
avgGlicko /= filtredLeaderboard.length;
|
||||
avgRD /= filtredLeaderboard.length;
|
||||
avgAPP /= filtredLeaderboard.length;
|
||||
|
@ -2162,7 +2188,7 @@ class TetrioPlayersLeaderboard {
|
|||
avgInfDS /= filtredLeaderboard.length;
|
||||
avgGamesPlayed = (totalGamesPlayed / filtredLeaderboard.length).floor();
|
||||
avgGamesWon = (totalGamesWon / filtredLeaderboard.length).floor();
|
||||
return [TetraLeague(timestamp: DateTime.now(), apm: avgAPM, pps: avgPPS, vs: avgVS, glicko: avgGlicko, rd: avgRD, gamesPlayed: avgGamesPlayed, gamesWon: avgGamesWon, bestRank: rank, gxe: -1, decaying: false, tr: avgTR, rank: rank == "" ? "z" : rank, percentileRank: rank, percentile: rankCutoffs[rank]!, standing: -1, standingLocal: -1, nextAt: -1, prevAt: -1),
|
||||
return [TetraLeague(timestamp: DateTime.now(), apm: avgAPM, pps: avgPPS, vs: avgVS, gxe: avgGlixare, glicko: avgGlicko, rd: avgRD, gamesPlayed: avgGamesPlayed, gamesWon: avgGamesWon, bestRank: rank, decaying: false, tr: avgTR, rank: rank == "" ? "z" : rank, percentileRank: rank, percentile: rankCutoffs[rank]!, standing: -1, standingLocal: -1, nextAt: -1, prevAt: -1),
|
||||
{
|
||||
"everyone": rank == "",
|
||||
"totalGamesPlayed": totalGamesPlayed,
|
||||
|
@ -2171,6 +2197,12 @@ class TetrioPlayersLeaderboard {
|
|||
"lowestTR": lowestTR,
|
||||
"lowestTRid": lowestTRid,
|
||||
"lowestTRnick": lowestTRnick,
|
||||
"lowestGlixare": lowestGlixare,
|
||||
"lowestGlixareID": lowestGlixareID,
|
||||
"lowestGlixareNick": lowestGlixareNick,
|
||||
"lowestS1tr": lowestGlixare * 250,
|
||||
"lowestS1trID": lowestGlixareID,
|
||||
"lowestS1trNick": lowestGlixareNick,
|
||||
"lowestGlicko": lowestGlicko,
|
||||
"lowestGlickoID": lowestGlickoID,
|
||||
"lowestGlickoNick": lowestGlickoNick,
|
||||
|
@ -2243,6 +2275,12 @@ class TetrioPlayersLeaderboard {
|
|||
"highestTR": highestTR,
|
||||
"highestTRid": highestTRid,
|
||||
"highestTRnick": highestTRnick,
|
||||
"highestGlixare": highestGlixare,
|
||||
"highestGlixareID": highestGlixareID,
|
||||
"highestGlixareNick": highestGlixareNick,
|
||||
"highestS1tr": highestGlixare * 250,
|
||||
"highestS1trID": highestGlixareID,
|
||||
"highestS1trNick": highestGlixareNick,
|
||||
"highestGlicko": highestGlicko,
|
||||
"highestGlickoID": highestGlickoID,
|
||||
"highestGlickoNick": highestGlickoNick,
|
||||
|
@ -2327,8 +2365,8 @@ class TetrioPlayersLeaderboard {
|
|||
"avgPlonk": avgPlonk,
|
||||
"avgStride": avgStride,
|
||||
"avgInfDS": avgInfDS,
|
||||
"toEnterTR": rank.toLowerCase() != "z" ? leaderboard[(leaderboard.length * rankCutoffs[rank]!).floor()].tr : lowestTR,
|
||||
"toEnterGlicko": rank.toLowerCase() != "z" ? leaderboard[(leaderboard.length * rankCutoffs[rank]!).floor()].glicko : 0,
|
||||
"toEnterTR": rank.toLowerCase() != "z" ? leaderboard[(leaderboard.length * rankCutoffs[rank]!).floor()-1].tr : lowestTR,
|
||||
"toEnterGlicko": rank.toLowerCase() != "z" ? leaderboard[(leaderboard.length * rankCutoffs[rank]!).floor()-1].glicko : 0,
|
||||
"entries": filtredLeaderboard
|
||||
}];
|
||||
}else{
|
||||
|
@ -2447,6 +2485,7 @@ class TetrioPlayerFromLeaderboard {
|
|||
late int gamesPlayed;
|
||||
late int gamesWon;
|
||||
late double tr;
|
||||
late double gxe;
|
||||
late double? glicko;
|
||||
late double? rd;
|
||||
late String rank;
|
||||
|
@ -2469,6 +2508,7 @@ class TetrioPlayerFromLeaderboard {
|
|||
this.gamesPlayed,
|
||||
this.gamesWon,
|
||||
this.tr,
|
||||
this.gxe,
|
||||
this.glicko,
|
||||
this.rd,
|
||||
this.rank,
|
||||
|
@ -2484,6 +2524,7 @@ class TetrioPlayerFromLeaderboard {
|
|||
|
||||
double get winrate => gamesWon / gamesPlayed;
|
||||
double get esttracc => estTr.esttr - tr;
|
||||
double get s1tr => gxe * 250;
|
||||
|
||||
TetrioPlayerFromLeaderboard.fromJson(Map<String, dynamic> json, DateTime ts) {
|
||||
userId = json['_id'];
|
||||
|
@ -2495,6 +2536,7 @@ class TetrioPlayerFromLeaderboard {
|
|||
gamesPlayed = json['league']['gamesplayed'] as int;
|
||||
gamesWon = json['league']['gameswon'] as int;
|
||||
tr = json['league']['tr'] != null ? json['league']['tr'].toDouble() : 0;
|
||||
gxe = json['league']['gxe']??-1;
|
||||
glicko = json['league']['glicko']?.toDouble();
|
||||
rd = json['league']['rd']?.toDouble();
|
||||
rank = json['league']['rank'];
|
||||
|
@ -2514,6 +2556,10 @@ class TetrioPlayerFromLeaderboard {
|
|||
return tr;
|
||||
case Stats.glicko:
|
||||
return glicko??-1;
|
||||
case Stats.gxe:
|
||||
return gxe;
|
||||
case Stats.s1tr:
|
||||
return s1tr;
|
||||
case Stats.rd:
|
||||
return rd??-1;
|
||||
case Stats.gp:
|
||||
|
|
|
@ -636,18 +636,12 @@ 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({double? after}) async {
|
||||
TetrioPlayersLeaderboard? cached = _cache.get("league${after != null ? after.toString() : ""}", TetrioPlayersLeaderboard);
|
||||
Future<TetrioPlayersLeaderboard> fetchTLLeaderboard() async {
|
||||
TetrioPlayersLeaderboard? cached = _cache.get("league", 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', {
|
||||
"limit": "100",
|
||||
if (after != null) "after": "$after:0:0"
|
||||
});
|
||||
}
|
||||
|
||||
Uri url = Uri.https('ts.dan63.by', 'beanserver_blaster/leaderboard.json');
|
||||
|
||||
try{
|
||||
final response = await client.get(url);
|
||||
|
||||
|
@ -655,16 +649,10 @@ class TetrioService extends DB {
|
|||
case 200:
|
||||
_lbPositions.clear();
|
||||
var rawJson = jsonDecode(response.body);
|
||||
if (rawJson['success']) { // if api confirmed that everything ok
|
||||
TetrioPlayersLeaderboard leaderboard = TetrioPlayersLeaderboard.fromJson(rawJson['data']['entries'], "league", DateTime.fromMillisecondsSinceEpoch(rawJson['cache']['cached_at']));
|
||||
developer.log("fetchTLLeaderboard: Leaderboard retrieved and cached", name: "services/tetrio_crud");
|
||||
//_leaderboardsCache[rawJson['cache']['cached_until'].toString()] = leaderboard;
|
||||
_cache.store(leaderboard, rawJson['cache']['cached_until']);
|
||||
return leaderboard;
|
||||
} else { // idk how to hit that one
|
||||
developer.log("fetchTLLeaderboard: Bruh", name: "services/tetrio_crud", error: rawJson);
|
||||
throw Exception("Failed to get leaderboard (problems on the tetr.io side)"); // will it be on tetr.io side?
|
||||
}
|
||||
TetrioPlayersLeaderboard leaderboard = TetrioPlayersLeaderboard.fromJson(rawJson['data'], "league", DateTime.fromMillisecondsSinceEpoch(rawJson['created']));
|
||||
developer.log("fetchTLLeaderboard: Leaderboard retrieved and cached", name: "services/tetrio_crud");
|
||||
_cache.store(leaderboard, rawJson['cache_until']);
|
||||
return leaderboard;
|
||||
case 403:
|
||||
throw TetrioForbidden();
|
||||
case 429:
|
||||
|
@ -686,19 +674,19 @@ 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;
|
||||
}
|
||||
}
|
||||
// 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 {
|
||||
|
|
|
@ -213,7 +213,7 @@ class _MainState extends State<MainView> with TickerProviderStateMixin {
|
|||
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 && summaries.league.gamesPlayed > 9) rankAverages = everyone?.averages[summaries.league.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);
|
||||
|
@ -482,8 +482,8 @@ class _MainState extends State<MainView> with TickerProviderStateMixin {
|
|||
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
|
||||
averages: rankAverages,
|
||||
lbPositions: meAmongEveryone
|
||||
),
|
||||
),
|
||||
SizedBox(
|
||||
|
@ -523,8 +523,8 @@ class _MainState extends State<MainView> with TickerProviderStateMixin {
|
|||
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
|
||||
averages: rankAverages,
|
||||
lbPositions: meAmongEveryone
|
||||
),
|
||||
_TLRecords(userID: snapshot.data![0].userId, changePlayer: changePlayer, data: snapshot.data![3].records, wasActiveInTL: true, oldMathcesHere: _TLHistoryWasFetched, separateScrollController: true),
|
||||
_History(chartsData: chartsData, changePlayer: changePlayer, userID: _searchFor, update: _justUpdate, wasActiveInTL: snapshot.data![1].league.gamesPlayed > 0),
|
||||
|
|
|
@ -379,6 +379,8 @@ class RankState extends State<RankView> with SingleTickerProviderStateMixin {
|
|||
child: ListView(
|
||||
children: [
|
||||
_ListEntry(value: widget.rank[1]["lowestTR"], label: t.statCellNum.tr.replaceAll(RegExp(r'\n'), " "), id: widget.rank[1]["lowestTRid"], username: widget.rank[1]["lowestTRnick"], approximate: false, fractionDigits: 2),
|
||||
_ListEntry(value: widget.rank[1]["lowestGlixare"], label: "Glixare", id: widget.rank[1]["lowestGlixareID"], username: widget.rank[1]["lowestGlixareNick"], approximate: false, fractionDigits: 3),
|
||||
_ListEntry(value: widget.rank[1]["lowestS1tr"], label: "S1 ${t.statCellNum.tr.replaceAll(RegExp(r'\n'), " ")}", id: widget.rank[1]["lowestS1trID"], username: widget.rank[1]["lowestS1trNick"], approximate: false, fractionDigits: 2),
|
||||
_ListEntry(value: widget.rank[1]["lowestGlicko"], label: "Glicko", id: widget.rank[1]["lowestGlickoID"], username: widget.rank[1]["lowestGlickoNick"], approximate: false, fractionDigits: 2),
|
||||
_ListEntry(value: widget.rank[1]["lowestRD"], label: t.statCellNum.rd.replaceAll(RegExp(r'\n'), " "), id: widget.rank[1]["lowestRdID"], username: widget.rank[1]["lowestRdNick"], approximate: false, fractionDigits: 3),
|
||||
_ListEntry(value: widget.rank[1]["lowestGamesPlayed"], label: t.statCellNum.gamesPlayed.replaceAll(RegExp(r'\n'), " "), id: widget.rank[1]["lowestGamesPlayedID"], username: widget.rank[1]["lowestGamesPlayedNick"], approximate: false),
|
||||
|
@ -413,6 +415,8 @@ class RankState extends State<RankView> with SingleTickerProviderStateMixin {
|
|||
Expanded(
|
||||
child: ListView(children: [
|
||||
_ListEntry(value: widget.rank[0].tr, label: t.statCellNum.tr.replaceAll(RegExp(r'\n'), " "), id: "", username: "", approximate: true, fractionDigits: 2),
|
||||
_ListEntry(value: widget.rank[0].gxe, label: "Glixare", id: "", username: "", approximate: false, fractionDigits: 3),
|
||||
_ListEntry(value: widget.rank[0].s1tr, label: "S1 ${t.statCellNum.tr.replaceAll(RegExp(r'\n'), " ")}", id: "", username: "", approximate: false, fractionDigits: 2),
|
||||
_ListEntry(value: widget.rank[0].glicko, label: "Glicko", id: "", username: "", approximate: true, fractionDigits: 2),
|
||||
_ListEntry(value: widget.rank[0].rd, label: t.statCellNum.rd.replaceAll(RegExp(r'\n'), " "), id: "", username: "", approximate: true, fractionDigits: 3),
|
||||
_ListEntry(value: widget.rank[0].gamesPlayed, label: t.statCellNum.gamesPlayed.replaceAll(RegExp(r'\n'), " "), id: "", username: "", approximate: true, fractionDigits: 0),
|
||||
|
@ -446,6 +450,8 @@ class RankState extends State<RankView> with SingleTickerProviderStateMixin {
|
|||
child: ListView(
|
||||
children: [
|
||||
_ListEntry(value: widget.rank[1]["highestTR"], label: t.statCellNum.tr.replaceAll(RegExp(r'\n'), " "), id: widget.rank[1]["highestTRid"], username: widget.rank[1]["highestTRnick"], approximate: false, fractionDigits: 2),
|
||||
_ListEntry(value: widget.rank[1]["highestGlixare"], label: "Glixare", id: widget.rank[1]["highestGlixareID"], username: widget.rank[1]["highestGlixareNick"], approximate: false, fractionDigits: 3),
|
||||
_ListEntry(value: widget.rank[1]["highestS1tr"], label: "S1 ${t.statCellNum.tr.replaceAll(RegExp(r'\n'), " ")}", id: widget.rank[1]["highestS1trID"], username: widget.rank[1]["highestS1trNick"], approximate: false, fractionDigits: 2),
|
||||
_ListEntry(value: widget.rank[1]["highestGlicko"], label: "Glicko", id: widget.rank[1]["highestGlickoID"], username: widget.rank[1]["highestGlickoNick"], approximate: false, fractionDigits: 2),
|
||||
_ListEntry(value: widget.rank[1]["highestRD"], label: t.statCellNum.rd.replaceAll(RegExp(r'\n'), " "), id: widget.rank[1]["highestRdID"], username: widget.rank[1]["highestRdNick"], approximate: false, fractionDigits: 3),
|
||||
_ListEntry(value: widget.rank[1]["highestGamesPlayed"], label: t.statCellNum.gamesPlayed.replaceAll(RegExp(r'\n'), " "), id: widget.rank[1]["highestGamesPlayedID"], username: widget.rank[1]["highestGamesPlayedNick"], approximate: false),
|
||||
|
@ -517,7 +523,7 @@ class _ListEntry extends StatelessWidget {
|
|||
children: [
|
||||
Text(f.format(value),
|
||||
style: const TextStyle(fontSize: 22, height: 0.9)),
|
||||
if (id.isNotEmpty) Text(t.forPlayer(username: username))
|
||||
if (id.isNotEmpty) Text(t.forPlayer(username: username), style: TextStyle(color: Colors.grey, fontWeight: FontWeight.w100),)
|
||||
],
|
||||
),
|
||||
onTap: id.isNotEmpty
|
||||
|
|
|
@ -4,13 +4,13 @@ import 'package:flutter/material.dart';
|
|||
import 'package:intl/intl.dart';
|
||||
import 'package:tetra_stats/data_objects/tetrio.dart';
|
||||
import 'package:tetra_stats/gen/strings.g.dart';
|
||||
import 'package:tetra_stats/services/tetrio_crud.dart';
|
||||
import 'package:tetra_stats/main.dart';
|
||||
import 'package:tetra_stats/views/main_view.dart';
|
||||
import 'package:tetra_stats/views/rank_averages_view.dart';
|
||||
import 'package:tetra_stats/views/ranks_averages_view.dart';
|
||||
import 'package:window_manager/window_manager.dart';
|
||||
import 'package:tetra_stats/widgets/text_timestamp.dart';
|
||||
|
||||
final TetrioService _teto = TetrioService();
|
||||
List<DropdownMenuItem> _itemStats = [for (MapEntry e in chartsShortTitles.entries) DropdownMenuItem(value: e.key, child: Text(e.value))];
|
||||
Stats _sortBy = Stats.tr;
|
||||
bool reversed = false;
|
||||
|
@ -64,148 +64,155 @@ class TLLeaderboardState extends State<TLLeaderboardView> {
|
|||
),
|
||||
backgroundColor: Colors.black,
|
||||
body: SafeArea(
|
||||
child: FutureBuilder(
|
||||
future: _teto.fetchTLLeaderboard(),
|
||||
builder: (context, snapshot) {
|
||||
switch (snapshot.connectionState) {
|
||||
case ConnectionState.none:
|
||||
case ConnectionState.waiting:
|
||||
case ConnectionState.active:
|
||||
return const Center(child: CircularProgressIndicator());
|
||||
case ConnectionState.done:
|
||||
final allPlayers = snapshot.data?.getStatRanking(snapshot.data!.leaderboard, _sortBy, reversed: reversed, country: _country);
|
||||
if (!kIsWeb && !Platform.isAndroid && !Platform.isIOS) windowManager.setTitle("Tetra Stats: ${t.tlLeaderboard} - ${t.players(n: allPlayers != null ? allPlayers.length : 0)}");
|
||||
bool bigScreen = MediaQuery.of(context).size.width > 768;
|
||||
return NestedScrollView(
|
||||
headerSliverBuilder: (context, value) {
|
||||
String howManyPlayers(int numberOfPlayers) => Intl.plural(
|
||||
numberOfPlayers,
|
||||
zero: t.lbViewZeroEntrys,
|
||||
one: t.lbViewOneEntry,
|
||||
other: t.lbViewManyEntrys(numberOfPlayers: t.players(n: numberOfPlayers)),
|
||||
name: 'howManyPeople',
|
||||
args: [numberOfPlayers],
|
||||
desc: 'Description of how many people are seen in a place.',
|
||||
examples: const {'numberOfPeople': 3},
|
||||
);
|
||||
return [
|
||||
SliverToBoxAdapter(
|
||||
child: Padding(
|
||||
padding: const EdgeInsets.only(left: 16),
|
||||
child: Wrap(
|
||||
direction: Axis.horizontal,
|
||||
alignment: WrapAlignment.spaceBetween,
|
||||
children: [
|
||||
Text(
|
||||
howManyPlayers(allPlayers.length),
|
||||
style: const TextStyle(color: Colors.white, fontSize: 25),
|
||||
),
|
||||
TextButton(onPressed: (){
|
||||
Navigator.push(
|
||||
context,
|
||||
MaterialPageRoute(
|
||||
builder: (context) => RankView(rank: snapshot.data!.getAverageOfRank("")),
|
||||
),
|
||||
);
|
||||
}, child: Text(t.everyoneAverages,
|
||||
style: const TextStyle(fontSize: 25)))
|
||||
],)
|
||||
)),
|
||||
SliverToBoxAdapter(child: Padding(
|
||||
padding: const EdgeInsets.only(left: 16),
|
||||
child: Wrap(
|
||||
direction: Axis.horizontal,
|
||||
alignment: WrapAlignment.start,
|
||||
crossAxisAlignment: WrapCrossAlignment.center,
|
||||
spacing: 16,
|
||||
children: [
|
||||
Row(
|
||||
mainAxisSize: MainAxisSize.min,
|
||||
crossAxisAlignment: CrossAxisAlignment.baseline,
|
||||
textBaseline: TextBaseline.alphabetic,
|
||||
children: [
|
||||
Text("${t.sortBy}: ",
|
||||
style: const TextStyle(color: Colors.white, fontSize: 25)),
|
||||
DropdownButton(items: _itemStats, value: _sortBy, onChanged: ((value) {
|
||||
_sortBy = value;
|
||||
setState(() {});
|
||||
}),),
|
||||
],
|
||||
),
|
||||
Row(
|
||||
mainAxisSize: MainAxisSize.min,
|
||||
crossAxisAlignment: CrossAxisAlignment.baseline,
|
||||
textBaseline: TextBaseline.alphabetic,
|
||||
children: [
|
||||
Text("${t.reversed}: ",
|
||||
style: const TextStyle(color: Colors.white, fontSize: 25)),
|
||||
Padding(
|
||||
padding: const EdgeInsets.fromLTRB(0, 5.5, 0, 7.5),
|
||||
child: Checkbox(value: reversed,
|
||||
checkColor: Colors.black,
|
||||
onChanged: ((value) {
|
||||
reversed = value!;
|
||||
setState(() {});
|
||||
}),),
|
||||
),
|
||||
],
|
||||
),
|
||||
Row(
|
||||
mainAxisSize: MainAxisSize.min,
|
||||
crossAxisAlignment: CrossAxisAlignment.baseline,
|
||||
textBaseline: TextBaseline.alphabetic,
|
||||
children: [
|
||||
Text("${t.country}: ",
|
||||
style: const TextStyle(color: Colors.white, fontSize: 25)),
|
||||
DropdownButton(items: _itemCountries, value: _country, onChanged: ((value) {
|
||||
_country = value;
|
||||
setState(() {});
|
||||
}),),
|
||||
],
|
||||
),
|
||||
],
|
||||
),
|
||||
),),
|
||||
const SliverToBoxAdapter(child: Divider())
|
||||
];
|
||||
},
|
||||
body: ListView.builder(
|
||||
itemCount: allPlayers!.length,
|
||||
prototypeItem: ListTile(
|
||||
leading: Text("0", style: TextStyle(fontFamily: "Eurostile Round Extended", fontSize: bigScreen ? 28 : 24, height: 0.9)),
|
||||
title: Text("ehhh...", style: TextStyle(fontFamily: bigScreen ? "Eurostile Round Extended" : "Eurostile Round", height: 0.9)),
|
||||
trailing: SizedBox(height: bigScreen ? 48 : 36, width: 1,),
|
||||
subtitle: const Text("eh..."),
|
||||
child: FutureBuilder(
|
||||
future: teto.fetchTLLeaderboard(),
|
||||
builder: (context, snapshot) {
|
||||
switch (snapshot.connectionState) {
|
||||
case ConnectionState.none:
|
||||
case ConnectionState.waiting:
|
||||
case ConnectionState.active:
|
||||
return const Center(child: CircularProgressIndicator());
|
||||
case ConnectionState.done:
|
||||
if (snapshot.hasData){
|
||||
final allPlayers = snapshot.data?.getStatRanking(snapshot.data!.leaderboard, _sortBy, reversed: reversed, country: _country);
|
||||
if (!kIsWeb && !Platform.isAndroid && !Platform.isIOS) windowManager.setTitle("Tetra Stats: ${t.tlLeaderboard} - ${t.players(n: allPlayers != null ? allPlayers.length : 0)}");
|
||||
bool bigScreen = MediaQuery.of(context).size.width > 768;
|
||||
return NestedScrollView(
|
||||
headerSliverBuilder: (context, value) {
|
||||
return [
|
||||
SliverToBoxAdapter(
|
||||
child: Padding(
|
||||
padding: const EdgeInsets.only(left: 16),
|
||||
child: Wrap(
|
||||
direction: Axis.horizontal,
|
||||
alignment: WrapAlignment.spaceBetween,
|
||||
children: [
|
||||
Text(
|
||||
"${t.players(n: allPlayers.length)} • ${t.sprintAndBlitsRelevance(date: timestamp(snapshot.data!.timestamp))}",
|
||||
style: const TextStyle(color: Colors.white, fontSize: 25),
|
||||
),
|
||||
TextButton(onPressed: (){
|
||||
Navigator.push(
|
||||
context,
|
||||
MaterialPageRoute(
|
||||
builder: (context) => RankView(rank: snapshot.data!.getAverageOfRank("")),
|
||||
),
|
||||
itemBuilder: (context, index) {
|
||||
return ListTile(
|
||||
leading: Text(
|
||||
(index+1).toString(),
|
||||
style: TextStyle(fontFamily: "Eurostile Round Extended", fontSize: bigScreen ? 28 : 24, height: 0.9)
|
||||
);
|
||||
}, child: Text(t.everyoneAverages,
|
||||
style: const TextStyle(fontSize: 25)))
|
||||
],)
|
||||
)),
|
||||
SliverToBoxAdapter(child: Padding(
|
||||
padding: const EdgeInsets.only(left: 16),
|
||||
child: Wrap(
|
||||
direction: Axis.horizontal,
|
||||
alignment: WrapAlignment.start,
|
||||
crossAxisAlignment: WrapCrossAlignment.center,
|
||||
spacing: 16,
|
||||
children: [
|
||||
Row(
|
||||
mainAxisSize: MainAxisSize.min,
|
||||
crossAxisAlignment: CrossAxisAlignment.baseline,
|
||||
textBaseline: TextBaseline.alphabetic,
|
||||
children: [
|
||||
Text("${t.sortBy}: ",
|
||||
style: const TextStyle(color: Colors.white, fontSize: 25)),
|
||||
DropdownButton(items: _itemStats, value: _sortBy, onChanged: ((value) {
|
||||
_sortBy = value;
|
||||
setState(() {});
|
||||
}),),
|
||||
],
|
||||
),
|
||||
Row(
|
||||
mainAxisSize: MainAxisSize.min,
|
||||
crossAxisAlignment: CrossAxisAlignment.baseline,
|
||||
textBaseline: TextBaseline.alphabetic,
|
||||
children: [
|
||||
Text("${t.reversed}: ",
|
||||
style: const TextStyle(color: Colors.white, fontSize: 25)),
|
||||
Padding(
|
||||
padding: const EdgeInsets.fromLTRB(0, 5.5, 0, 7.5),
|
||||
child: Checkbox(value: reversed,
|
||||
checkColor: Colors.black,
|
||||
onChanged: ((value) {
|
||||
reversed = value!;
|
||||
setState(() {});
|
||||
}),),
|
||||
),
|
||||
title: Text(allPlayers[index].username, style: TextStyle(fontFamily: bigScreen ? "Eurostile Round Extended" : "Eurostile Round", height: 0.9)),
|
||||
subtitle: (bigScreen || _sortBy != Stats.tr) ? Text(_sortBy == Stats.tr ? "${f2.format(allPlayers[index].apm)} APM, ${f2.format(allPlayers[index].pps)} PPS, ${f2.format(allPlayers[index].vs)} VS, ${f2.format(allPlayers[index].nerdStats.app)} APP, ${f2.format(allPlayers[index].nerdStats.vsapm)} VS/APM" : "${_f4.format(allPlayers[index].getStatByEnum(_sortBy))} ${chartsShortTitles[_sortBy]}",
|
||||
style: TextStyle(fontFamily: "Eurostile Round Condensed", fontSize: bigScreen ? null : 13, color: _sortBy == Stats.tr ? Colors.grey : null)) : null,
|
||||
trailing: Row(
|
||||
mainAxisSize: MainAxisSize.min,
|
||||
children: [
|
||||
Text("${f2.format(allPlayers[index].tr)} TR", style: const TextStyle(fontSize: 28)),
|
||||
Image.asset("res/tetrio_tl_alpha_ranks/${allPlayers[index].rank}.png", height: bigScreen ? 48 : 36),
|
||||
],
|
||||
),
|
||||
onTap: () {
|
||||
Navigator.push(
|
||||
context,
|
||||
MaterialPageRoute(
|
||||
builder: (context) => MainView(player: allPlayers[index].userId),
|
||||
maintainState: false,
|
||||
),
|
||||
);
|
||||
},
|
||||
);
|
||||
}));
|
||||
}
|
||||
})),
|
||||
],
|
||||
),
|
||||
Row(
|
||||
mainAxisSize: MainAxisSize.min,
|
||||
crossAxisAlignment: CrossAxisAlignment.baseline,
|
||||
textBaseline: TextBaseline.alphabetic,
|
||||
children: [
|
||||
Text("${t.country}: ",
|
||||
style: const TextStyle(color: Colors.white, fontSize: 25)),
|
||||
DropdownButton(items: _itemCountries, value: _country, onChanged: ((value) {
|
||||
_country = value;
|
||||
setState(() {});
|
||||
}),),
|
||||
],
|
||||
),
|
||||
],
|
||||
),
|
||||
),),
|
||||
const SliverToBoxAdapter(child: Divider())
|
||||
];
|
||||
},
|
||||
body: ListView.builder(
|
||||
itemCount: allPlayers!.length,
|
||||
prototypeItem: ListTile(
|
||||
leading: Text("0", style: TextStyle(fontFamily: "Eurostile Round Extended", fontSize: bigScreen ? 28 : 24, height: 0.9)),
|
||||
title: Text("ehhh...", style: TextStyle(fontFamily: bigScreen ? "Eurostile Round Extended" : "Eurostile Round", height: 0.9)),
|
||||
trailing: SizedBox(height: bigScreen ? 48 : 36, width: 1,),
|
||||
subtitle: const Text("eh..."),
|
||||
),
|
||||
itemBuilder: (context, index) {
|
||||
return ListTile(
|
||||
leading: Text(
|
||||
(index+1).toString(),
|
||||
style: TextStyle(fontFamily: "Eurostile Round Extended", fontSize: bigScreen ? 28 : 24, height: 0.9)
|
||||
),
|
||||
title: Text(allPlayers[index].username, style: TextStyle(fontFamily: bigScreen ? "Eurostile Round Extended" : "Eurostile Round", height: 0.9)),
|
||||
subtitle: (bigScreen || _sortBy != Stats.tr) ? Text(_sortBy == Stats.tr ? "${f2.format(allPlayers[index].apm)} APM, ${f2.format(allPlayers[index].pps)} PPS, ${f2.format(allPlayers[index].vs)} VS, ${f2.format(allPlayers[index].nerdStats.app)} APP, ${f2.format(allPlayers[index].nerdStats.vsapm)} VS/APM" : "${_f4.format(allPlayers[index].getStatByEnum(_sortBy))} ${chartsShortTitles[_sortBy]}",
|
||||
style: TextStyle(fontFamily: "Eurostile Round Condensed", fontSize: bigScreen ? null : 13, color: _sortBy == Stats.tr ? Colors.grey : null)) : null,
|
||||
trailing: Row(
|
||||
mainAxisSize: MainAxisSize.min,
|
||||
children: [
|
||||
Text("${f2.format(allPlayers[index].tr)} TR", style: const TextStyle(fontSize: 28)),
|
||||
Image.asset("res/tetrio_tl_alpha_ranks/${allPlayers[index].rank}.png", height: bigScreen ? 48 : 36),
|
||||
],
|
||||
),
|
||||
onTap: () {
|
||||
Navigator.push(
|
||||
context,
|
||||
MaterialPageRoute(
|
||||
builder: (context) => MainView(player: allPlayers[index].userId),
|
||||
maintainState: false,
|
||||
),
|
||||
);
|
||||
},
|
||||
);
|
||||
}));
|
||||
}
|
||||
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 Text("end of FutureBuilder");
|
||||
}
|
||||
})),
|
||||
);
|
||||
}
|
||||
}
|
||||
|
|
|
@ -2,7 +2,7 @@ name: tetra_stats
|
|||
description: Track your and other player stats in TETR.IO
|
||||
publish_to: 'none'
|
||||
|
||||
version: 1.6.5+31
|
||||
version: 1.6.6+32
|
||||
|
||||
environment:
|
||||
sdk: '>=3.0.0'
|
||||
|
|
Loading…
Reference in New Issue