Compare commits
2 Commits
e5ffa9711e
...
ce2fb89ccf
Author | SHA1 | Date |
---|---|---|
dan63047 | ce2fb89ccf | |
dan63047 | 7cb1fc0543 |
|
@ -3,6 +3,7 @@
|
||||||
import 'dart:math';
|
import 'dart:math';
|
||||||
import 'package:flutter/foundation.dart';
|
import 'package:flutter/foundation.dart';
|
||||||
import 'package:flutter/material.dart';
|
import 'package:flutter/material.dart';
|
||||||
|
import 'package:tetra_stats/data_objects/tetra_stats.dart';
|
||||||
import 'package:tetra_stats/gen/strings.g.dart';
|
import 'package:tetra_stats/gen/strings.g.dart';
|
||||||
import 'package:vector_math/vector_math.dart';
|
import 'package:vector_math/vector_math.dart';
|
||||||
|
|
||||||
|
@ -42,25 +43,26 @@ const Map<String, double> rankCutoffs = {
|
||||||
"z": -1,
|
"z": -1,
|
||||||
"": 0.5
|
"": 0.5
|
||||||
};
|
};
|
||||||
// const Map<String, double> rankTargets = {
|
const Map<String, double> rankTargets = {
|
||||||
// "x": 24503.75, // where that comes from?
|
"x+": 24000.00,
|
||||||
// "u": 23038,
|
"x": 22500.00,
|
||||||
// "ss": 21583,
|
"u": 20000.00,
|
||||||
// "s+": 20128,
|
"ss": 18000.00,
|
||||||
// "s": 18673,
|
"s+": 16500.00,
|
||||||
// "s-": 16975,
|
"s": 15200.00,
|
||||||
// "a+": 15035,
|
"s-": 13800.00,
|
||||||
// "a": 13095,
|
"a+": 12000.00,
|
||||||
// "a-": 11155,
|
"a": 10500.00,
|
||||||
// "b+": 9215,
|
"a-": 9000.00,
|
||||||
// "b": 7275,
|
"b+": 7400.00,
|
||||||
// "b-": 5335,
|
"b": 5700.00,
|
||||||
// "c+": 3880,
|
"b-": 4200.00,
|
||||||
// "c": 2425,
|
"c+": 3000.00,
|
||||||
// "c-": 1213,
|
"c": 2000.00,
|
||||||
// "d+": 606,
|
"c-": 1300.00,
|
||||||
// "d": 0,
|
"d+": 800.00,
|
||||||
// };
|
"d": 0.00,
|
||||||
|
};
|
||||||
// DateTime seasonStart = DateTime.utc(2024, 08, 16, 18);
|
// DateTime seasonStart = DateTime.utc(2024, 08, 16, 18);
|
||||||
//DateTime seasonEnd = DateTime.utc(2024, 07, 26, 15);
|
//DateTime seasonEnd = DateTime.utc(2024, 07, 26, 15);
|
||||||
enum Stats {
|
enum Stats {
|
||||||
|
@ -424,7 +426,9 @@ class Summaries{
|
||||||
RecordSingle? sprint;
|
RecordSingle? sprint;
|
||||||
RecordSingle? blitz;
|
RecordSingle? blitz;
|
||||||
RecordSingle? zenith;
|
RecordSingle? zenith;
|
||||||
|
RecordSingle? zenithCareerBest; // leaderboard best, not overall
|
||||||
RecordSingle? zenithEx;
|
RecordSingle? zenithEx;
|
||||||
|
RecordSingle? zenithExCareerBest; // leaderboard best, not overall
|
||||||
late List<Achievement> achievements;
|
late List<Achievement> achievements;
|
||||||
late TetraLeague league;
|
late TetraLeague league;
|
||||||
late TetrioZen zen;
|
late TetrioZen zen;
|
||||||
|
@ -436,7 +440,9 @@ class Summaries{
|
||||||
if (json['40l']['record'] != null) sprint = RecordSingle.fromJson(json['40l']['record'], json['40l']['rank'], json['40l']['rank_local']);
|
if (json['40l']['record'] != null) sprint = RecordSingle.fromJson(json['40l']['record'], json['40l']['rank'], json['40l']['rank_local']);
|
||||||
if (json['blitz']['record'] != null) blitz = RecordSingle.fromJson(json['blitz']['record'], json['blitz']['rank'], json['40l']['rank_local']);
|
if (json['blitz']['record'] != null) blitz = RecordSingle.fromJson(json['blitz']['record'], json['blitz']['rank'], json['40l']['rank_local']);
|
||||||
if (json['zenith']['record'] != null) zenith = RecordSingle.fromJson(json['zenith']['record'], json['zenith']['rank'], json['zenith']['rank_local']);
|
if (json['zenith']['record'] != null) zenith = RecordSingle.fromJson(json['zenith']['record'], json['zenith']['rank'], json['zenith']['rank_local']);
|
||||||
|
if (json['zenith']['best']['record'] != null) zenithCareerBest = RecordSingle.fromJson(json['zenith']['best']['record'], json['zenith']['best']['rank'], -1);
|
||||||
if (json['zenithex']['record'] != null) zenithEx = RecordSingle.fromJson(json['zenithex']['record'], json['zenithex']['rank'], json['zenithex']['rank_local']);
|
if (json['zenithex']['record'] != null) zenithEx = RecordSingle.fromJson(json['zenithex']['record'], json['zenithex']['rank'], json['zenithex']['rank_local']);
|
||||||
|
if (json['zenithex']['best']['record'] != null) zenithCareerBest = RecordSingle.fromJson(json['zenithex']['best']['record'], json['zenith']['best']['rank'], -1);
|
||||||
achievements = [for (var achievement in json['achievements']) Achievement.fromJson(achievement)];
|
achievements = [for (var achievement in json['achievements']) Achievement.fromJson(achievement)];
|
||||||
league = TetraLeague.fromJson(json['league'], DateTime.now());
|
league = TetraLeague.fromJson(json['league'], DateTime.now());
|
||||||
zen = TetrioZen.fromJson(json['zen']);
|
zen = TetrioZen.fromJson(json['zen']);
|
||||||
|
@ -2612,3 +2618,44 @@ class TetrioPlayerFromLeaderboard {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
class CutoffTetrio {
|
||||||
|
late int pos;
|
||||||
|
late double percentile;
|
||||||
|
late double tr;
|
||||||
|
late double targetTr;
|
||||||
|
late double apm;
|
||||||
|
late double pps;
|
||||||
|
late double vs;
|
||||||
|
late int count;
|
||||||
|
late double countPercentile;
|
||||||
|
|
||||||
|
CutoffTetrio.fromJson(Map<String, dynamic> json, int total){
|
||||||
|
pos = json['pos'];
|
||||||
|
percentile = json['percentile'].toDouble();
|
||||||
|
tr = json['tr'].toDouble();
|
||||||
|
targetTr = json['targettr'].toDouble();
|
||||||
|
apm = json['apm'].toDouble();
|
||||||
|
pps = json['pps'].toDouble();
|
||||||
|
vs = json['vs'].toDouble();
|
||||||
|
count = json['count'];
|
||||||
|
countPercentile = count / total;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
class CutoffsTetrio {
|
||||||
|
late String id;
|
||||||
|
late DateTime timestamp;
|
||||||
|
late int total;
|
||||||
|
Map<String, CutoffTetrio> data = {};
|
||||||
|
|
||||||
|
CutoffsTetrio.fromJson(Map<String, dynamic> json){
|
||||||
|
id = json['s'];
|
||||||
|
timestamp = DateTime.parse(json['t']);
|
||||||
|
total = json['data']['total'];
|
||||||
|
json['data'].remove("total");
|
||||||
|
for (String rank in json['data'].keys){
|
||||||
|
data[rank] = CutoffTetrio.fromJson(json['data'][rank], total);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
|
@ -407,7 +407,53 @@ class TetrioService extends DB {
|
||||||
// Sidenote: as you can see, fetch functions looks and works pretty much same way, as described above,
|
// Sidenote: as you can see, fetch functions looks and works pretty much same way, as described above,
|
||||||
// so i'm going to document only unique differences between them
|
// so i'm going to document only unique differences between them
|
||||||
|
|
||||||
Future<Cutoffs?> fetchCutoffs() async {
|
Future<CutoffsTetrio?> fetchCutoffsTetrio() async {
|
||||||
|
CutoffsTetrio? cached = _cache.get("league_ranks", CutoffsTetrio);
|
||||||
|
if (cached != null) return cached;
|
||||||
|
|
||||||
|
Uri url;
|
||||||
|
if (kIsWeb) {
|
||||||
|
url = Uri.https('ts.dan63.by', 'oskware_bridge.php', {"endpoint": "cutoffs"});
|
||||||
|
} else {
|
||||||
|
url = Uri.https('ch.tetr.io', 'api/labs/league_ranks');
|
||||||
|
}
|
||||||
|
|
||||||
|
try{
|
||||||
|
final response = await client.get(url);
|
||||||
|
|
||||||
|
switch (response.statusCode) {
|
||||||
|
case 200:
|
||||||
|
Map<String, dynamic> rawData = jsonDecode(response.body);
|
||||||
|
CutoffsTetrio result = CutoffsTetrio.fromJson(rawData['data']);
|
||||||
|
_cache.store(result, rawData["cache"]["cached_until"]);
|
||||||
|
return result;
|
||||||
|
case 404:
|
||||||
|
developer.log("fetchCutoffsTetrio: Cutoffs are gone", name: "services/tetrio_crud", error: response.statusCode);
|
||||||
|
return null;
|
||||||
|
// if not 200 or 404 - throw a unique for each code exception
|
||||||
|
case 403:
|
||||||
|
throw TetrioForbidden();
|
||||||
|
case 429:
|
||||||
|
throw TetrioTooManyRequests();
|
||||||
|
case 418:
|
||||||
|
throw TetrioOskwareBridgeProblem();
|
||||||
|
case 500:
|
||||||
|
case 502:
|
||||||
|
case 503:
|
||||||
|
case 504:
|
||||||
|
developer.log("fetchCutoffsTetrio: Cutoffs are unavalable (${response.statusCode})", name: "services/tetrio_crud", error: response.statusCode);
|
||||||
|
return null;
|
||||||
|
default:
|
||||||
|
developer.log("fetchCutoffsTetrio: Failed to fetch top Cutoffs", name: "services/tetrio_crud", error: response.statusCode);
|
||||||
|
throw ConnectionIssue(response.statusCode, response.reasonPhrase??"No reason");
|
||||||
|
}
|
||||||
|
} on http.ClientException catch (e, s) { // If local http client fails
|
||||||
|
developer.log("$e, $s");
|
||||||
|
throw http.ClientException(e.message, e.uri); // just assuming, that our end user don't have acess to the internet
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
Future<Cutoffs?> fetchCutoffsBeanserver() async {
|
||||||
Cutoffs? cached = _cache.get("", Cutoffs);
|
Cutoffs? cached = _cache.get("", Cutoffs);
|
||||||
if (cached != null) return cached;
|
if (cached != null) return cached;
|
||||||
|
|
||||||
|
@ -429,7 +475,7 @@ class TetrioService extends DB {
|
||||||
_cache.store(result, rawData["cache_until"]);
|
_cache.store(result, rawData["cache_until"]);
|
||||||
return result;
|
return result;
|
||||||
case 404:
|
case 404:
|
||||||
developer.log("fetchCutoffs: Cutoffs are gone", name: "services/tetrio_crud", error: response.statusCode);
|
developer.log("fetchCutoffsBeanserver: Cutoffs are gone", name: "services/tetrio_crud", error: response.statusCode);
|
||||||
return null;
|
return null;
|
||||||
// if not 200 or 404 - throw a unique for each code exception
|
// if not 200 or 404 - throw a unique for each code exception
|
||||||
case 403:
|
case 403:
|
||||||
|
@ -442,10 +488,10 @@ class TetrioService extends DB {
|
||||||
case 502:
|
case 502:
|
||||||
case 503:
|
case 503:
|
||||||
case 504:
|
case 504:
|
||||||
developer.log("fetchCutoffs: Cutoffs are unavalable (${response.statusCode})", name: "services/tetrio_crud", error: response.statusCode);
|
developer.log("fetchCutoffsBeanserver: Cutoffs are unavalable (${response.statusCode})", name: "services/tetrio_crud", error: response.statusCode);
|
||||||
return null;
|
return null;
|
||||||
default:
|
default:
|
||||||
developer.log("fetchCutoffs: Failed to fetch top Cutoffs", name: "services/tetrio_crud", error: response.statusCode);
|
developer.log("fetchCutoffsBeanserver: Failed to fetch top Cutoffs", name: "services/tetrio_crud", error: response.statusCode);
|
||||||
throw ConnectionIssue(response.statusCode, response.reasonPhrase??"No reason");
|
throw ConnectionIssue(response.statusCode, response.reasonPhrase??"No reason");
|
||||||
}
|
}
|
||||||
} on http.ClientException catch (e, s) { // If local http client fails
|
} on http.ClientException catch (e, s) { // If local http client fails
|
||||||
|
|
|
@ -175,10 +175,10 @@ class _MainState extends State<MainView> with TickerProviderStateMixin {
|
||||||
teto.fetchNews(_searchFor),
|
teto.fetchNews(_searchFor),
|
||||||
teto.fetchStream(_searchFor, "zenith/recent"),
|
teto.fetchStream(_searchFor, "zenith/recent"),
|
||||||
teto.fetchStream(_searchFor, "zenithex/recent"),
|
teto.fetchStream(_searchFor, "zenithex/recent"),
|
||||||
teto.fetchCutoffs(),
|
teto.fetchCutoffsBeanserver(),
|
||||||
(summaries.league.rank != "z" ? summaries.league.rank == "x+" : summaries.league.percentileRank == "x+") ? teto.fetchTopOneFromTheLeaderboard() : Future.delayed(Duration.zero, ()=>null),
|
(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>>[]),
|
//prefs.getBool("showPositions") != true ? teto.fetchCutoffsBeanserver() : Future.delayed(Duration.zero, ()=><Map<String, double>>[]),
|
||||||
|
|
||||||
//(summaries.league.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;
|
summaries = requests[0] as Summaries;
|
||||||
|
@ -478,10 +478,10 @@ class _MainState extends State<MainView> with TickerProviderStateMixin {
|
||||||
guest: snapshot.data![0].role == "anon",
|
guest: snapshot.data![0].role == "anon",
|
||||||
thatRankCutoff: thatRankCutoff,
|
thatRankCutoff: thatRankCutoff,
|
||||||
thatRankCutoffGlicko: thatRankGlickoCutoff,
|
thatRankCutoffGlicko: thatRankGlickoCutoff,
|
||||||
//thatRankTarget: snapshot.data![1].league.rank != "z" ? rankTargets[snapshot.data![1].league.rank] : null,
|
thatRankTarget: snapshot.data![1].league.rank != "z" ? rankTargets[snapshot.data![1].league.rank] : null,
|
||||||
nextRankCutoff: nextRankCutoff,
|
nextRankCutoff: nextRankCutoff,
|
||||||
nextRankCutoffGlicko: nextRankGlickoCutoff,
|
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,
|
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,
|
averages: rankAverages,
|
||||||
lbPositions: meAmongEveryone
|
lbPositions: meAmongEveryone
|
||||||
),
|
),
|
||||||
|
@ -519,10 +519,10 @@ class _MainState extends State<MainView> with TickerProviderStateMixin {
|
||||||
guest: snapshot.data![0].role == "anon",
|
guest: snapshot.data![0].role == "anon",
|
||||||
thatRankCutoff: thatRankCutoff,
|
thatRankCutoff: thatRankCutoff,
|
||||||
thatRankCutoffGlicko: thatRankGlickoCutoff,
|
thatRankCutoffGlicko: thatRankGlickoCutoff,
|
||||||
//thatRankTarget: snapshot.data![1].league.rank != "z" ? rankTargets[snapshot.data![1].league.rank] : null,
|
thatRankTarget: snapshot.data![1].league.rank != "z" ? rankTargets[snapshot.data![1].league.rank] : null,
|
||||||
nextRankCutoff: nextRankCutoff,
|
nextRankCutoff: nextRankCutoff,
|
||||||
nextRankCutoffGlicko: nextRankGlickoCutoff,
|
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,
|
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,
|
averages: rankAverages,
|
||||||
lbPositions: meAmongEveryone
|
lbPositions: meAmongEveryone
|
||||||
),
|
),
|
||||||
|
|
|
@ -40,7 +40,7 @@ class MainView extends StatefulWidget {
|
||||||
|
|
||||||
enum Page {home, leaderboards, leagueAverages, calculator, settings}
|
enum Page {home, leaderboards, leagueAverages, calculator, settings}
|
||||||
enum Cards {overview, tetraLeague, quickPlay, sprint, blitz}
|
enum Cards {overview, tetraLeague, quickPlay, sprint, blitz}
|
||||||
enum CardMod {info, recent, top, ex, exRecent, exTop}
|
enum CardMod {info, records, ex, exRecords}
|
||||||
Map<Cards, String> cardsTitles = {
|
Map<Cards, String> cardsTitles = {
|
||||||
Cards.overview: "Overview",
|
Cards.overview: "Overview",
|
||||||
Cards.tetraLeague: t.tetraLeague,
|
Cards.tetraLeague: t.tetraLeague,
|
||||||
|
@ -574,7 +574,7 @@ class RecordSummary extends StatelessWidget{
|
||||||
text: "",
|
text: "",
|
||||||
style: const TextStyle(fontFamily: "Eurostile Round", fontSize: 14, color: Colors.grey),
|
style: const TextStyle(fontFamily: "Eurostile Round", fontSize: 14, color: Colors.grey),
|
||||||
children: [
|
children: [
|
||||||
if (rank != null && rank != "z") TextSpan(text: "${t.verdictGeneral(n: switch(record!.gamemode){
|
if (rank != null && rank != "z" && rank != "x+") TextSpan(text: "${t.verdictGeneral(n: switch(record!.gamemode){
|
||||||
"40l" => readableTimeDifference(record!.stats.finalTime, sprintAverages[rank]!),
|
"40l" => readableTimeDifference(record!.stats.finalTime, sprintAverages[rank]!),
|
||||||
"blitz" => readableIntDifference(record!.stats.score, blitzAverages[rank]!),
|
"blitz" => readableIntDifference(record!.stats.score, blitzAverages[rank]!),
|
||||||
_ => record!.stats.score.toString()
|
_ => record!.stats.score.toString()
|
||||||
|
@ -872,7 +872,7 @@ class _DestinationHomeState extends State<DestinationHome> {
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
Widget getListOfRecords(String stream, bool isTop, BoxConstraints constraints){
|
Widget getListOfRecords(String recentStream, String topStream, BoxConstraints constraints){
|
||||||
return Column(
|
return Column(
|
||||||
children: [
|
children: [
|
||||||
Card(
|
Card(
|
||||||
|
@ -883,7 +883,8 @@ class _DestinationHomeState extends State<DestinationHome> {
|
||||||
mainAxisSize: MainAxisSize.min,
|
mainAxisSize: MainAxisSize.min,
|
||||||
crossAxisAlignment: CrossAxisAlignment.center,
|
crossAxisAlignment: CrossAxisAlignment.center,
|
||||||
children: [
|
children: [
|
||||||
Text(isTop ? t.top : t.recent, style: const TextStyle(fontFamily: "Eurostile Round Extended", fontSize: 42)),
|
Text("Records", style: const TextStyle(fontFamily: "Eurostile Round Extended", fontSize: 42)),
|
||||||
|
//Text("${t.seasonStarts} ${countdown(postSeasonLeft)}", textAlign: TextAlign.center)
|
||||||
],
|
],
|
||||||
),
|
),
|
||||||
),
|
),
|
||||||
|
@ -891,8 +892,22 @@ class _DestinationHomeState extends State<DestinationHome> {
|
||||||
),
|
),
|
||||||
Card(
|
Card(
|
||||||
clipBehavior: Clip.antiAlias,
|
clipBehavior: Clip.antiAlias,
|
||||||
child: FutureBuilder<SingleplayerStream>(
|
child: DefaultTabController(length: 2,
|
||||||
future: teto.fetchStream(widget.searchFor, stream),
|
child: Column(
|
||||||
|
mainAxisSize: MainAxisSize.min,
|
||||||
|
children: [
|
||||||
|
TabBar(
|
||||||
|
tabs: [
|
||||||
|
Tab(text: "Recent"),
|
||||||
|
Tab(text: "Top"),
|
||||||
|
],
|
||||||
|
),
|
||||||
|
SizedBox(
|
||||||
|
height: 400,
|
||||||
|
child: TabBarView(
|
||||||
|
children: [
|
||||||
|
FutureBuilder<SingleplayerStream>(
|
||||||
|
future: teto.fetchStream(widget.searchFor, recentStream),
|
||||||
builder: (context, snapshot) {
|
builder: (context, snapshot) {
|
||||||
switch (snapshot.connectionState){
|
switch (snapshot.connectionState){
|
||||||
case ConnectionState.none:
|
case ConnectionState.none:
|
||||||
|
@ -906,7 +921,7 @@ class _DestinationHomeState extends State<DestinationHome> {
|
||||||
for (int i = 0; i < snapshot.data!.records.length; i++) ListTile(
|
for (int i = 0; i < snapshot.data!.records.length; i++) ListTile(
|
||||||
onTap: () => Navigator.push(context, MaterialPageRoute(builder: (context) => SingleplayerRecordView(record: snapshot.data!.records[i]))),
|
onTap: () => Navigator.push(context, MaterialPageRoute(builder: (context) => SingleplayerRecordView(record: snapshot.data!.records[i]))),
|
||||||
leading: Text(
|
leading: Text(
|
||||||
isTop ? "#${i+1}" : switch (snapshot.data!.records[i].gamemode){
|
switch (snapshot.data!.records[i].gamemode){
|
||||||
"40l" => "40L",
|
"40l" => "40L",
|
||||||
"blitz" => "BLZ",
|
"blitz" => "BLZ",
|
||||||
"5mblast" => "5MB",
|
"5mblast" => "5MB",
|
||||||
|
@ -950,6 +965,64 @@ class _DestinationHomeState extends State<DestinationHome> {
|
||||||
return Text("what?");
|
return Text("what?");
|
||||||
},
|
},
|
||||||
),
|
),
|
||||||
|
FutureBuilder<SingleplayerStream>(
|
||||||
|
future: teto.fetchStream(widget.searchFor, topStream),
|
||||||
|
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){
|
||||||
|
return Column(
|
||||||
|
children: [
|
||||||
|
for (int i = 0; i < snapshot.data!.records.length; i++) ListTile(
|
||||||
|
onTap: () => Navigator.push(context, MaterialPageRoute(builder: (context) => SingleplayerRecordView(record: snapshot.data!.records[i]))),
|
||||||
|
leading: Text(
|
||||||
|
"#${i+1}",
|
||||||
|
style: const TextStyle(fontFamily: "Eurostile Round", fontSize: 28, shadows: textShadow, height: 0.9)
|
||||||
|
),
|
||||||
|
title: Text(
|
||||||
|
switch (snapshot.data!.records[i].gamemode){
|
||||||
|
"40l" => get40lTime(snapshot.data!.records[i].stats.finalTime.inMicroseconds),
|
||||||
|
"blitz" => t.blitzScore(p: NumberFormat.decimalPattern().format(snapshot.data!.records[i].stats.score)),
|
||||||
|
"5mblast" => get40lTime(snapshot.data!.records[i].stats.finalTime.inMicroseconds),
|
||||||
|
"zenith" => "${f2.format(snapshot.data!.records[i].stats.zenith!.altitude)} m${(snapshot.data!.records[i].extras as ZenithExtras).mods.isNotEmpty ? " (${t.withModsPlural(n: (snapshot.data!.records[i].extras as ZenithExtras).mods.length)})" : ""}",
|
||||||
|
"zenithex" => "${f2.format(snapshot.data!.records[i].stats.zenith!.altitude)} m${(snapshot.data!.records[i].extras as ZenithExtras).mods.isNotEmpty ? " (${t.withModsPlural(n: (snapshot.data!.records[i].extras as ZenithExtras).mods.length)})" : ""}",
|
||||||
|
String() => "huh",
|
||||||
|
},
|
||||||
|
style: const TextStyle(fontSize: 18)),
|
||||||
|
subtitle: Text(timestamp(snapshot.data!.records[i].timestamp), style: const TextStyle(color: Colors.grey, height: 0.85)),
|
||||||
|
trailing: SpTrailingStats(snapshot.data!.records[i], snapshot.data!.records[i].gamemode)
|
||||||
|
)
|
||||||
|
],
|
||||||
|
);
|
||||||
|
}
|
||||||
|
if (snapshot.hasError){
|
||||||
|
return Center(
|
||||||
|
child: Column(
|
||||||
|
mainAxisSize: MainAxisSize.min,
|
||||||
|
children: [
|
||||||
|
Text(t.errors.noSuchUser, style: const TextStyle(fontFamily: "Eurostile Round", fontSize: 42, fontWeight: FontWeight.bold), textAlign: TextAlign.center),
|
||||||
|
Padding(
|
||||||
|
padding: const EdgeInsets.only(top: 8.0),
|
||||||
|
child: Text(t.errors.noSuchUserSub, textAlign: TextAlign.center),
|
||||||
|
),
|
||||||
|
],
|
||||||
|
)
|
||||||
|
);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return Text("what?");
|
||||||
|
},
|
||||||
|
),
|
||||||
|
]
|
||||||
|
),
|
||||||
|
)
|
||||||
|
],
|
||||||
|
),
|
||||||
|
)
|
||||||
),
|
),
|
||||||
],
|
],
|
||||||
);
|
);
|
||||||
|
@ -1301,7 +1374,7 @@ class _DestinationHomeState extends State<DestinationHome> {
|
||||||
label: Text('Standing'),
|
label: Text('Standing'),
|
||||||
),
|
),
|
||||||
const ButtonSegment<CardMod>(
|
const ButtonSegment<CardMod>(
|
||||||
value: CardMod.recent,
|
value: CardMod.records,
|
||||||
label: Text('Recent Matches'),
|
label: Text('Recent Matches'),
|
||||||
),
|
),
|
||||||
],
|
],
|
||||||
|
@ -1311,25 +1384,17 @@ class _DestinationHomeState extends State<DestinationHome> {
|
||||||
label: Text('Normal'),
|
label: Text('Normal'),
|
||||||
),
|
),
|
||||||
const ButtonSegment<CardMod>(
|
const ButtonSegment<CardMod>(
|
||||||
value: CardMod.recent,
|
value: CardMod.records,
|
||||||
label: Text('Recent Normal'),
|
label: Text('Records'),
|
||||||
),
|
|
||||||
const ButtonSegment<CardMod>(
|
|
||||||
value: CardMod.top,
|
|
||||||
label: Text('Top Normal'),
|
|
||||||
),
|
),
|
||||||
const ButtonSegment<CardMod>(
|
const ButtonSegment<CardMod>(
|
||||||
value: CardMod.ex,
|
value: CardMod.ex,
|
||||||
label: Text('Expert'),
|
label: Text('Expert'),
|
||||||
),
|
),
|
||||||
const ButtonSegment<CardMod>(
|
const ButtonSegment<CardMod>(
|
||||||
value: CardMod.exRecent,
|
value: CardMod.exRecords,
|
||||||
label: Text('Recent Expert'),
|
label: Text('Expert Records'),
|
||||||
),
|
)
|
||||||
const ButtonSegment<CardMod>(
|
|
||||||
value: CardMod.exTop,
|
|
||||||
label: Text('Top Expert'),
|
|
||||||
),
|
|
||||||
],
|
],
|
||||||
Cards.blitz: [
|
Cards.blitz: [
|
||||||
const ButtonSegment<CardMod>(
|
const ButtonSegment<CardMod>(
|
||||||
|
@ -1337,13 +1402,9 @@ class _DestinationHomeState extends State<DestinationHome> {
|
||||||
label: Text('PB'),
|
label: Text('PB'),
|
||||||
),
|
),
|
||||||
const ButtonSegment<CardMod>(
|
const ButtonSegment<CardMod>(
|
||||||
value: CardMod.recent,
|
value: CardMod.records,
|
||||||
label: Text('Recent'),
|
label: Text('Records'),
|
||||||
),
|
)
|
||||||
const ButtonSegment<CardMod>(
|
|
||||||
value: CardMod.top,
|
|
||||||
label: Text('Top'),
|
|
||||||
),
|
|
||||||
],
|
],
|
||||||
Cards.sprint: [
|
Cards.sprint: [
|
||||||
const ButtonSegment<CardMod>(
|
const ButtonSegment<CardMod>(
|
||||||
|
@ -1351,13 +1412,9 @@ class _DestinationHomeState extends State<DestinationHome> {
|
||||||
label: Text('PB'),
|
label: Text('PB'),
|
||||||
),
|
),
|
||||||
const ButtonSegment<CardMod>(
|
const ButtonSegment<CardMod>(
|
||||||
value: CardMod.recent,
|
value: CardMod.records,
|
||||||
label: Text('Recent'),
|
label: Text('Records'),
|
||||||
),
|
)
|
||||||
const ButtonSegment<CardMod>(
|
|
||||||
value: CardMod.top,
|
|
||||||
label: Text('Top'),
|
|
||||||
),
|
|
||||||
]
|
]
|
||||||
};
|
};
|
||||||
super.initState();
|
super.initState();
|
||||||
|
@ -1389,8 +1446,8 @@ class _DestinationHomeState extends State<DestinationHome> {
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
if (snapshot.hasData){
|
if (snapshot.hasData){
|
||||||
blitzBetterThanRankAverage = (snapshot.data!.summaries!.league.rank != "z" && snapshot.data!.summaries!.blitz != null) ? snapshot.data!.summaries!.blitz!.stats.score > blitzAverages[snapshot.data!.summaries!.league.rank]! : null;
|
blitzBetterThanRankAverage = (snapshot.data!.summaries!.league.rank != "z" && snapshot.data!.summaries!.blitz != null && snapshot.data!.summaries!.league.rank != "x+") ? snapshot.data!.summaries!.blitz!.stats.score > blitzAverages[snapshot.data!.summaries!.league.rank]! : null;
|
||||||
sprintBetterThanRankAverage = (snapshot.data!.summaries!.league.rank != "z" && snapshot.data!.summaries!.sprint != null) ? snapshot.data!.summaries!.sprint!.stats.finalTime < sprintAverages[snapshot.data!.summaries!.league.rank]! : null;
|
sprintBetterThanRankAverage = (snapshot.data!.summaries!.league.rank != "z" && snapshot.data!.summaries!.sprint != null && snapshot.data!.summaries!.league.rank != "x+") ? snapshot.data!.summaries!.sprint!.stats.finalTime < sprintAverages[snapshot.data!.summaries!.league.rank]! : null;
|
||||||
if (snapshot.data!.summaries!.sprint != null) {
|
if (snapshot.data!.summaries!.sprint != null) {
|
||||||
closestAverageSprint = sprintAverages.entries.singleWhere((element) => element.value == sprintAverages.values.reduce((a, b) => (a-snapshot.data!.summaries!.sprint!.stats.finalTime).abs() < (b -snapshot.data!.summaries!.sprint!.stats.finalTime).abs() ? a : b));
|
closestAverageSprint = sprintAverages.entries.singleWhere((element) => element.value == sprintAverages.values.reduce((a, b) => (a-snapshot.data!.summaries!.sprint!.stats.finalTime).abs() < (b -snapshot.data!.summaries!.sprint!.stats.finalTime).abs() ? a : b));
|
||||||
sprintBetterThanClosestAverage = snapshot.data!.summaries!.sprint!.stats.finalTime < closestAverageSprint!.value;
|
sprintBetterThanClosestAverage = snapshot.data!.summaries!.sprint!.stats.finalTime < closestAverageSprint!.value;
|
||||||
|
@ -1467,28 +1524,24 @@ class _DestinationHomeState extends State<DestinationHome> {
|
||||||
Cards.overview => getOverviewCard(snapshot.data!.summaries!),
|
Cards.overview => getOverviewCard(snapshot.data!.summaries!),
|
||||||
Cards.tetraLeague => switch (cardMod){
|
Cards.tetraLeague => switch (cardMod){
|
||||||
CardMod.info => getTetraLeagueCard(snapshot.data!.summaries!.league),
|
CardMod.info => getTetraLeagueCard(snapshot.data!.summaries!.league),
|
||||||
CardMod.recent => getRecentTLrecords(widget.constraints),
|
CardMod.records => getRecentTLrecords(widget.constraints),
|
||||||
_ => Center(child: Text("huh?"))
|
_ => Center(child: Text("huh?"))
|
||||||
},
|
},
|
||||||
Cards.quickPlay => switch (cardMod){
|
Cards.quickPlay => switch (cardMod){
|
||||||
CardMod.info => getZenithCard(snapshot.data?.summaries!.zenith),
|
CardMod.info => getZenithCard(snapshot.data?.summaries!.zenith),
|
||||||
CardMod.recent => getListOfRecords("zenith/recent", false, widget.constraints),
|
CardMod.records => getListOfRecords("zenith/recent", "zenith/top", widget.constraints),
|
||||||
CardMod.top => getListOfRecords("zenith/top", true, widget.constraints),
|
|
||||||
CardMod.ex => getZenithCard(snapshot.data?.summaries!.zenithEx),
|
CardMod.ex => getZenithCard(snapshot.data?.summaries!.zenithEx),
|
||||||
CardMod.exRecent => getListOfRecords("zenithex/recent", false, widget.constraints),
|
CardMod.exRecords => getListOfRecords("zenithex/recent", "zenithex/top", widget.constraints),
|
||||||
CardMod.exTop => getListOfRecords("zenithex/top", true, widget.constraints),
|
|
||||||
_ => Center(child: Text("huh?"))
|
_ => Center(child: Text("huh?"))
|
||||||
},
|
},
|
||||||
Cards.sprint => switch (cardMod){
|
Cards.sprint => switch (cardMod){
|
||||||
CardMod.info => getRecordCard(snapshot.data?.summaries!.sprint, sprintBetterThanRankAverage, closestAverageSprint, sprintBetterThanClosestAverage, snapshot.data!.summaries!.league.rank),
|
CardMod.info => getRecordCard(snapshot.data?.summaries!.sprint, sprintBetterThanRankAverage, closestAverageSprint, sprintBetterThanClosestAverage, snapshot.data!.summaries!.league.rank),
|
||||||
CardMod.recent => getListOfRecords("40l/recent", false, widget.constraints),
|
CardMod.records => getListOfRecords("40l/recent", "40l/top", widget.constraints),
|
||||||
CardMod.top => getListOfRecords("40l/top", true, widget.constraints),
|
|
||||||
_ => Center(child: Text("huh?"))
|
_ => Center(child: Text("huh?"))
|
||||||
},
|
},
|
||||||
Cards.blitz => switch (cardMod){
|
Cards.blitz => switch (cardMod){
|
||||||
CardMod.info => getRecordCard(snapshot.data?.summaries!.blitz, blitzBetterThanRankAverage, closestAverageBlitz, blitzBetterThanClosestAverage, snapshot.data!.summaries!.league.rank),
|
CardMod.info => getRecordCard(snapshot.data?.summaries!.blitz, blitzBetterThanRankAverage, closestAverageBlitz, blitzBetterThanClosestAverage, snapshot.data!.summaries!.league.rank),
|
||||||
CardMod.recent => getListOfRecords("blitz/recent", false, widget.constraints),
|
CardMod.records => getListOfRecords("blitz/recent", "blitz/top", widget.constraints),
|
||||||
CardMod.top => getListOfRecords("blitz/top", true, widget.constraints),
|
|
||||||
_ => Center(child: Text("huh?"))
|
_ => Center(child: Text("huh?"))
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
|
@ -2333,12 +2386,13 @@ class TetraLeagueThingy extends StatelessWidget{
|
||||||
backgroundColor: Colors.black,
|
backgroundColor: Colors.black,
|
||||||
axes: [
|
axes: [
|
||||||
RadialAxis(
|
RadialAxis(
|
||||||
minimum: 0.4,
|
minimum: 0.0,
|
||||||
maximum: 0.6,
|
maximum: 1.0,
|
||||||
radiusFactor: 1.01,
|
radiusFactor: 1.01,
|
||||||
showTicks: true,
|
showTicks: true,
|
||||||
showLabels: false,
|
showLabels: false,
|
||||||
interval: 0.1,
|
interval: 0.25,
|
||||||
|
minorTicksPerInterval: 0,
|
||||||
ranges:[
|
ranges:[
|
||||||
GaugeRange(startValue: 0, endValue: league.winrate, color: theme.colorScheme.primary)
|
GaugeRange(startValue: 0, endValue: league.winrate, color: theme.colorScheme.primary)
|
||||||
],
|
],
|
||||||
|
|
|
@ -1,13 +1,10 @@
|
||||||
import 'dart:io';
|
import 'dart:io';
|
||||||
import 'package:flutter/foundation.dart';
|
import 'package:flutter/foundation.dart';
|
||||||
import 'package:flutter/material.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/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';
|
||||||
import 'package:tetra_stats/utils/text_shadow.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:tetra_stats/widgets/text_timestamp.dart';
|
||||||
import 'package:window_manager/window_manager.dart';
|
import 'package:window_manager/window_manager.dart';
|
||||||
import 'package:tetra_stats/main.dart' show teto;
|
import 'package:tetra_stats/main.dart' show teto;
|
||||||
|
@ -40,14 +37,13 @@ class RanksAverages extends State<RankAveragesView> {
|
||||||
|
|
||||||
@override
|
@override
|
||||||
Widget build(BuildContext context) {
|
Widget build(BuildContext context) {
|
||||||
bool bigScreen = MediaQuery.of(context).size.width >= 700;
|
|
||||||
return Scaffold(
|
return Scaffold(
|
||||||
appBar: AppBar(
|
appBar: AppBar(
|
||||||
title: Text(t.rankAveragesViewTitle),
|
title: Text(t.rankAveragesViewTitle),
|
||||||
),
|
),
|
||||||
backgroundColor: Colors.black,
|
backgroundColor: Colors.black,
|
||||||
body: SafeArea(
|
body: SafeArea(
|
||||||
child: FutureBuilder<Cutoffs?>(future: teto.fetchCutoffs(), builder: (context, snapshot){
|
child: FutureBuilder<CutoffsTetrio?>(future: teto.fetchCutoffsTetrio(), builder: (context, snapshot){
|
||||||
switch (snapshot.connectionState) {
|
switch (snapshot.connectionState) {
|
||||||
case ConnectionState.none:
|
case ConnectionState.none:
|
||||||
case ConnectionState.waiting:
|
case ConnectionState.waiting:
|
||||||
|
@ -61,8 +57,7 @@ class RanksAverages extends State<RankAveragesView> {
|
||||||
scrollDirection: Axis.horizontal,
|
scrollDirection: Axis.horizontal,
|
||||||
child: Container(
|
child: Container(
|
||||||
alignment: Alignment.center,
|
alignment: Alignment.center,
|
||||||
width: MediaQuery.of(context).size.width,
|
width: 900,
|
||||||
constraints: const BoxConstraints(maxWidth: 900, minWidth: 610),
|
|
||||||
child: SingleChildScrollView(
|
child: SingleChildScrollView(
|
||||||
padding: const EdgeInsets.all(16),
|
padding: const EdgeInsets.all(16),
|
||||||
child: Column(
|
child: Column(
|
||||||
|
@ -71,54 +66,85 @@ class RanksAverages extends State<RankAveragesView> {
|
||||||
Table(
|
Table(
|
||||||
defaultVerticalAlignment: TableCellVerticalAlignment.middle,
|
defaultVerticalAlignment: TableCellVerticalAlignment.middle,
|
||||||
border: TableBorder.all(color: Colors.grey.shade900),
|
border: TableBorder.all(color: Colors.grey.shade900),
|
||||||
columnWidths: const {0: FixedColumnWidth(48)},
|
columnWidths: const {
|
||||||
|
0: FixedColumnWidth(48),
|
||||||
|
1: FixedColumnWidth(155),
|
||||||
|
2: FixedColumnWidth(150),
|
||||||
|
3: FixedColumnWidth(90),
|
||||||
|
4: FixedColumnWidth(130),
|
||||||
|
},
|
||||||
children: [
|
children: [
|
||||||
TableRow(
|
TableRow(
|
||||||
children: [
|
children: [
|
||||||
Text(t.rank, textAlign: TextAlign.center, style: const TextStyle(fontFamily: "Eurostile Round", fontSize: 14, fontWeight: FontWeight.w500, color: Colors.white)),
|
Text(t.rank, textAlign: TextAlign.center, style: const TextStyle(fontFamily: "Eurostile Round", fontSize: 14, fontWeight: FontWeight.w500, color: Colors.white)),
|
||||||
Padding(
|
const Padding(
|
||||||
padding: const EdgeInsets.only(right: 8.0),
|
padding: 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)),
|
child: Text("TR", textAlign: TextAlign.right, style: TextStyle(fontFamily: "Eurostile Round", fontSize: 28, fontWeight: FontWeight.w500, color: Colors.white)),
|
||||||
|
),
|
||||||
|
const Padding(
|
||||||
|
padding: EdgeInsets.only(right: 8.0),
|
||||||
|
child: Text("APM", textAlign: TextAlign.right, style: TextStyle(fontFamily: "Eurostile Round", fontSize: 28, fontWeight: FontWeight.w500, color: Colors.white)),
|
||||||
|
),
|
||||||
|
const Padding(
|
||||||
|
padding: EdgeInsets.only(right: 8.0),
|
||||||
|
child: Text("PPS", textAlign: TextAlign.right, style: TextStyle(fontFamily: "Eurostile Round", fontSize: 28, fontWeight: FontWeight.w500, color: Colors.white)),
|
||||||
|
),
|
||||||
|
const Padding(
|
||||||
|
padding: EdgeInsets.only(right: 8.0),
|
||||||
|
child: Text("VS", textAlign: TextAlign.right, style: TextStyle(fontFamily: "Eurostile Round", fontSize: 28, fontWeight: FontWeight.w500, color: Colors.white)),
|
||||||
|
),
|
||||||
|
const Padding(
|
||||||
|
padding: EdgeInsets.only(right: 8.0),
|
||||||
|
child: Text("Advanced", textAlign: TextAlign.right, style: TextStyle(fontFamily: "Eurostile Round", fontSize: 14, fontWeight: FontWeight.w500, color: Colors.white)),
|
||||||
),
|
),
|
||||||
Padding(
|
Padding(
|
||||||
padding: const EdgeInsets.only(right: 8.0),
|
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)),
|
child: Text("Players (${intf.format(snapshot.data!.total)})", textAlign: TextAlign.right, style: const TextStyle(fontFamily: "Eurostile Round", fontSize: 14, 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(
|
for (String rank in snapshot.data!.data.keys) TableRow(
|
||||||
decoration: BoxDecoration(gradient: LinearGradient(colors: [rankColors[rank]!.withAlpha(100), rankColors[rank]!.withAlpha(200)])),
|
decoration: BoxDecoration(gradient: LinearGradient(colors: [rankColors[rank]!.withAlpha(200), rankColors[rank]!.withAlpha(100)])),
|
||||||
children: [
|
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)),
|
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(
|
||||||
padding: const EdgeInsets.only(right: 8.0),
|
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)),
|
child: Text(f2.format(snapshot.data!.data[rank]!.tr), textAlign: TextAlign.right, style: const TextStyle(fontFamily: "Eurostile Round", fontSize: 28, fontWeight: FontWeight.w500, color: Colors.white, shadows: textShadow)),
|
||||||
),
|
),
|
||||||
Padding(
|
Padding(
|
||||||
padding: const EdgeInsets.only(right: 8.0),
|
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)),
|
child: Text(f2.format(snapshot.data!.data[rank]!.apm), textAlign: TextAlign.right, style: const TextStyle(fontFamily: "Eurostile Round", fontSize: 28, fontWeight: FontWeight.w100, color: Colors.white, shadows: textShadow)),
|
||||||
),
|
),
|
||||||
Padding(
|
Padding(
|
||||||
padding: const EdgeInsets.only(right: 8.0),
|
padding: const EdgeInsets.only(right: 8.0),
|
||||||
child: Text(f3.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)),
|
child: Text(f2.format(snapshot.data!.data[rank]!.pps), textAlign: TextAlign.right, style: const TextStyle(fontFamily: "Eurostile Round", fontSize: 28, fontWeight: FontWeight.w100, color: Colors.white, shadows: textShadow)),
|
||||||
),
|
),
|
||||||
Padding(
|
Padding(
|
||||||
padding: const EdgeInsets.only(right: 8.0),
|
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)),
|
child: Text(f2.format(snapshot.data!.data[rank]!.vs), textAlign: TextAlign.right, style: const TextStyle(fontFamily: "Eurostile Round", fontSize: 28, fontWeight: FontWeight.w100, color: Colors.white, shadows: textShadow)),
|
||||||
|
),
|
||||||
|
Padding(
|
||||||
|
padding: const EdgeInsets.only(right: 8.0),
|
||||||
|
child: Text("${f3.format(snapshot.data!.data[rank]!.apm / (snapshot.data!.data[rank]!.pps * 60))} APP\n${f3.format(snapshot.data!.data[rank]!.vs / snapshot.data!.data[rank]!.apm)} VS/APM", textAlign: TextAlign.right, style: const TextStyle(fontFamily: "Eurostile Round", fontSize: 14, fontWeight: FontWeight.w100, color: Colors.white, shadows: textShadow)),
|
||||||
|
),
|
||||||
|
Padding(
|
||||||
|
padding: const EdgeInsets.only(right: 8.0),
|
||||||
|
child: RichText(
|
||||||
|
textAlign: TextAlign.right,
|
||||||
|
text: TextSpan(
|
||||||
|
style: const TextStyle(fontFamily: "Eurostile Round", fontSize: 14, fontWeight: FontWeight.w100, color: Colors.white, shadows: textShadow),
|
||||||
|
children: [
|
||||||
|
TextSpan(text: intf.format(snapshot.data!.data[rank]!.count)),
|
||||||
|
TextSpan(text: " (${f2.format(snapshot.data!.data[rank]!.countPercentile * 100)}%)", style: const TextStyle(color: Colors.white60, shadows: null)),
|
||||||
|
TextSpan(text: "\n(from № ${intf.format(snapshot.data!.data[rank]!.pos)})", style: const TextStyle(color: Colors.white60, shadows: null))
|
||||||
|
]
|
||||||
|
))
|
||||||
),
|
),
|
||||||
]
|
]
|
||||||
)
|
)
|
||||||
],
|
],
|
||||||
),
|
),
|
||||||
Text(t.sprintAndBlitsRelevance(date: timestamp(snapshot.data!.ts)))
|
Text(t.sprintAndBlitsRelevance(date: timestamp(snapshot.data!.timestamp)))
|
||||||
],
|
],
|
||||||
),
|
),
|
||||||
),
|
),
|
||||||
|
|
|
@ -2,7 +2,7 @@ name: tetra_stats
|
||||||
description: Track your and other player stats in TETR.IO
|
description: Track your and other player stats in TETR.IO
|
||||||
publish_to: 'none'
|
publish_to: 'none'
|
||||||
|
|
||||||
version: 1.6.7+33
|
version: 1.6.8+34
|
||||||
|
|
||||||
environment:
|
environment:
|
||||||
sdk: '>=3.0.0'
|
sdk: '>=3.0.0'
|
||||||
|
|
Loading…
Reference in New Issue