|
@ -16,6 +16,7 @@ You can [download an app](https://github.com/dan63047/TetraStats/releases), or [
|
||||||
- Stats Calculator
|
- Stats Calculator
|
||||||
- Player history in charts
|
- Player history in charts
|
||||||
- Tetra League matches history
|
- Tetra League matches history
|
||||||
|
- Time-weighted stats in Tetra League matches
|
||||||
|
|
||||||
# Special thanks
|
# Special thanks
|
||||||
- **kerrmunism** — formulas
|
- **kerrmunism** — formulas
|
||||||
|
|
|
@ -25,6 +25,12 @@ apply plugin: 'com.android.application'
|
||||||
apply plugin: 'kotlin-android'
|
apply plugin: 'kotlin-android'
|
||||||
apply from: "$flutterRoot/packages/flutter_tools/gradle/flutter.gradle"
|
apply from: "$flutterRoot/packages/flutter_tools/gradle/flutter.gradle"
|
||||||
|
|
||||||
|
def keystoreProperties = new Properties()
|
||||||
|
def keystorePropertiesFile = rootProject.file('key.properties')
|
||||||
|
if (keystorePropertiesFile.exists()) {
|
||||||
|
keystoreProperties.load(new FileInputStream(keystorePropertiesFile))
|
||||||
|
}
|
||||||
|
|
||||||
android {
|
android {
|
||||||
compileSdkVersion flutter.compileSdkVersion
|
compileSdkVersion flutter.compileSdkVersion
|
||||||
ndkVersion flutter.ndkVersion
|
ndkVersion flutter.ndkVersion
|
||||||
|
@ -53,11 +59,17 @@ android {
|
||||||
versionName flutterVersionName
|
versionName flutterVersionName
|
||||||
}
|
}
|
||||||
|
|
||||||
|
signingConfigs {
|
||||||
|
release {
|
||||||
|
keyAlias keystoreProperties['keyAlias']
|
||||||
|
keyPassword keystoreProperties['keyPassword']
|
||||||
|
storeFile keystoreProperties['storeFile'] ? file(keystoreProperties['storeFile']) : null
|
||||||
|
storePassword keystoreProperties['storePassword']
|
||||||
|
}
|
||||||
|
}
|
||||||
buildTypes {
|
buildTypes {
|
||||||
release {
|
release {
|
||||||
// TODO: Add your own signing config for the release build.
|
signingConfig signingConfigs.release
|
||||||
// Signing with the debug keys for now, so `flutter run --release` works.
|
|
||||||
signingConfig signingConfigs.debug
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -0,0 +1,25 @@
|
||||||
|
//import 'dart:convert';
|
||||||
|
//import 'dart:io';
|
||||||
|
|
||||||
|
//import 'package:path_provider/path_provider.dart';
|
||||||
|
|
||||||
|
//import 'tetrio_multiplayer_replay.dart';
|
||||||
|
|
||||||
|
/// That thing allows me to test my new staff i'm trying to implement
|
||||||
|
//void main() async {
|
||||||
|
// List<Tetromino> queue = List.from(tetrominoes);
|
||||||
|
// TetrioRNG rng = TetrioRNG(0);
|
||||||
|
// queue = rng.shuffleList(queue);
|
||||||
|
// print(queue);
|
||||||
|
// queue = List.from(tetrominoes);
|
||||||
|
// queue = rng.shuffleList(queue);
|
||||||
|
// print(queue);
|
||||||
|
|
||||||
|
// var downloadPath = await getDownloadsDirectory();
|
||||||
|
// ReplayData replay = ReplayData.fromJson(jsonDecode(File("${downloadPath!.path}/65b504a9ade6d287b8427af0").readAsStringSync()));
|
||||||
|
// List<List<Tetromino>> board = [for (var i = 0 ; i < 40; i++) [for (var i = 0 ; i < 10; i++) Tetromino.empty]];
|
||||||
|
// print(replay.rawJson);
|
||||||
|
|
||||||
|
//print("");
|
||||||
|
// exit(0);
|
||||||
|
//}
|
|
@ -38,6 +38,25 @@ const Map<String, double> rankCutoffs = {
|
||||||
"z": -1,
|
"z": -1,
|
||||||
"": 0.5
|
"": 0.5
|
||||||
};
|
};
|
||||||
|
const Map<String, double> rankTargets = {
|
||||||
|
"x": 24008,
|
||||||
|
"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,
|
||||||
|
};
|
||||||
enum Stats {
|
enum Stats {
|
||||||
tr,
|
tr,
|
||||||
glicko,
|
glicko,
|
||||||
|
@ -59,6 +78,7 @@ enum Stats {
|
||||||
area,
|
area,
|
||||||
eTR,
|
eTR,
|
||||||
acceTR,
|
acceTR,
|
||||||
|
acceTRabs,
|
||||||
opener,
|
opener,
|
||||||
plonk,
|
plonk,
|
||||||
infDS,
|
infDS,
|
||||||
|
@ -88,6 +108,7 @@ const Map<Stats, String> chartsShortTitles = {
|
||||||
Stats.area: "Area",
|
Stats.area: "Area",
|
||||||
Stats.eTR: "eTR",
|
Stats.eTR: "eTR",
|
||||||
Stats.acceTR: "±eTR",
|
Stats.acceTR: "±eTR",
|
||||||
|
Stats.acceTRabs: "+eTR absolute",
|
||||||
Stats.opener: "Opener",
|
Stats.opener: "Opener",
|
||||||
Stats.plonk: "Plonk",
|
Stats.plonk: "Plonk",
|
||||||
Stats.infDS: "Inf. DS",
|
Stats.infDS: "Inf. DS",
|
||||||
|
@ -117,6 +138,48 @@ const Map<String, Color> rankColors = { // thanks osk for const rankColors at ht
|
||||||
'z': Color(0xFF375433)
|
'z': Color(0xFF375433)
|
||||||
};
|
};
|
||||||
|
|
||||||
|
const Map<String, Duration> sprintAverages = { // based on https://discord.com/channels/673303546107658242/917098364787650590/1214231970259673098
|
||||||
|
'x': Duration(seconds: 25, milliseconds: 413),
|
||||||
|
'u': Duration(seconds: 34, milliseconds: 549),
|
||||||
|
'ss': Duration(seconds: 43, milliseconds: 373),
|
||||||
|
's+': Duration(seconds: 54, milliseconds: 027),
|
||||||
|
's': Duration(seconds: 60, milliseconds: 412),
|
||||||
|
's-': Duration(seconds: 67, milliseconds: 381),
|
||||||
|
'a+': Duration(seconds: 73, milliseconds: 694),
|
||||||
|
'a': Duration(seconds: 81, milliseconds: 166),
|
||||||
|
'a-': Duration(seconds: 88, milliseconds: 334),
|
||||||
|
'b+': Duration(seconds: 93, milliseconds: 741),
|
||||||
|
'b': Duration(seconds: 98, milliseconds: 354),
|
||||||
|
'b-': Duration(seconds: 109, milliseconds: 610),
|
||||||
|
'c+': Duration(seconds: 124, milliseconds: 641),
|
||||||
|
'c': Duration(seconds: 126, milliseconds: 104),
|
||||||
|
'c-': Duration(seconds: 145, milliseconds: 865),
|
||||||
|
'd+': Duration(seconds: 154, milliseconds: 338),
|
||||||
|
'd': Duration(seconds: 162, milliseconds: 063),
|
||||||
|
//'z': Duration(seconds: 66, milliseconds: 802)
|
||||||
|
};
|
||||||
|
|
||||||
|
const Map<String, int> blitzAverages = {
|
||||||
|
'x': 626494,
|
||||||
|
'u': 406059,
|
||||||
|
'ss': 243166,
|
||||||
|
's+': 168636,
|
||||||
|
's': 121594,
|
||||||
|
's-': 107845,
|
||||||
|
'a+': 87142,
|
||||||
|
'a': 73413,
|
||||||
|
'a-': 60799,
|
||||||
|
'b+': 55417,
|
||||||
|
'b': 47608,
|
||||||
|
'b-': 40534,
|
||||||
|
'c+': 34200,
|
||||||
|
'c': 32535,
|
||||||
|
'c-': 25808,
|
||||||
|
'd+': 23345,
|
||||||
|
'd': 23063,
|
||||||
|
//'z': 72084
|
||||||
|
};
|
||||||
|
|
||||||
String getStatNameByEnum(Stats stat){
|
String getStatNameByEnum(Stats stat){
|
||||||
return t[stat.name];
|
return t[stat.name];
|
||||||
}
|
}
|
||||||
|
@ -271,6 +334,10 @@ class TetrioPlayer {
|
||||||
return tlSeason1.lessStrictCheck(other.tlSeason1);
|
return tlSeason1.lessStrictCheck(other.tlSeason1);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
TetrioPlayerFromLeaderboard convertToPlayerFromLeaderboard() => TetrioPlayerFromLeaderboard(
|
||||||
|
userId, username, role, xp, country, supporterTier > 0, verified, state, gamesPlayed, gamesWon,
|
||||||
|
tlSeason1.rating, tlSeason1.glicko??0, tlSeason1.rd??noTrRd, tlSeason1.rank, tlSeason1.bestRank, tlSeason1.apm??0, tlSeason1.pps??0, tlSeason1.vs??0, tlSeason1.decaying);
|
||||||
|
|
||||||
@override
|
@override
|
||||||
String toString() {
|
String toString() {
|
||||||
return "$username ($state)";
|
return "$username ($state)";
|
||||||
|
@ -318,6 +385,8 @@ class TetrioPlayer {
|
||||||
return tlSeason1.estTr?.esttr;
|
return tlSeason1.estTr?.esttr;
|
||||||
case Stats.acceTR:
|
case Stats.acceTR:
|
||||||
return tlSeason1.esttracc;
|
return tlSeason1.esttracc;
|
||||||
|
case Stats.acceTRabs:
|
||||||
|
return tlSeason1.esttracc?.abs();
|
||||||
case Stats.opener:
|
case Stats.opener:
|
||||||
return tlSeason1.playstyle?.opener;
|
return tlSeason1.playstyle?.opener;
|
||||||
case Stats.plonk:
|
case Stats.plonk:
|
||||||
|
@ -1097,6 +1166,73 @@ class News {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
class PlayerLeaderboardPosition{
|
||||||
|
late LeaderboardPosition? apm;
|
||||||
|
late LeaderboardPosition? pps;
|
||||||
|
late LeaderboardPosition? vs;
|
||||||
|
late LeaderboardPosition? gamesPlayed;
|
||||||
|
late LeaderboardPosition? gamesWon;
|
||||||
|
late LeaderboardPosition? winrate;
|
||||||
|
late LeaderboardPosition? app;
|
||||||
|
late LeaderboardPosition? vsapm;
|
||||||
|
late LeaderboardPosition? dss;
|
||||||
|
late LeaderboardPosition? dsp;
|
||||||
|
late LeaderboardPosition? appdsp;
|
||||||
|
late LeaderboardPosition? cheese;
|
||||||
|
late LeaderboardPosition? gbe;
|
||||||
|
late LeaderboardPosition? nyaapp;
|
||||||
|
late LeaderboardPosition? area;
|
||||||
|
late LeaderboardPosition? estTr;
|
||||||
|
late LeaderboardPosition? accOfEst;
|
||||||
|
|
||||||
|
PlayerLeaderboardPosition({
|
||||||
|
required this.apm,
|
||||||
|
required this.pps,
|
||||||
|
required this.vs,
|
||||||
|
required this.gamesPlayed,
|
||||||
|
required this.gamesWon,
|
||||||
|
required this.winrate,
|
||||||
|
required this.app,
|
||||||
|
required this.vsapm,
|
||||||
|
required this.dss,
|
||||||
|
required this.dsp,
|
||||||
|
required this.appdsp,
|
||||||
|
required this.cheese,
|
||||||
|
required this.gbe,
|
||||||
|
required this.nyaapp,
|
||||||
|
required this.area,
|
||||||
|
required this.estTr,
|
||||||
|
required this.accOfEst
|
||||||
|
});
|
||||||
|
|
||||||
|
PlayerLeaderboardPosition.fromSearchResults(List<LeaderboardPosition?> results){
|
||||||
|
apm = results[0];
|
||||||
|
pps = results[1];
|
||||||
|
vs = results[2];
|
||||||
|
gamesPlayed = results[3];
|
||||||
|
gamesWon = results[4];
|
||||||
|
winrate = results[5];
|
||||||
|
app = results[6];
|
||||||
|
vsapm = results[7];
|
||||||
|
dss = results[8];
|
||||||
|
dsp = results[9];
|
||||||
|
appdsp = results[10];
|
||||||
|
cheese = results[11];
|
||||||
|
gbe = results[12];
|
||||||
|
nyaapp = results[13];
|
||||||
|
area = results[14];
|
||||||
|
estTr = results[15];
|
||||||
|
accOfEst = results[16];
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
class LeaderboardPosition{
|
||||||
|
int position;
|
||||||
|
double percentage;
|
||||||
|
|
||||||
|
LeaderboardPosition(this.position, this.percentage);
|
||||||
|
}
|
||||||
|
|
||||||
class TetrioPlayersLeaderboard {
|
class TetrioPlayersLeaderboard {
|
||||||
late String type;
|
late String type;
|
||||||
late DateTime timestamp;
|
late DateTime timestamp;
|
||||||
|
@ -1121,6 +1257,20 @@ class TetrioPlayersLeaderboard {
|
||||||
return lb;
|
return lb;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
List<TetrioPlayerFromLeaderboard> getStatRankingSequel(Stats stat){
|
||||||
|
List<TetrioPlayerFromLeaderboard> lb = List.from(leaderboard);
|
||||||
|
lb.sort(((a, b) {
|
||||||
|
if (a.getStatByEnum(stat) > b.getStatByEnum(stat)){
|
||||||
|
return -1;
|
||||||
|
}else if (a.getStatByEnum(stat) == b.getStatByEnum(stat)){
|
||||||
|
return 0;
|
||||||
|
}else{
|
||||||
|
return 1;
|
||||||
|
}
|
||||||
|
}));
|
||||||
|
return lb;
|
||||||
|
}
|
||||||
|
|
||||||
List<dynamic> getAverageOfRank(String rank){ // i tried to refactor it and that's was terrible
|
List<dynamic> getAverageOfRank(String rank){ // i tried to refactor it and that's was terrible
|
||||||
if (rank.isNotEmpty && !rankCutoffs.keys.contains(rank)) throw Exception("Invalid rank");
|
if (rank.isNotEmpty && !rankCutoffs.keys.contains(rank)) throw Exception("Invalid rank");
|
||||||
List<TetrioPlayerFromLeaderboard> filtredLeaderboard = List.from(leaderboard);
|
List<TetrioPlayerFromLeaderboard> filtredLeaderboard = List.from(leaderboard);
|
||||||
|
@ -1711,6 +1861,30 @@ class TetrioPlayersLeaderboard {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
PlayerLeaderboardPosition? getLeaderboardPosition(TetrioPlayer user) {
|
||||||
|
if (user.tlSeason1.gamesPlayed == 0) return null;
|
||||||
|
bool fakePositions = false;
|
||||||
|
late List<TetrioPlayerFromLeaderboard> copyOfLeaderboard;
|
||||||
|
if (leaderboard.indexWhere((element) => element.userId == user.userId) == -1){
|
||||||
|
fakePositions =true;
|
||||||
|
copyOfLeaderboard = List.of(leaderboard);
|
||||||
|
copyOfLeaderboard.add(user.convertToPlayerFromLeaderboard());
|
||||||
|
}
|
||||||
|
List<Stats> stats = [Stats.apm, Stats.pps, Stats.vs, Stats.gp, Stats.gw, Stats.wr,
|
||||||
|
Stats.app, Stats.vsapm, Stats.dss, Stats.dsp, Stats.appdsp, Stats.cheese, Stats.gbe, Stats.nyaapp, Stats.area, Stats.eTR, Stats.acceTR];
|
||||||
|
List<LeaderboardPosition?> results = [];
|
||||||
|
for (Stats stat in stats) {
|
||||||
|
List<TetrioPlayerFromLeaderboard> sortedLeaderboard = getStatRanking(fakePositions ? copyOfLeaderboard : leaderboard, stat, reversed: stat == Stats.cheese ? true : false);
|
||||||
|
int position = sortedLeaderboard.indexWhere((element) => element.userId == user.userId) + 1;
|
||||||
|
if (position == 0) {
|
||||||
|
results.add(null);
|
||||||
|
} else {
|
||||||
|
results.add(LeaderboardPosition(fakePositions ? 1001 : position, position / sortedLeaderboard.length));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return PlayerLeaderboardPosition.fromSearchResults(results);
|
||||||
|
}
|
||||||
|
|
||||||
Map<String, List<dynamic>> get averages => {
|
Map<String, List<dynamic>> get averages => {
|
||||||
'x': getAverageOfRank("x"),
|
'x': getAverageOfRank("x"),
|
||||||
'u': getAverageOfRank("u"),
|
'u': getAverageOfRank("u"),
|
||||||
|
@ -1732,6 +1906,26 @@ class TetrioPlayersLeaderboard {
|
||||||
'z': getAverageOfRank("z")
|
'z': getAverageOfRank("z")
|
||||||
};
|
};
|
||||||
|
|
||||||
|
Map<String, double> get cutoffs => {
|
||||||
|
'x': getAverageOfRank("x")[1]["toEnterTR"],
|
||||||
|
'u': getAverageOfRank("u")[1]["toEnterTR"],
|
||||||
|
'ss': getAverageOfRank("ss")[1]["toEnterTR"],
|
||||||
|
's+': getAverageOfRank("s+")[1]["toEnterTR"],
|
||||||
|
's': getAverageOfRank("s")[1]["toEnterTR"],
|
||||||
|
's-': getAverageOfRank("s-")[1]["toEnterTR"],
|
||||||
|
'a+': getAverageOfRank("a+")[1]["toEnterTR"],
|
||||||
|
'a': getAverageOfRank("a")[1]["toEnterTR"],
|
||||||
|
'a-': getAverageOfRank("a-")[1]["toEnterTR"],
|
||||||
|
'b+': getAverageOfRank("b+")[1]["toEnterTR"],
|
||||||
|
'b': getAverageOfRank("b")[1]["toEnterTR"],
|
||||||
|
'b-': getAverageOfRank("b-")[1]["toEnterTR"],
|
||||||
|
'c+': getAverageOfRank("c+")[1]["toEnterTR"],
|
||||||
|
'c': getAverageOfRank("c")[1]["toEnterTR"],
|
||||||
|
'c-': getAverageOfRank("c-")[1]["toEnterTR"],
|
||||||
|
'd+': getAverageOfRank("d+")[1]["toEnterTR"],
|
||||||
|
'd': getAverageOfRank("d")[1]["toEnterTR"]
|
||||||
|
};
|
||||||
|
|
||||||
TetrioPlayersLeaderboard.fromJson(List<dynamic> json, String t, DateTime ts) {
|
TetrioPlayersLeaderboard.fromJson(List<dynamic> json, String t, DateTime ts) {
|
||||||
type = t;
|
type = t;
|
||||||
timestamp = ts;
|
timestamp = ts;
|
||||||
|
@ -1785,7 +1979,11 @@ class TetrioPlayerFromLeaderboard {
|
||||||
this.apm,
|
this.apm,
|
||||||
this.pps,
|
this.pps,
|
||||||
this.vs,
|
this.vs,
|
||||||
this.decaying);
|
this.decaying){
|
||||||
|
nerdStats = NerdStats(apm, pps, vs);
|
||||||
|
estTr = EstTr(apm, pps, vs, nerdStats.app, nerdStats.dss, nerdStats.dsp, nerdStats.gbe);
|
||||||
|
playstyle = Playstyle(apm, pps, nerdStats.app, nerdStats.vsapm, nerdStats.dsp, nerdStats.gbe, estTr.srarea, estTr.statrank);
|
||||||
|
}
|
||||||
|
|
||||||
double get winrate => gamesWon / gamesPlayed;
|
double get winrate => gamesWon / gamesPlayed;
|
||||||
double get esttracc => estTr.esttr - rating;
|
double get esttracc => estTr.esttr - rating;
|
||||||
|
@ -1857,6 +2055,8 @@ class TetrioPlayerFromLeaderboard {
|
||||||
return estTr.esttr;
|
return estTr.esttr;
|
||||||
case Stats.acceTR:
|
case Stats.acceTR:
|
||||||
return esttracc;
|
return esttracc;
|
||||||
|
case Stats.acceTRabs:
|
||||||
|
return esttracc.abs();
|
||||||
case Stats.opener:
|
case Stats.opener:
|
||||||
return playstyle.opener;
|
return playstyle.opener;
|
||||||
case Stats.plonk:
|
case Stats.plonk:
|
||||||
|
|
|
@ -1,4 +1,6 @@
|
||||||
import 'dart:math';
|
import 'dart:math';
|
||||||
|
import 'package:vector_math/vector_math_64.dart';
|
||||||
|
|
||||||
import 'tetrio.dart';
|
import 'tetrio.dart';
|
||||||
|
|
||||||
// I want to implement those fancy TWC stats
|
// I want to implement those fancy TWC stats
|
||||||
|
@ -148,10 +150,29 @@ class ReplayStats{
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
class AggregateStats{
|
||||||
|
double apm;
|
||||||
|
double pps;
|
||||||
|
double vs;
|
||||||
|
late NerdStats nerdStats;
|
||||||
|
late EstTr estTr;
|
||||||
|
late Playstyle playstyle;
|
||||||
|
double spp;
|
||||||
|
double kpp;
|
||||||
|
double kps;
|
||||||
|
|
||||||
|
AggregateStats(this.apm, this.pps, this.vs, this.spp, this.kpp, this.kps){
|
||||||
|
nerdStats = NerdStats(apm, pps, vs);
|
||||||
|
estTr = EstTr(apm, pps, vs, nerdStats.app, nerdStats.dss, nerdStats.dsp, nerdStats.gbe);
|
||||||
|
playstyle = Playstyle(apm, pps, nerdStats.app, nerdStats.vsapm, nerdStats.dsp, nerdStats.gbe, estTr.srarea, estTr.statrank);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
class ReplayData{
|
class ReplayData{
|
||||||
late String id;
|
late String id;
|
||||||
late Map<dynamic, dynamic> rawJson;
|
late Map<dynamic, dynamic> rawJson;
|
||||||
late List<EndContextMulti> endcontext;
|
late List<EndContextMulti> endcontext;
|
||||||
|
late List<AggregateStats> timeWeightedStats;
|
||||||
late List<List<ReplayStats>> stats;
|
late List<List<ReplayStats>> stats;
|
||||||
late List<ReplayStats> totalStats;
|
late List<ReplayStats> totalStats;
|
||||||
late List<List<String>> roundWinners;
|
late List<List<String>> roundWinners;
|
||||||
|
@ -178,20 +199,45 @@ class ReplayData{
|
||||||
totalLength = 0;
|
totalLength = 0;
|
||||||
stats = [];
|
stats = [];
|
||||||
roundWinners = [];
|
roundWinners = [];
|
||||||
|
int roundID = 0;
|
||||||
|
List<double> APMmultipliedByWeights = [0, 0];
|
||||||
|
List<double> PPSmultipliedByWeights = [0, 0];
|
||||||
|
List<double> VSmultipliedByWeights = [0, 0];
|
||||||
|
List<double> SPPmultipliedByWeights = [0, 0];
|
||||||
|
List<double> KPPmultipliedByWeights = [0, 0];
|
||||||
|
List<double> KPSmultipliedByWeights = [0, 0];
|
||||||
totalStats = [ReplayStats.createEmpty(), ReplayStats.createEmpty()];
|
totalStats = [ReplayStats.createEmpty(), ReplayStats.createEmpty()];
|
||||||
for(var round in json['data']) {
|
for(var round in json['data']) {
|
||||||
int firstInEndContext = round['replays'][0]["events"].last['data']['export']['options']['gameid'].startsWith(endcontext[0].userId) ? 0 : 1;
|
int firstInEndContext = round['replays'][0]["events"].last['data']['export']['options']['gameid'].startsWith(endcontext[0].userId) ? 0 : 1;
|
||||||
int secondInEndContext = round['replays'][1]["events"].last['data']['export']['options']['gameid'].startsWith(endcontext[1].userId) ? 1 : 0;
|
int secondInEndContext = round['replays'][1]["events"].last['data']['export']['options']['gameid'].startsWith(endcontext[1].userId) ? 1 : 0;
|
||||||
roundLengths.add(max(round['replays'][0]['frames'], round['replays'][1]['frames']));
|
int roundLength = max(round['replays'][0]['frames'], round['replays'][1]['frames']);
|
||||||
|
roundLengths.add(roundLength);
|
||||||
totalLength = totalLength + max(round['replays'][0]['frames'], round['replays'][1]['frames']);
|
totalLength = totalLength + max(round['replays'][0]['frames'], round['replays'][1]['frames']);
|
||||||
|
APMmultipliedByWeights[0] += endcontext[0].secondaryTracking[roundID]*roundLength;
|
||||||
|
APMmultipliedByWeights[1] += endcontext[1].secondaryTracking[roundID]*roundLength;
|
||||||
|
PPSmultipliedByWeights[0] += endcontext[0].tertiaryTracking[roundID]*roundLength;
|
||||||
|
PPSmultipliedByWeights[1] += endcontext[1].tertiaryTracking[roundID]*roundLength;
|
||||||
|
VSmultipliedByWeights[0] += endcontext[0].extraTracking[roundID]*roundLength;
|
||||||
|
VSmultipliedByWeights[1] += endcontext[1].extraTracking[roundID]*roundLength;
|
||||||
int winner = round['board'].indexWhere((element) => element['success'] == true);
|
int winner = round['board'].indexWhere((element) => element['success'] == true);
|
||||||
roundWinners.add([round['board'][winner]['id'], round['board'][winner]['username']]);
|
roundWinners.add([round['board'][winner]['id'], round['board'][winner]['username']]);
|
||||||
ReplayStats playerOne = ReplayStats.fromJson(round['replays'][firstInEndContext]['events'].last['data']['export']['stats'], biggestSpikeFromReplay(round['replays'][secondInEndContext]['events']), round['replays'][firstInEndContext]['frames']); // (events contain recived attacks)
|
ReplayStats playerOne = ReplayStats.fromJson(round['replays'][firstInEndContext]['events'].last['data']['export']['stats'], biggestSpikeFromReplay(round['replays'][secondInEndContext]['events']), round['replays'][firstInEndContext]['frames']); // (events contain recived attacks)
|
||||||
ReplayStats playerTwo = ReplayStats.fromJson(round['replays'][secondInEndContext]['events'].last['data']['export']['stats'], biggestSpikeFromReplay(round['replays'][firstInEndContext]['events']), round['replays'][secondInEndContext]['frames']);
|
ReplayStats playerTwo = ReplayStats.fromJson(round['replays'][secondInEndContext]['events'].last['data']['export']['stats'], biggestSpikeFromReplay(round['replays'][firstInEndContext]['events']), round['replays'][secondInEndContext]['frames']);
|
||||||
|
SPPmultipliedByWeights[0] += playerOne.spp*roundLength;
|
||||||
|
SPPmultipliedByWeights[1] += playerTwo.spp*roundLength;
|
||||||
|
KPPmultipliedByWeights[0] += playerOne.kpp*roundLength;
|
||||||
|
KPPmultipliedByWeights[1] += playerTwo.kpp*roundLength;
|
||||||
|
KPSmultipliedByWeights[0] += playerOne.kps*roundLength;
|
||||||
|
KPSmultipliedByWeights[1] += playerTwo.kps*roundLength;
|
||||||
stats.add([playerOne, playerTwo]);
|
stats.add([playerOne, playerTwo]);
|
||||||
totalStats[0] = totalStats[0] + playerOne;
|
totalStats[0] = totalStats[0] + playerOne;
|
||||||
totalStats[1] = totalStats[1] + playerTwo;
|
totalStats[1] = totalStats[1] + playerTwo;
|
||||||
|
roundID ++;
|
||||||
}
|
}
|
||||||
|
timeWeightedStats = [
|
||||||
|
AggregateStats(APMmultipliedByWeights[0]/totalLength, PPSmultipliedByWeights[0]/totalLength, VSmultipliedByWeights[0]/totalLength, SPPmultipliedByWeights[0]/totalLength, KPPmultipliedByWeights[0]/totalLength, KPSmultipliedByWeights[0]/totalLength),
|
||||||
|
AggregateStats(APMmultipliedByWeights[1]/totalLength, PPSmultipliedByWeights[1]/totalLength, VSmultipliedByWeights[1]/totalLength, SPPmultipliedByWeights[1]/totalLength, KPPmultipliedByWeights[1]/totalLength, KPSmultipliedByWeights[1]/totalLength)
|
||||||
|
];
|
||||||
}
|
}
|
||||||
|
|
||||||
Map<String, dynamic> toJson(){
|
Map<String, dynamic> toJson(){
|
||||||
|
@ -212,3 +258,402 @@ class ReplayData{
|
||||||
return data;
|
return data;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// can't belive i have to implement that difficult shit
|
||||||
|
|
||||||
|
// List<Event> readEventList(Map<dynamic, dynamic> json){
|
||||||
|
// List<Event> events = [];
|
||||||
|
// int id = 0;
|
||||||
|
// for (var event in json['data'][0]['replays'][0]['events']){
|
||||||
|
// int frame = event["frame"];
|
||||||
|
// EventType type = EventType.values.byName(event['type']);
|
||||||
|
// switch (type) {
|
||||||
|
// case EventType.start:
|
||||||
|
// events.add(Event(id, frame, type));
|
||||||
|
// break;
|
||||||
|
// case EventType.full:
|
||||||
|
// events.add(EventFull(id, frame, type, DataFull.fromJson(event["data"])));
|
||||||
|
// break;
|
||||||
|
// case EventType.targets:
|
||||||
|
// // TODO
|
||||||
|
// break;
|
||||||
|
// case EventType.keydown:
|
||||||
|
// events.add(EventKeyPress(id, frame, type,
|
||||||
|
// Keypress(
|
||||||
|
// KeyType.values.byName(event['data']['key']),
|
||||||
|
// event['data']['subframe'],
|
||||||
|
// false)
|
||||||
|
// ));
|
||||||
|
// break;
|
||||||
|
// case EventType.keyup:
|
||||||
|
// events.add(EventKeyPress(id, frame, type,
|
||||||
|
// Keypress(
|
||||||
|
// KeyType.values.byName(event['data']['key']),
|
||||||
|
// event['data']['subframe'],
|
||||||
|
// true)
|
||||||
|
// ));
|
||||||
|
// break;
|
||||||
|
// case EventType.end:
|
||||||
|
// // TODO: Handle this case.
|
||||||
|
// case EventType.ige:
|
||||||
|
// // TODO: Handle this case.
|
||||||
|
// case EventType.exit:
|
||||||
|
// // TODO: Handle this case.
|
||||||
|
// }
|
||||||
|
// id++;
|
||||||
|
// }
|
||||||
|
// return [];
|
||||||
|
// }
|
||||||
|
|
||||||
|
// enum EventType
|
||||||
|
// {
|
||||||
|
// start,
|
||||||
|
// end,
|
||||||
|
// full,
|
||||||
|
// keydown,
|
||||||
|
// keyup,
|
||||||
|
// targets,
|
||||||
|
// ige,
|
||||||
|
// exit
|
||||||
|
// }
|
||||||
|
|
||||||
|
// enum KeyType
|
||||||
|
// {
|
||||||
|
// moveLeft,
|
||||||
|
// moveRight,
|
||||||
|
// softDrop,
|
||||||
|
// rotateCCW,
|
||||||
|
// rotateCW,
|
||||||
|
// rotate180,
|
||||||
|
// hardDrop,
|
||||||
|
// hold,
|
||||||
|
// chat,
|
||||||
|
// exit,
|
||||||
|
// retry
|
||||||
|
// }
|
||||||
|
|
||||||
|
// class Event{
|
||||||
|
// int id;
|
||||||
|
// int frame;
|
||||||
|
// EventType type;
|
||||||
|
// //dynamic data;
|
||||||
|
|
||||||
|
// Event(this.id, this.frame, this.type);
|
||||||
|
|
||||||
|
// @override
|
||||||
|
// String toString(){
|
||||||
|
// return "E#$id f#$frame: $type";
|
||||||
|
// }
|
||||||
|
// }
|
||||||
|
|
||||||
|
// class Keypress{
|
||||||
|
// KeyType key;
|
||||||
|
// double subframe;
|
||||||
|
// bool released;
|
||||||
|
|
||||||
|
// Keypress(this.key, this.subframe, this.released);
|
||||||
|
// }
|
||||||
|
|
||||||
|
// class EventKeyPress extends Event{
|
||||||
|
// Keypress data;
|
||||||
|
|
||||||
|
// EventKeyPress(super.id, super.frame, super.type, this.data);
|
||||||
|
// }
|
||||||
|
|
||||||
|
// class IGE{
|
||||||
|
// int id;
|
||||||
|
// int frame;
|
||||||
|
// String type;
|
||||||
|
// int amount;
|
||||||
|
|
||||||
|
// IGE(this.id, this.frame, this.type, this.amount);
|
||||||
|
// }
|
||||||
|
|
||||||
|
// class EventIGE extends Event{
|
||||||
|
// IGE data;
|
||||||
|
|
||||||
|
// EventIGE(super.id, super.frame, super.type, this.data);
|
||||||
|
// }
|
||||||
|
|
||||||
|
// class Hold
|
||||||
|
// {
|
||||||
|
// String? piece;
|
||||||
|
// bool locked;
|
||||||
|
|
||||||
|
// Hold(this.piece, this.locked);
|
||||||
|
// }
|
||||||
|
|
||||||
|
// class DataFullOptions{
|
||||||
|
// int? version;
|
||||||
|
// bool? seedRandom;
|
||||||
|
// int? seed;
|
||||||
|
// double? g;
|
||||||
|
// int? stock;
|
||||||
|
// int? gMargin;
|
||||||
|
// double? gIncrease;
|
||||||
|
// double? garbageMultiplier;
|
||||||
|
// int? garbageMargin;
|
||||||
|
// double? garbageIncrease;
|
||||||
|
// int? garbageCap;
|
||||||
|
// double? garbageCapIncrease;
|
||||||
|
// int? garbageCapMax;
|
||||||
|
// int? garbageHoleSize;
|
||||||
|
// String? garbageBlocking; // TODO: enum
|
||||||
|
// bool? hasGarbage;
|
||||||
|
// int? locktime;
|
||||||
|
// int? garbageSpeed;
|
||||||
|
// int? forfeitTime;
|
||||||
|
// int? are;
|
||||||
|
// int? areLineclear;
|
||||||
|
// bool? infiniteMovement;
|
||||||
|
// int? lockresets;
|
||||||
|
// bool? allow180;
|
||||||
|
// bool? btbChaining;
|
||||||
|
// bool? allclears;
|
||||||
|
// bool? clutch;
|
||||||
|
// bool? noLockout;
|
||||||
|
// String? passthrough;
|
||||||
|
// int? boardwidth;
|
||||||
|
// int? boardheight;
|
||||||
|
// Handling? handling;
|
||||||
|
// int? boardbuffer;
|
||||||
|
|
||||||
|
// DataFullOptions.fromJson(Map<String, dynamic> json){
|
||||||
|
// version = json["version"];
|
||||||
|
// seedRandom = json["seed_random"];
|
||||||
|
// seed = json["seed"];
|
||||||
|
// g = json["g"];
|
||||||
|
// stock = json["stock"];
|
||||||
|
// gMargin = json["gmargin"];
|
||||||
|
// gIncrease = json["gincrease"];
|
||||||
|
// garbageMultiplier = json["garbagemultiplier"];
|
||||||
|
// garbageCapIncrease = json["garbagecapincrease"];
|
||||||
|
// garbageCapMax = json["garbagecapmax"];
|
||||||
|
// garbageHoleSize = json["garbageholesize"];
|
||||||
|
// garbageBlocking = json["garbageblocking"];
|
||||||
|
// hasGarbage = json["hasgarbage"];
|
||||||
|
// locktime = json["locktime"];
|
||||||
|
// garbageSpeed = json["garbagespeed"];
|
||||||
|
// forfeitTime = json["forfeit_time"];
|
||||||
|
// are = json["are"];
|
||||||
|
// areLineclear = json["lineclear_are"];
|
||||||
|
// infiniteMovement = json["infinitemovement"];
|
||||||
|
// lockresets = json["lockresets"];
|
||||||
|
// allow180 = json["allow180"];
|
||||||
|
// btbChaining = json["b2bchaining"];
|
||||||
|
// allclears = json["allclears"];
|
||||||
|
// clutch = json["clutch"];
|
||||||
|
// noLockout = json["nolockout"];
|
||||||
|
// passthrough = json["passthrough"];
|
||||||
|
// boardwidth = json["boardwidth"];
|
||||||
|
// boardheight = json["boardheight"];
|
||||||
|
// handling = Handling.fromJson(json["handling"]);
|
||||||
|
// boardbuffer = json["boardbuffer"];
|
||||||
|
// }
|
||||||
|
// }
|
||||||
|
|
||||||
|
// class DataFullStats
|
||||||
|
// {
|
||||||
|
// double? seed;
|
||||||
|
// int? lines;
|
||||||
|
// int? levelLines;
|
||||||
|
// int? levelLinesNeeded;
|
||||||
|
// int? inputs;
|
||||||
|
// int? holds;
|
||||||
|
// int? score;
|
||||||
|
// int? zenLevel;
|
||||||
|
// int? zenProgress;
|
||||||
|
// int? level;
|
||||||
|
// int? combo;
|
||||||
|
// int? currentComboPower;
|
||||||
|
// int? topCombo;
|
||||||
|
// int? btb;
|
||||||
|
// int? topbtb;
|
||||||
|
// int? tspins;
|
||||||
|
// int? piecesPlaced;
|
||||||
|
// Clears? clears;
|
||||||
|
// Garbage? garbage;
|
||||||
|
// int? kills;
|
||||||
|
// Finesse? finesse;
|
||||||
|
|
||||||
|
// DataFullStats.fromJson(Map<String, dynamic> json){
|
||||||
|
// seed = json["seed"];
|
||||||
|
// lines = json["lines"];
|
||||||
|
// levelLines = json["level_lines"];
|
||||||
|
// levelLinesNeeded = json["level_lines_needed"];
|
||||||
|
// inputs = json["inputs"];
|
||||||
|
// holds = json["holds"];
|
||||||
|
// score = json["score"];
|
||||||
|
// zenLevel = json["zenlevel"];
|
||||||
|
// zenProgress = json["zenprogress"];
|
||||||
|
// level = json["level"];
|
||||||
|
// combo = json["combo"];
|
||||||
|
// currentComboPower = json["currentcombopower"];
|
||||||
|
// topCombo = json["topcombo"];
|
||||||
|
// btb = json["btb"];
|
||||||
|
// topbtb = json["topbtb"];
|
||||||
|
// tspins = json["tspins"];
|
||||||
|
// piecesPlaced = json["piecesplaced"];
|
||||||
|
// clears = Clears.fromJson(json["clears"]);
|
||||||
|
// garbage = Garbage.fromJson(json["garbage"]);
|
||||||
|
// kills = json["kills"];
|
||||||
|
// finesse = Finesse.fromJson(json["finesse"]);
|
||||||
|
// }
|
||||||
|
// }
|
||||||
|
|
||||||
|
// class DataFullGame
|
||||||
|
// {
|
||||||
|
// List<List<String?>>? board;
|
||||||
|
// List<String>? bag;
|
||||||
|
// double? g;
|
||||||
|
// bool? playing;
|
||||||
|
// Hold? hold;
|
||||||
|
// String? piece;
|
||||||
|
// Handling? handling;
|
||||||
|
|
||||||
|
// DataFullGame.fromJson(Map<String, dynamic> json){
|
||||||
|
// board = json["board"];
|
||||||
|
// bag = json["bag"];
|
||||||
|
// hold = Hold(json["hold"]["piece"], json["hold"]["locked"]);
|
||||||
|
// g = json["g"];
|
||||||
|
// handling = Handling.fromJson(json["handling"]);
|
||||||
|
// }
|
||||||
|
// }
|
||||||
|
|
||||||
|
// class DataFull{
|
||||||
|
// bool? successful;
|
||||||
|
// String? gameOverReason;
|
||||||
|
// int? fire;
|
||||||
|
// DataFullOptions? options;
|
||||||
|
// DataFullStats? stats;
|
||||||
|
// DataFullGame? game;
|
||||||
|
|
||||||
|
// DataFull.fromJson(Map<String, dynamic> json){
|
||||||
|
// successful = json["successful"];
|
||||||
|
// gameOverReason = json["gameoverreason"];
|
||||||
|
// fire = json["fire"];
|
||||||
|
// options = DataFullOptions.fromJson(json["options"]);
|
||||||
|
// stats = DataFullStats.fromJson(json["stats"]);
|
||||||
|
// game = DataFullGame.fromJson(json["game"]);
|
||||||
|
// }
|
||||||
|
// }
|
||||||
|
|
||||||
|
// class EventFull extends Event{
|
||||||
|
// DataFull data;
|
||||||
|
|
||||||
|
// EventFull(super.id, super.frame, super.type, this.data);
|
||||||
|
// }
|
||||||
|
|
||||||
|
// class TetrioRNG{
|
||||||
|
// late double _t;
|
||||||
|
|
||||||
|
// TetrioRNG(int seed){
|
||||||
|
// _t = seed % 2147483647;
|
||||||
|
// if (_t <= 0) _t += 2147483646;
|
||||||
|
// }
|
||||||
|
|
||||||
|
// int next(){
|
||||||
|
// _t = 16807 * _t % 2147483647;
|
||||||
|
// return _t.toInt();
|
||||||
|
// }
|
||||||
|
|
||||||
|
// double nextFloat(){
|
||||||
|
// return (next() - 1) / 2147483646;
|
||||||
|
// }
|
||||||
|
|
||||||
|
// List<Tetromino> shuffleList(List<Tetromino> array){
|
||||||
|
// int length = array.length;
|
||||||
|
// if (length == 0) return [];
|
||||||
|
|
||||||
|
// for (; --length > 0;){
|
||||||
|
// int swapIndex = ((nextFloat()) * (length + 1)).toInt();
|
||||||
|
// Tetromino tmp = array[length];
|
||||||
|
// array[length] = array[swapIndex];
|
||||||
|
// array[swapIndex] = tmp;
|
||||||
|
// }
|
||||||
|
// return array;
|
||||||
|
// }
|
||||||
|
// }
|
||||||
|
|
||||||
|
// enum Tetromino{
|
||||||
|
// Z,
|
||||||
|
// L,
|
||||||
|
// O,
|
||||||
|
// S,
|
||||||
|
// I,
|
||||||
|
// J,
|
||||||
|
// T,
|
||||||
|
// garbage,
|
||||||
|
// empty
|
||||||
|
// }
|
||||||
|
|
||||||
|
// List<Tetromino> tetrominoes = [Tetromino.Z, Tetromino.L, Tetromino.O, Tetromino.S, Tetromino.I, Tetromino.J, Tetromino.T];
|
||||||
|
// List<List<List<Vector2>>> shapes = [
|
||||||
|
// [ // Z
|
||||||
|
// [Vector2(0, 0), Vector2(1, 0), Vector2(1, 1), Vector2(2, 1)],
|
||||||
|
// [Vector2(2, 0), Vector2(1, 1), Vector2(2, 1), Vector2(1, 2)],
|
||||||
|
// [Vector2(0, 1), Vector2(1, 1), Vector2(1, 2), Vector2(2, 2)],
|
||||||
|
// [Vector2(1, 0), Vector2(0, 1), Vector2(1, 1), Vector2(0, 2)]
|
||||||
|
// ],
|
||||||
|
// [ // L
|
||||||
|
// [Vector2(2, 0), Vector2(0, 1), Vector2(1, 1), Vector2(2, 1)],
|
||||||
|
// [Vector2(1, 0), Vector2(1, 1), Vector2(1, 2), Vector2(2, 2)],
|
||||||
|
// [Vector2(0, 1), Vector2(1, 1), Vector2(2, 1), Vector2(0, 2)],
|
||||||
|
// [Vector2(0, 0), Vector2(1, 0), Vector2(1, 1), Vector2(1, 2)]
|
||||||
|
// ],
|
||||||
|
// [ // O
|
||||||
|
// [Vector2(0, 0), Vector2(1, 0), Vector2(0, 1), Vector2(1, 1)],
|
||||||
|
// [Vector2(0, 0), Vector2(1, 0), Vector2(0, 1), Vector2(1, 1)],
|
||||||
|
// [Vector2(0, 0), Vector2(1, 0), Vector2(0, 1), Vector2(1, 1)],
|
||||||
|
// [Vector2(0, 0), Vector2(1, 0), Vector2(0, 1), Vector2(1, 1)]
|
||||||
|
// ],
|
||||||
|
// [ // S
|
||||||
|
// [Vector2(1, 0), Vector2(2, 0), Vector2(0, 1), Vector2(1, 1)],
|
||||||
|
// [Vector2(1, 0), Vector2(1, 1), Vector2(2, 1), Vector2(2, 2)],
|
||||||
|
// [Vector2(1, 1), Vector2(2, 1), Vector2(0, 2), Vector2(1, 2)],
|
||||||
|
// [Vector2(0, 0), Vector2(0, 1), Vector2(1, 1), Vector2(1, 2)]
|
||||||
|
// ],
|
||||||
|
// [ // I
|
||||||
|
// [Vector2(0, 1), Vector2(1, 1), Vector2(2, 1), Vector2(3, 1)],
|
||||||
|
// [Vector2(2, 0), Vector2(2, 1), Vector2(2, 2), Vector2(2, 3)],
|
||||||
|
// [Vector2(0, 2), Vector2(1, 2), Vector2(2, 2), Vector2(3, 2)],
|
||||||
|
// [Vector2(1, 0), Vector2(1, 1), Vector2(1, 2), Vector2(1, 3)]
|
||||||
|
// ],
|
||||||
|
// [ // J
|
||||||
|
// [Vector2(0, 0), Vector2(0, 1), Vector2(1, 1), Vector2(2, 1)],
|
||||||
|
// [Vector2(1, 0), Vector2(2, 0), Vector2(1, 1), Vector2(1, 2)],
|
||||||
|
// [Vector2(0, 1), Vector2(1, 1), Vector2(2, 1), Vector2(2, 2)],
|
||||||
|
// [Vector2(1, 0), Vector2(1, 1), Vector2(0, 2), Vector2(1, 2)]
|
||||||
|
// ],
|
||||||
|
// [ // T
|
||||||
|
// [Vector2(1, 0), Vector2(0, 1), Vector2(1, 1), Vector2(2, 1)],
|
||||||
|
// [Vector2(1, 0), Vector2(1, 1), Vector2(2, 1), Vector2(1, 2)],
|
||||||
|
// [Vector2(0, 1), Vector2(1, 1), Vector2(2, 1), Vector2(1, 2)],
|
||||||
|
// [Vector2(1, 0), Vector2(0, 1), Vector2(1, 1), Vector2(1, 2)]
|
||||||
|
// ]
|
||||||
|
// ];
|
||||||
|
// List<Vector2> spawnPositionFixes = [Vector2(1, 1), Vector2(1, 1), Vector2(0, 1), Vector2(1, 1), Vector2(1, 1), Vector2(1, 1), Vector2(1, 1)];
|
||||||
|
|
||||||
|
// const Map<String, double> garbage = {
|
||||||
|
// "single": 0,
|
||||||
|
// "double": 1,
|
||||||
|
// "triple": 2,
|
||||||
|
// "quad": 4,
|
||||||
|
// "penta": 5,
|
||||||
|
// "t-spin": 0,
|
||||||
|
// "t-spin single": 2,
|
||||||
|
// "t-spin double": 4,
|
||||||
|
// "t-spin triple": 6,
|
||||||
|
// "t-spin quad": 10,
|
||||||
|
// "t-spin penta": 12,
|
||||||
|
// "t-spin mini": 0,
|
||||||
|
// "t-spin mini single": 0,
|
||||||
|
// "t-spin mini double": 1,
|
||||||
|
// "allclear": 10
|
||||||
|
// };
|
||||||
|
// int btbBonus = 1;
|
||||||
|
// double btbLog = 0.8;
|
||||||
|
// double comboBonus = 0.25;
|
||||||
|
// int comboMinifier = 1;
|
||||||
|
// double comboMinifierLog = 1.25;
|
||||||
|
// List<int> comboTable = [0, 1, 1, 2, 2, 3, 3, 4, 4, 4, 5];
|
||||||
|
|
|
@ -4,9 +4,9 @@
|
||||||
/// To regenerate, run: `dart run slang`
|
/// To regenerate, run: `dart run slang`
|
||||||
///
|
///
|
||||||
/// Locales: 2
|
/// Locales: 2
|
||||||
/// Strings: 1018 (509 per locale)
|
/// Strings: 1120 (560 per locale)
|
||||||
///
|
///
|
||||||
/// Built on 2024-02-08 at 20:30 UTC
|
/// Built on 2024-03-24 at 14:28 UTC
|
||||||
|
|
||||||
// coverage:ignore-file
|
// coverage:ignore-file
|
||||||
// ignore_for_file: type=lint
|
// ignore_for_file: type=lint
|
||||||
|
@ -181,6 +181,14 @@ class Translations implements BaseTranslations<AppLocale, Translations> {
|
||||||
String get stoppedBeingTracked => 'Removed from tracking list!';
|
String get stoppedBeingTracked => 'Removed from tracking list!';
|
||||||
String get tlLeaderboard => 'Tetra League leaderboard';
|
String get tlLeaderboard => 'Tetra League leaderboard';
|
||||||
String get noRecords => 'No records';
|
String get noRecords => 'No records';
|
||||||
|
String noOldRecords({required num n}) => (_root.$meta.cardinalResolver ?? PluralResolvers.cardinal('en'))(n,
|
||||||
|
zero: 'No records',
|
||||||
|
one: 'Only ${n} record',
|
||||||
|
two: 'Only ${n} records',
|
||||||
|
few: 'Only ${n} records',
|
||||||
|
many: 'Only ${n} records',
|
||||||
|
other: 'Only ${n} records',
|
||||||
|
);
|
||||||
String get noRecord => 'No record';
|
String get noRecord => 'No record';
|
||||||
String get botRecord => 'Bots are not allowed to set records';
|
String get botRecord => 'Bots are not allowed to set records';
|
||||||
String get anonRecord => 'Guests are not allowed to set records';
|
String get anonRecord => 'Guests are not allowed to set records';
|
||||||
|
@ -204,7 +212,10 @@ class Translations implements BaseTranslations<AppLocale, Translations> {
|
||||||
String supporter({required Object tier}) => 'Supporter tier ${tier}';
|
String supporter({required Object tier}) => 'Supporter tier ${tier}';
|
||||||
String comparingWith({required Object newDate, required Object oldDate}) => 'Data from ${newDate} comparing with ${oldDate}';
|
String comparingWith({required Object newDate, required Object oldDate}) => 'Data from ${newDate} comparing with ${oldDate}';
|
||||||
String get top => 'Top';
|
String get top => 'Top';
|
||||||
String get topRank => 'Top Rank';
|
String get topRank => 'Top rank';
|
||||||
|
String verdictGeneral({required Object n, required Object verdict, required Object rank}) => '${n} ${verdict} than ${rank} rank average';
|
||||||
|
String get verdictBetter => 'better';
|
||||||
|
String get verdictWorse => 'worse';
|
||||||
String gamesUntilRanked({required Object left}) => '${left} games until being ranked';
|
String gamesUntilRanked({required Object left}) => '${left} games until being ranked';
|
||||||
String get nerdStats => 'Nerd Stats';
|
String get nerdStats => 'Nerd Stats';
|
||||||
String get playersYouTrack => 'Players you track';
|
String get playersYouTrack => 'Players you track';
|
||||||
|
@ -228,8 +239,14 @@ class Translations implements BaseTranslations<AppLocale, Translations> {
|
||||||
String get yourIDAlertTitle => 'Your nickname in TETR.IO';
|
String get yourIDAlertTitle => 'Your nickname in TETR.IO';
|
||||||
String get yourIDText => 'When app loads, it will retrieve data for this account';
|
String get yourIDText => 'When app loads, it will retrieve data for this account';
|
||||||
String get language => 'Language';
|
String get language => 'Language';
|
||||||
|
String get customization => 'Customization';
|
||||||
|
String get customizationDescription => 'There is only one toggle, planned to add more settings';
|
||||||
|
String get lbStats => 'Show leaderboard based stats';
|
||||||
|
String get lbStatsDescription => 'That will impact on loading times, but will allow you to see position on LB by stats and comparison with average values';
|
||||||
String get aboutApp => 'About app';
|
String get aboutApp => 'About app';
|
||||||
String aboutAppText({required Object appName, required Object packageName, required Object version, required Object buildNumber}) => '${appName} (${packageName}) Version ${version} Build ${buildNumber}\n\nDeveloped by dan63047\nFormulas provided by kerrmunism\nHistory provided by p1nkl0bst3r\nTETR.IO replay grabber API by szy';
|
String aboutAppText({required Object appName, required Object packageName, required Object version, required Object buildNumber}) => '${appName} (${packageName}) Version ${version} Build ${buildNumber}\n\nDeveloped by dan63047\nFormulas provided by kerrmunism\nHistory provided by p1nkl0bst3r\nTETR.IO replay grabber API by szy';
|
||||||
|
String get oskKagari => 'Osk Kagari gimmick';
|
||||||
|
String get oskKagariDescription => 'If on, osk\'s rank on main view will be rendered as :kagari:';
|
||||||
String stateViewTitle({required Object nickname, required Object date}) => '${nickname} account on ${date}';
|
String stateViewTitle({required Object nickname, required Object date}) => '${nickname} account on ${date}';
|
||||||
String statesViewTitle({required Object number, required Object nickname}) => '${number} states of ${nickname} account';
|
String statesViewTitle({required Object number, required Object nickname}) => '${number} states of ${nickname} account';
|
||||||
String matchesViewTitle({required Object nickname}) => '${nickname} TL matches';
|
String matchesViewTitle({required Object nickname}) => '${nickname} TL matches';
|
||||||
|
@ -254,10 +271,14 @@ class Translations implements BaseTranslations<AppLocale, Translations> {
|
||||||
String get openReplay => 'Open replay in TETR.IO';
|
String get openReplay => 'Open replay in TETR.IO';
|
||||||
String replaySaved({required Object path}) => 'Replay saved to ${path}';
|
String replaySaved({required Object path}) => 'Replay saved to ${path}';
|
||||||
String get match => 'Match';
|
String get match => 'Match';
|
||||||
|
String get timeWeightedmatch => 'Match (time-weighted)';
|
||||||
String roundNumber({required Object n}) => 'Round ${n}';
|
String roundNumber({required Object n}) => 'Round ${n}';
|
||||||
String get statsFor => 'Stats for';
|
String get statsFor => 'Stats for';
|
||||||
|
String get numberOfRounds => 'Number of rounds';
|
||||||
String get matchLength => 'Match Length';
|
String get matchLength => 'Match Length';
|
||||||
String get roundLength => 'Round Length';
|
String get roundLength => 'Round Length';
|
||||||
|
String get matchStats => 'Match stats';
|
||||||
|
String get timeWeightedmatchStats => 'Time-weighted match stats';
|
||||||
String get replayIssue => 'Can\'t process replay';
|
String get replayIssue => 'Can\'t process replay';
|
||||||
String get matchIsTooOld => 'Replay is not available';
|
String get matchIsTooOld => 'Replay is not available';
|
||||||
String get winner => 'Winner';
|
String get winner => 'Winner';
|
||||||
|
@ -294,6 +315,15 @@ class Translations implements BaseTranslations<AppLocale, Translations> {
|
||||||
many: '${n} players',
|
many: '${n} players',
|
||||||
other: '${n} players',
|
other: '${n} players',
|
||||||
);
|
);
|
||||||
|
String games({required num n}) => (_root.$meta.cardinalResolver ?? PluralResolvers.cardinal('en'))(n,
|
||||||
|
zero: '${n} games',
|
||||||
|
one: '${n} game',
|
||||||
|
two: '${n} games',
|
||||||
|
few: '${n} games',
|
||||||
|
many: '${n} games',
|
||||||
|
other: '${n} games',
|
||||||
|
);
|
||||||
|
String gamesPlayed({required Object games}) => '${games} played';
|
||||||
String get chart => 'Chart';
|
String get chart => 'Chart';
|
||||||
String get entries => 'Entries';
|
String get entries => 'Entries';
|
||||||
String get minimums => 'Minimums';
|
String get minimums => 'Minimums';
|
||||||
|
@ -675,8 +705,30 @@ class _StringsNumOfGameActionsEn {
|
||||||
// Translations
|
// Translations
|
||||||
String get pc => 'All Clears';
|
String get pc => 'All Clears';
|
||||||
String get hold => 'Holds';
|
String get hold => 'Holds';
|
||||||
String get tspinsTotal => 'T-spins total';
|
String inputs({required num n}) => (_root.$meta.cardinalResolver ?? PluralResolvers.cardinal('en'))(n,
|
||||||
String get lineClears => 'Line clears';
|
zero: '${n} key presses',
|
||||||
|
one: '${n} key press',
|
||||||
|
two: '${n} key presses',
|
||||||
|
few: '${n} key presses',
|
||||||
|
many: '${n} key presses',
|
||||||
|
other: '${n} key presses',
|
||||||
|
);
|
||||||
|
String tspinsTotal({required num n}) => (_root.$meta.cardinalResolver ?? PluralResolvers.cardinal('en'))(n,
|
||||||
|
zero: '${n} T-spins total',
|
||||||
|
one: '${n} T-spin total',
|
||||||
|
two: '${n} T-spins total',
|
||||||
|
few: '${n} T-spins total',
|
||||||
|
many: '${n} T-spins total',
|
||||||
|
other: '${n} T-spins total',
|
||||||
|
);
|
||||||
|
String lineClears({required num n}) => (_root.$meta.cardinalResolver ?? PluralResolvers.cardinal('en'))(n,
|
||||||
|
zero: '${n} lines cleared',
|
||||||
|
one: '${n} line cleared',
|
||||||
|
two: '${n} lines cleared',
|
||||||
|
few: '${n} lines cleared',
|
||||||
|
many: '${n} lines cleared',
|
||||||
|
other: '${n} lines cleared',
|
||||||
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
// Path: popupActions
|
// Path: popupActions
|
||||||
|
@ -700,21 +752,30 @@ class _StringsErrorsEn {
|
||||||
// Translations
|
// Translations
|
||||||
String connection({required Object code, required Object message}) => 'Some issue with connection: ${code} ${message}';
|
String connection({required Object code, required Object message}) => 'Some issue with connection: ${code} ${message}';
|
||||||
String get noSuchUser => 'No such user';
|
String get noSuchUser => 'No such user';
|
||||||
|
String get noSuchUserSub => 'Either you mistyped something, or the account no longer exists';
|
||||||
|
String get discordNotAssigned => 'No user assigned to given Discord ID';
|
||||||
|
String get discordNotAssignedSub => 'Make sure you provided valid ID';
|
||||||
String get history => 'History for that player is missing';
|
String get history => 'History for that player is missing';
|
||||||
|
String get actionSuggestion => 'Perhaps, you want to';
|
||||||
String get p1nkl0bst3rTLmatches => 'No Tetra League matches was found';
|
String get p1nkl0bst3rTLmatches => 'No Tetra League matches was found';
|
||||||
String get clientException => 'No internet connection';
|
String get clientException => 'No internet connection';
|
||||||
String get forbidden => 'Your IP address is blocked.\nChange IP address or reach out to osk';
|
String get forbidden => 'Your IP address is blocked';
|
||||||
String get tooManyRequests => 'You have been rate limited. Try again later';
|
String forbiddenSub({required Object nickname}) => 'If you are using VPN or Proxy, turn it off. If this does not help, reach out to ${nickname}';
|
||||||
|
String get tooManyRequests => 'You have been rate limited.';
|
||||||
|
String get tooManyRequestsSub => 'Wait a few moments and try again';
|
||||||
String get internal => 'Something happend on the tetr.io side';
|
String get internal => 'Something happend on the tetr.io side';
|
||||||
|
String get internalSub => 'osk, probably, already aware about it';
|
||||||
String get internalWebVersion => 'Something happend on the tetr.io side (or on oskware_bridge, idk honestly)';
|
String get internalWebVersion => 'Something happend on the tetr.io side (or on oskware_bridge, idk honestly)';
|
||||||
String get oskwareBridge => 'Something happend with oskware_bridge. Let dan63047 know';
|
String get internalWebVersionSub => 'If osk status page says that everything is ok, let dan63047 know about this issue';
|
||||||
String get p1nkl0bst3rForbidden => 'Third party API blocked your IP address.\nChange IP address or reach out to p1nkl0bst3r';
|
String get oskwareBridge => 'Something happend with oskware_bridge';
|
||||||
|
String get oskwareBridgeSub => 'Let dan63047 know';
|
||||||
|
String get p1nkl0bst3rForbidden => 'Third party API blocked your IP address';
|
||||||
String get p1nkl0bst3rTooManyRequests => 'Too many requests to third party API. Try again later';
|
String get p1nkl0bst3rTooManyRequests => 'Too many requests to third party API. Try again later';
|
||||||
String get p1nkl0bst3rinternal => 'Something happend on the p1nkl0bst3r side';
|
String get p1nkl0bst3rinternal => 'Something happend on the p1nkl0bst3r side';
|
||||||
String get p1nkl0bst3rinternalWebVersion => 'Something happend on the p1nkl0bst3r side (or on oskware_bridge, idk honestly)';
|
String get p1nkl0bst3rinternalWebVersion => 'Something happend on the p1nkl0bst3r side (or on oskware_bridge, idk honestly)';
|
||||||
String get replayAlreadySaved => 'Replay already saved';
|
String get replayAlreadySaved => 'Replay already saved';
|
||||||
String get replayExpired => 'Replay expired and not available anymore';
|
String get replayExpired => 'Replay expired and not available anymore';
|
||||||
String get replayRejected => 'Third party API blocked your IP address.\nChange IP address or reach out to szy';
|
String get replayRejected => 'Third party API blocked your IP address';
|
||||||
}
|
}
|
||||||
|
|
||||||
// Path: <root>
|
// Path: <root>
|
||||||
|
@ -774,6 +835,14 @@ class _StringsRu implements Translations {
|
||||||
@override String get compare => 'Сравнить';
|
@override String get compare => 'Сравнить';
|
||||||
@override String get tlLeaderboard => 'Рейтинговая таблица';
|
@override String get tlLeaderboard => 'Рейтинговая таблица';
|
||||||
@override String get noRecords => 'Нет записей';
|
@override String get noRecords => 'Нет записей';
|
||||||
|
@override String noOldRecords({required num n}) => (_root.$meta.cardinalResolver ?? PluralResolvers.cardinal('ru'))(n,
|
||||||
|
zero: 'Нет записей',
|
||||||
|
one: 'Всего один матч',
|
||||||
|
two: 'Всего ${n} матча',
|
||||||
|
few: 'Всего ${n} матча',
|
||||||
|
many: 'Всего ${n} матчей',
|
||||||
|
other: '${n} матчей',
|
||||||
|
);
|
||||||
@override String get noRecord => 'Нет рекорда';
|
@override String get noRecord => 'Нет рекорда';
|
||||||
@override String get botRecord => 'Ботам нельзя ставить рекорды';
|
@override String get botRecord => 'Ботам нельзя ставить рекорды';
|
||||||
@override String get anonRecord => 'Гостям нельзя ставить рекорды';
|
@override String get anonRecord => 'Гостям нельзя ставить рекорды';
|
||||||
|
@ -797,7 +866,10 @@ class _StringsRu implements Translations {
|
||||||
@override String get assignedManualy => 'Этот значок был присвоен вручную администрацией TETR.IO';
|
@override String get assignedManualy => 'Этот значок был присвоен вручную администрацией TETR.IO';
|
||||||
@override String comparingWith({required Object newDate, required Object oldDate}) => 'Данные от ${newDate} в сравнении с данными от ${oldDate}';
|
@override String comparingWith({required Object newDate, required Object oldDate}) => 'Данные от ${newDate} в сравнении с данными от ${oldDate}';
|
||||||
@override String get top => 'Топ';
|
@override String get top => 'Топ';
|
||||||
@override String get topRank => 'Топ Ранг';
|
@override String get topRank => 'Топ ранг';
|
||||||
|
@override String verdictGeneral({required Object verdict, required Object rank, required Object n}) => '${verdict} среднего ${rank} ранга на ${n}';
|
||||||
|
@override String get verdictBetter => 'Лучше';
|
||||||
|
@override String get verdictWorse => 'Хуже';
|
||||||
@override String gamesUntilRanked({required Object left}) => '${left} матчей до получения рейтинга';
|
@override String gamesUntilRanked({required Object left}) => '${left} матчей до получения рейтинга';
|
||||||
@override String get nerdStats => 'Для задротов';
|
@override String get nerdStats => 'Для задротов';
|
||||||
@override String get playersYouTrack => 'Отслеживаемые игроки';
|
@override String get playersYouTrack => 'Отслеживаемые игроки';
|
||||||
|
@ -821,8 +893,14 @@ class _StringsRu implements Translations {
|
||||||
@override String get yourIDAlertTitle => 'Ваш ник в TETR.IO';
|
@override String get yourIDAlertTitle => 'Ваш ник в TETR.IO';
|
||||||
@override String get yourIDText => 'При запуске приложения оно будет получать статистику этого игрока.';
|
@override String get yourIDText => 'При запуске приложения оно будет получать статистику этого игрока.';
|
||||||
@override String get language => 'Язык (Language)';
|
@override String get language => 'Язык (Language)';
|
||||||
|
@override String get customization => 'Кастомизация';
|
||||||
|
@override String get customizationDescription => 'Здесь только один переключатель, в планах добавить больше';
|
||||||
|
@override String get lbStats => 'Показывать статистику, основанную на рейтинговой таблице';
|
||||||
|
@override String get lbStatsDescription => 'Это повлияет на время загрузки, но позволит видеть положение в рейтинге и сравнение со средними значениями по рангу по каждой стате';
|
||||||
@override String get aboutApp => 'О приложении';
|
@override String get aboutApp => 'О приложении';
|
||||||
@override String aboutAppText({required Object appName, required Object packageName, required Object version, required Object buildNumber}) => '${appName} (${packageName}) Версия ${version} Сборка ${buildNumber}\n\nРазработал dan63047\nФормулы предоставил kerrmunism\nИсторию предоставляет p1nkl0bst3r\nВозможность скачивать повторы из TETR.IO предоставляет szy';
|
@override String aboutAppText({required Object appName, required Object packageName, required Object version, required Object buildNumber}) => '${appName} (${packageName}) Версия ${version} Сборка ${buildNumber}\n\nРазработал dan63047\nФормулы предоставил kerrmunism\nИсторию предоставляет p1nkl0bst3r\nВозможность скачивать повторы из TETR.IO предоставляет szy';
|
||||||
|
@override String get oskKagari => '"Оск Кагари" прикол';
|
||||||
|
@override String get oskKagariDescription => 'Если включено, вместо настоящего ранга оска будет рендерится :kagari:';
|
||||||
@override String stateViewTitle({required Object nickname, required Object date}) => 'Аккаунт ${nickname} ${date}';
|
@override String stateViewTitle({required Object nickname, required Object date}) => 'Аккаунт ${nickname} ${date}';
|
||||||
@override String statesViewTitle({required Object number, required Object nickname}) => '${number} состояний аккаунта ${nickname}';
|
@override String statesViewTitle({required Object number, required Object nickname}) => '${number} состояний аккаунта ${nickname}';
|
||||||
@override String matchesViewTitle({required Object nickname}) => 'Матчи аккаунта ${nickname}';
|
@override String matchesViewTitle({required Object nickname}) => 'Матчи аккаунта ${nickname}';
|
||||||
|
@ -847,10 +925,14 @@ class _StringsRu implements Translations {
|
||||||
@override String get openReplay => 'Открыть повтор в TETR.IO';
|
@override String get openReplay => 'Открыть повтор в TETR.IO';
|
||||||
@override String replaySaved({required Object path}) => 'Повтор сохранён по пути ${path}';
|
@override String replaySaved({required Object path}) => 'Повтор сохранён по пути ${path}';
|
||||||
@override String get match => 'Матч';
|
@override String get match => 'Матч';
|
||||||
|
@override String get timeWeightedmatch => 'Матч (взвешенная по времени)';
|
||||||
@override String roundNumber({required Object n}) => 'Раунд ${n}';
|
@override String roundNumber({required Object n}) => 'Раунд ${n}';
|
||||||
@override String get statsFor => 'Статистика за';
|
@override String get statsFor => 'Статистика за';
|
||||||
|
@override String get numberOfRounds => 'Количество раундов';
|
||||||
@override String get matchLength => 'Продолжительность матча';
|
@override String get matchLength => 'Продолжительность матча';
|
||||||
@override String get roundLength => 'Продолжительность раунда';
|
@override String get roundLength => 'Продолжительность раунда';
|
||||||
|
@override String get matchStats => 'Статистика матча';
|
||||||
|
@override String get timeWeightedmatchStats => 'Взвешенная по времени cтатистика матча';
|
||||||
@override String get replayIssue => 'Ошибка обработки повтора';
|
@override String get replayIssue => 'Ошибка обработки повтора';
|
||||||
@override String get matchIsTooOld => 'Информация о повторе недоступна';
|
@override String get matchIsTooOld => 'Информация о повторе недоступна';
|
||||||
@override String get winner => 'Победитель';
|
@override String get winner => 'Победитель';
|
||||||
|
@ -887,6 +969,15 @@ class _StringsRu implements Translations {
|
||||||
many: '${n} игроков',
|
many: '${n} игроков',
|
||||||
other: '${n} игроков',
|
other: '${n} игроков',
|
||||||
);
|
);
|
||||||
|
@override String games({required num n}) => (_root.$meta.cardinalResolver ?? PluralResolvers.cardinal('ru'))(n,
|
||||||
|
zero: '${n} игр',
|
||||||
|
one: '${n} игра',
|
||||||
|
two: '${n} игры',
|
||||||
|
few: '${n} игры',
|
||||||
|
many: '${n} игр',
|
||||||
|
other: '${n} игр',
|
||||||
|
);
|
||||||
|
@override String gamesPlayed({required Object games}) => '${games} сыграно';
|
||||||
@override String get chart => 'График';
|
@override String get chart => 'График';
|
||||||
@override String get entries => 'Список';
|
@override String get entries => 'Список';
|
||||||
@override String get minimums => 'Минимумы';
|
@override String get minimums => 'Минимумы';
|
||||||
|
@ -1268,8 +1359,30 @@ class _StringsNumOfGameActionsRu implements _StringsNumOfGameActionsEn {
|
||||||
// Translations
|
// Translations
|
||||||
@override String get pc => 'Все чисто';
|
@override String get pc => 'Все чисто';
|
||||||
@override String get hold => 'В запас';
|
@override String get hold => 'В запас';
|
||||||
@override String get tspinsTotal => 'T-spins всего';
|
@override String inputs({required num n}) => (_root.$meta.cardinalResolver ?? PluralResolvers.cardinal('ru'))(n,
|
||||||
@override String get lineClears => 'Линий очищено';
|
zero: '${n} нажатий клавиш',
|
||||||
|
one: '${n} нажатие на клавишу',
|
||||||
|
two: '${n} нажатия на клавишы',
|
||||||
|
few: '${n} нажатия на клавишы',
|
||||||
|
many: '${n} нажатий на клавиш',
|
||||||
|
other: '${n} нажатий на клавиш',
|
||||||
|
);
|
||||||
|
@override String tspinsTotal({required num n}) => (_root.$meta.cardinalResolver ?? PluralResolvers.cardinal('ru'))(n,
|
||||||
|
zero: '${n} T-спинов всего',
|
||||||
|
one: 'Всего ${n} T-спин',
|
||||||
|
two: '${n} T-спина всего',
|
||||||
|
few: '${n} T-спина всего',
|
||||||
|
many: '${n} T-спинов всего',
|
||||||
|
other: '${n} T-спинов всего',
|
||||||
|
);
|
||||||
|
@override String lineClears({required num n}) => (_root.$meta.cardinalResolver ?? PluralResolvers.cardinal('ru'))(n,
|
||||||
|
zero: '${n} линий очищено',
|
||||||
|
one: '${n} линия очищена',
|
||||||
|
two: '${n} линии очищено',
|
||||||
|
few: '${n} линии очищено',
|
||||||
|
many: '${n} линий очищено',
|
||||||
|
other: '${n} линий очищено',
|
||||||
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
// Path: popupActions
|
// Path: popupActions
|
||||||
|
@ -1293,21 +1406,30 @@ class _StringsErrorsRu implements _StringsErrorsEn {
|
||||||
// Translations
|
// Translations
|
||||||
@override String connection({required Object code, required Object message}) => 'Проблема с подключением: ${code} ${message}';
|
@override String connection({required Object code, required Object message}) => 'Проблема с подключением: ${code} ${message}';
|
||||||
@override String get noSuchUser => 'Нет такого пользователя';
|
@override String get noSuchUser => 'Нет такого пользователя';
|
||||||
|
@override String get noSuchUserSub => 'Либо вы ошиблись при вводе, либо аккаунта больше не существует';
|
||||||
|
@override String get discordNotAssigned => 'К данному Discord ID не привязан аккаунт';
|
||||||
|
@override String get discordNotAssignedSub => 'Убедитесь в том, что вы вставили правильный ID';
|
||||||
@override String get history => 'История данного игрока отсутствует';
|
@override String get history => 'История данного игрока отсутствует';
|
||||||
|
@override String get actionSuggestion => 'Возможно, вы хотите';
|
||||||
@override String get p1nkl0bst3rTLmatches => 'Старых матчей Тетра Лиги не было найдено';
|
@override String get p1nkl0bst3rTLmatches => 'Старых матчей Тетра Лиги не было найдено';
|
||||||
@override String get clientException => 'Нет соединения с интернетом';
|
@override String get clientException => 'Нет соединения с интернетом';
|
||||||
@override String get forbidden => 'Ваш IP адрес заблокирован.\nСмените IP адрес или свяжитесь с osk-ом';
|
@override String get forbidden => 'Ваш IP адрес заблокирован';
|
||||||
@override String get tooManyRequests => 'Слишком много запросов. Попробуйте позже';
|
@override String forbiddenSub({required Object nickname}) => 'Если у вас работает VPN или прокси, выключите его. Если это не помогло, свяжитесь с ${nickname}';
|
||||||
|
@override String get tooManyRequests => 'Слишком много запросов';
|
||||||
|
@override String get tooManyRequestsSub => 'Подождите немного и попробуйте снова';
|
||||||
@override String get internal => 'Что-то случилось на стороне tetr.io';
|
@override String get internal => 'Что-то случилось на стороне tetr.io';
|
||||||
|
@override String get internalSub => 'Скорее всего, osk уже в курсе об этом';
|
||||||
@override String get internalWebVersion => 'Что-то случилось на стороне tetr.io (или на стороне oskware_bridge, я хз если честно)';
|
@override String get internalWebVersion => 'Что-то случилось на стороне tetr.io (или на стороне oskware_bridge, я хз если честно)';
|
||||||
@override String get oskwareBridge => 'Что-то случилось с oskware_bridge. Дайте dan63047 знать';
|
@override String get internalWebVersionSub => 'Если статус страница osk-а говорит, что всё ок - свяжитесь с dan63047';
|
||||||
@override String get p1nkl0bst3rForbidden => 'Стороннее API заблокировало ваш IP адрес.\nСмените IP адрес или свяжитесь с p1nkl0bst3r-ом';
|
@override String get oskwareBridge => 'Что-то случилось с oskware_bridge';
|
||||||
|
@override String get oskwareBridgeSub => 'Дайте dan63047 знать';
|
||||||
|
@override String get p1nkl0bst3rForbidden => 'Стороннее API заблокировало ваш IP адрес';
|
||||||
@override String get p1nkl0bst3rTooManyRequests => 'Слишком много запросов к стороннему API. Попробуйте позже';
|
@override String get p1nkl0bst3rTooManyRequests => 'Слишком много запросов к стороннему API. Попробуйте позже';
|
||||||
@override String get p1nkl0bst3rinternal => 'Что-то случилось на стороне p1nkl0bst3r-а';
|
@override String get p1nkl0bst3rinternal => 'Что-то случилось на стороне p1nkl0bst3r-а';
|
||||||
@override String get p1nkl0bst3rinternalWebVersion => 'Что-то случилось на стороне p1nkl0bst3r-а (или на стороне oskware_bridge, я хз если честно)';
|
@override String get p1nkl0bst3rinternalWebVersion => 'Что-то случилось на стороне p1nkl0bst3r-а (или на стороне oskware_bridge, я хз если честно)';
|
||||||
@override String get replayAlreadySaved => 'Повтор уже сохранён';
|
@override String get replayAlreadySaved => 'Повтор уже сохранён';
|
||||||
@override String get replayExpired => 'Повтор истёк и больше недоступен';
|
@override String get replayExpired => 'Повтор истёк и больше недоступен';
|
||||||
@override String get replayRejected => 'Стороннее API заблокировало ваш IP адрес.\nСмените IP адрес или свяжитесь с szy';
|
@override String get replayRejected => 'Стороннее API заблокировало ваш IP адрес';
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Flat map(s) containing all translations.
|
/// Flat map(s) containing all translations.
|
||||||
|
@ -1359,6 +1481,14 @@ extension on Translations {
|
||||||
case 'stoppedBeingTracked': return 'Removed from tracking list!';
|
case 'stoppedBeingTracked': return 'Removed from tracking list!';
|
||||||
case 'tlLeaderboard': return 'Tetra League leaderboard';
|
case 'tlLeaderboard': return 'Tetra League leaderboard';
|
||||||
case 'noRecords': return 'No records';
|
case 'noRecords': return 'No records';
|
||||||
|
case 'noOldRecords': return ({required num n}) => (_root.$meta.cardinalResolver ?? PluralResolvers.cardinal('en'))(n,
|
||||||
|
zero: 'No records',
|
||||||
|
one: 'Only ${n} record',
|
||||||
|
two: 'Only ${n} records',
|
||||||
|
few: 'Only ${n} records',
|
||||||
|
many: 'Only ${n} records',
|
||||||
|
other: 'Only ${n} records',
|
||||||
|
);
|
||||||
case 'noRecord': return 'No record';
|
case 'noRecord': return 'No record';
|
||||||
case 'botRecord': return 'Bots are not allowed to set records';
|
case 'botRecord': return 'Bots are not allowed to set records';
|
||||||
case 'anonRecord': return 'Guests are not allowed to set records';
|
case 'anonRecord': return 'Guests are not allowed to set records';
|
||||||
|
@ -1382,7 +1512,10 @@ extension on Translations {
|
||||||
case 'supporter': return ({required Object tier}) => 'Supporter tier ${tier}';
|
case 'supporter': return ({required Object tier}) => 'Supporter tier ${tier}';
|
||||||
case 'comparingWith': return ({required Object newDate, required Object oldDate}) => 'Data from ${newDate} comparing with ${oldDate}';
|
case 'comparingWith': return ({required Object newDate, required Object oldDate}) => 'Data from ${newDate} comparing with ${oldDate}';
|
||||||
case 'top': return 'Top';
|
case 'top': return 'Top';
|
||||||
case 'topRank': return 'Top Rank';
|
case 'topRank': return 'Top rank';
|
||||||
|
case 'verdictGeneral': return ({required Object n, required Object verdict, required Object rank}) => '${n} ${verdict} than ${rank} rank average';
|
||||||
|
case 'verdictBetter': return 'better';
|
||||||
|
case 'verdictWorse': return 'worse';
|
||||||
case 'gamesUntilRanked': return ({required Object left}) => '${left} games until being ranked';
|
case 'gamesUntilRanked': return ({required Object left}) => '${left} games until being ranked';
|
||||||
case 'nerdStats': return 'Nerd Stats';
|
case 'nerdStats': return 'Nerd Stats';
|
||||||
case 'playersYouTrack': return 'Players you track';
|
case 'playersYouTrack': return 'Players you track';
|
||||||
|
@ -1406,8 +1539,14 @@ extension on Translations {
|
||||||
case 'yourIDAlertTitle': return 'Your nickname in TETR.IO';
|
case 'yourIDAlertTitle': return 'Your nickname in TETR.IO';
|
||||||
case 'yourIDText': return 'When app loads, it will retrieve data for this account';
|
case 'yourIDText': return 'When app loads, it will retrieve data for this account';
|
||||||
case 'language': return 'Language';
|
case 'language': return 'Language';
|
||||||
|
case 'customization': return 'Customization';
|
||||||
|
case 'customizationDescription': return 'There is only one toggle, planned to add more settings';
|
||||||
|
case 'lbStats': return 'Show leaderboard based stats';
|
||||||
|
case 'lbStatsDescription': return 'That will impact on loading times, but will allow you to see position on LB by stats and comparison with average values';
|
||||||
case 'aboutApp': return 'About app';
|
case 'aboutApp': return 'About app';
|
||||||
case 'aboutAppText': return ({required Object appName, required Object packageName, required Object version, required Object buildNumber}) => '${appName} (${packageName}) Version ${version} Build ${buildNumber}\n\nDeveloped by dan63047\nFormulas provided by kerrmunism\nHistory provided by p1nkl0bst3r\nTETR.IO replay grabber API by szy';
|
case 'aboutAppText': return ({required Object appName, required Object packageName, required Object version, required Object buildNumber}) => '${appName} (${packageName}) Version ${version} Build ${buildNumber}\n\nDeveloped by dan63047\nFormulas provided by kerrmunism\nHistory provided by p1nkl0bst3r\nTETR.IO replay grabber API by szy';
|
||||||
|
case 'oskKagari': return 'Osk Kagari gimmick';
|
||||||
|
case 'oskKagariDescription': return 'If on, osk\'s rank on main view will be rendered as :kagari:';
|
||||||
case 'stateViewTitle': return ({required Object nickname, required Object date}) => '${nickname} account on ${date}';
|
case 'stateViewTitle': return ({required Object nickname, required Object date}) => '${nickname} account on ${date}';
|
||||||
case 'statesViewTitle': return ({required Object number, required Object nickname}) => '${number} states of ${nickname} account';
|
case 'statesViewTitle': return ({required Object number, required Object nickname}) => '${number} states of ${nickname} account';
|
||||||
case 'matchesViewTitle': return ({required Object nickname}) => '${nickname} TL matches';
|
case 'matchesViewTitle': return ({required Object nickname}) => '${nickname} TL matches';
|
||||||
|
@ -1432,10 +1571,14 @@ extension on Translations {
|
||||||
case 'openReplay': return 'Open replay in TETR.IO';
|
case 'openReplay': return 'Open replay in TETR.IO';
|
||||||
case 'replaySaved': return ({required Object path}) => 'Replay saved to ${path}';
|
case 'replaySaved': return ({required Object path}) => 'Replay saved to ${path}';
|
||||||
case 'match': return 'Match';
|
case 'match': return 'Match';
|
||||||
|
case 'timeWeightedmatch': return 'Match (time-weighted)';
|
||||||
case 'roundNumber': return ({required Object n}) => 'Round ${n}';
|
case 'roundNumber': return ({required Object n}) => 'Round ${n}';
|
||||||
case 'statsFor': return 'Stats for';
|
case 'statsFor': return 'Stats for';
|
||||||
|
case 'numberOfRounds': return 'Number of rounds';
|
||||||
case 'matchLength': return 'Match Length';
|
case 'matchLength': return 'Match Length';
|
||||||
case 'roundLength': return 'Round Length';
|
case 'roundLength': return 'Round Length';
|
||||||
|
case 'matchStats': return 'Match stats';
|
||||||
|
case 'timeWeightedmatchStats': return 'Time-weighted match stats';
|
||||||
case 'replayIssue': return 'Can\'t process replay';
|
case 'replayIssue': return 'Can\'t process replay';
|
||||||
case 'matchIsTooOld': return 'Replay is not available';
|
case 'matchIsTooOld': return 'Replay is not available';
|
||||||
case 'winner': return 'Winner';
|
case 'winner': return 'Winner';
|
||||||
|
@ -1472,6 +1615,15 @@ extension on Translations {
|
||||||
many: '${n} players',
|
many: '${n} players',
|
||||||
other: '${n} players',
|
other: '${n} players',
|
||||||
);
|
);
|
||||||
|
case 'games': return ({required num n}) => (_root.$meta.cardinalResolver ?? PluralResolvers.cardinal('en'))(n,
|
||||||
|
zero: '${n} games',
|
||||||
|
one: '${n} game',
|
||||||
|
two: '${n} games',
|
||||||
|
few: '${n} games',
|
||||||
|
many: '${n} games',
|
||||||
|
other: '${n} games',
|
||||||
|
);
|
||||||
|
case 'gamesPlayed': return ({required Object games}) => '${games} played';
|
||||||
case 'chart': return 'Chart';
|
case 'chart': return 'Chart';
|
||||||
case 'entries': return 'Entries';
|
case 'entries': return 'Entries';
|
||||||
case 'minimums': return 'Minimums';
|
case 'minimums': return 'Minimums';
|
||||||
|
@ -1546,28 +1698,59 @@ extension on Translations {
|
||||||
case 'playerRole.anon': return 'Anonymous';
|
case 'playerRole.anon': return 'Anonymous';
|
||||||
case 'numOfGameActions.pc': return 'All Clears';
|
case 'numOfGameActions.pc': return 'All Clears';
|
||||||
case 'numOfGameActions.hold': return 'Holds';
|
case 'numOfGameActions.hold': return 'Holds';
|
||||||
case 'numOfGameActions.tspinsTotal': return 'T-spins total';
|
case 'numOfGameActions.inputs': return ({required num n}) => (_root.$meta.cardinalResolver ?? PluralResolvers.cardinal('en'))(n,
|
||||||
case 'numOfGameActions.lineClears': return 'Line clears';
|
zero: '${n} key presses',
|
||||||
|
one: '${n} key press',
|
||||||
|
two: '${n} key presses',
|
||||||
|
few: '${n} key presses',
|
||||||
|
many: '${n} key presses',
|
||||||
|
other: '${n} key presses',
|
||||||
|
);
|
||||||
|
case 'numOfGameActions.tspinsTotal': return ({required num n}) => (_root.$meta.cardinalResolver ?? PluralResolvers.cardinal('en'))(n,
|
||||||
|
zero: '${n} T-spins total',
|
||||||
|
one: '${n} T-spin total',
|
||||||
|
two: '${n} T-spins total',
|
||||||
|
few: '${n} T-spins total',
|
||||||
|
many: '${n} T-spins total',
|
||||||
|
other: '${n} T-spins total',
|
||||||
|
);
|
||||||
|
case 'numOfGameActions.lineClears': return ({required num n}) => (_root.$meta.cardinalResolver ?? PluralResolvers.cardinal('en'))(n,
|
||||||
|
zero: '${n} lines cleared',
|
||||||
|
one: '${n} line cleared',
|
||||||
|
two: '${n} lines cleared',
|
||||||
|
few: '${n} lines cleared',
|
||||||
|
many: '${n} lines cleared',
|
||||||
|
other: '${n} lines cleared',
|
||||||
|
);
|
||||||
case 'popupActions.cancel': return 'Cancel';
|
case 'popupActions.cancel': return 'Cancel';
|
||||||
case 'popupActions.submit': return 'Submit';
|
case 'popupActions.submit': return 'Submit';
|
||||||
case 'popupActions.ok': return 'OK';
|
case 'popupActions.ok': return 'OK';
|
||||||
case 'errors.connection': return ({required Object code, required Object message}) => 'Some issue with connection: ${code} ${message}';
|
case 'errors.connection': return ({required Object code, required Object message}) => 'Some issue with connection: ${code} ${message}';
|
||||||
case 'errors.noSuchUser': return 'No such user';
|
case 'errors.noSuchUser': return 'No such user';
|
||||||
|
case 'errors.noSuchUserSub': return 'Either you mistyped something, or the account no longer exists';
|
||||||
|
case 'errors.discordNotAssigned': return 'No user assigned to given Discord ID';
|
||||||
|
case 'errors.discordNotAssignedSub': return 'Make sure you provided valid ID';
|
||||||
case 'errors.history': return 'History for that player is missing';
|
case 'errors.history': return 'History for that player is missing';
|
||||||
|
case 'errors.actionSuggestion': return 'Perhaps, you want to';
|
||||||
case 'errors.p1nkl0bst3rTLmatches': return 'No Tetra League matches was found';
|
case 'errors.p1nkl0bst3rTLmatches': return 'No Tetra League matches was found';
|
||||||
case 'errors.clientException': return 'No internet connection';
|
case 'errors.clientException': return 'No internet connection';
|
||||||
case 'errors.forbidden': return 'Your IP address is blocked.\nChange IP address or reach out to osk';
|
case 'errors.forbidden': return 'Your IP address is blocked';
|
||||||
case 'errors.tooManyRequests': return 'You have been rate limited. Try again later';
|
case 'errors.forbiddenSub': return ({required Object nickname}) => 'If you are using VPN or Proxy, turn it off. If this does not help, reach out to ${nickname}';
|
||||||
|
case 'errors.tooManyRequests': return 'You have been rate limited.';
|
||||||
|
case 'errors.tooManyRequestsSub': return 'Wait a few moments and try again';
|
||||||
case 'errors.internal': return 'Something happend on the tetr.io side';
|
case 'errors.internal': return 'Something happend on the tetr.io side';
|
||||||
|
case 'errors.internalSub': return 'osk, probably, already aware about it';
|
||||||
case 'errors.internalWebVersion': return 'Something happend on the tetr.io side (or on oskware_bridge, idk honestly)';
|
case 'errors.internalWebVersion': return 'Something happend on the tetr.io side (or on oskware_bridge, idk honestly)';
|
||||||
case 'errors.oskwareBridge': return 'Something happend with oskware_bridge. Let dan63047 know';
|
case 'errors.internalWebVersionSub': return 'If osk status page says that everything is ok, let dan63047 know about this issue';
|
||||||
case 'errors.p1nkl0bst3rForbidden': return 'Third party API blocked your IP address.\nChange IP address or reach out to p1nkl0bst3r';
|
case 'errors.oskwareBridge': return 'Something happend with oskware_bridge';
|
||||||
|
case 'errors.oskwareBridgeSub': return 'Let dan63047 know';
|
||||||
|
case 'errors.p1nkl0bst3rForbidden': return 'Third party API blocked your IP address';
|
||||||
case 'errors.p1nkl0bst3rTooManyRequests': return 'Too many requests to third party API. Try again later';
|
case 'errors.p1nkl0bst3rTooManyRequests': return 'Too many requests to third party API. Try again later';
|
||||||
case 'errors.p1nkl0bst3rinternal': return 'Something happend on the p1nkl0bst3r side';
|
case 'errors.p1nkl0bst3rinternal': return 'Something happend on the p1nkl0bst3r side';
|
||||||
case 'errors.p1nkl0bst3rinternalWebVersion': return 'Something happend on the p1nkl0bst3r side (or on oskware_bridge, idk honestly)';
|
case 'errors.p1nkl0bst3rinternalWebVersion': return 'Something happend on the p1nkl0bst3r side (or on oskware_bridge, idk honestly)';
|
||||||
case 'errors.replayAlreadySaved': return 'Replay already saved';
|
case 'errors.replayAlreadySaved': return 'Replay already saved';
|
||||||
case 'errors.replayExpired': return 'Replay expired and not available anymore';
|
case 'errors.replayExpired': return 'Replay expired and not available anymore';
|
||||||
case 'errors.replayRejected': return 'Third party API blocked your IP address.\nChange IP address or reach out to szy';
|
case 'errors.replayRejected': return 'Third party API blocked your IP address';
|
||||||
case 'countries.': return 'Not selected';
|
case 'countries.': return 'Not selected';
|
||||||
case 'countries.AF': return 'Afghanistan';
|
case 'countries.AF': return 'Afghanistan';
|
||||||
case 'countries.AX': return 'Åland Islands';
|
case 'countries.AX': return 'Åland Islands';
|
||||||
|
@ -1878,6 +2061,14 @@ extension on _StringsRu {
|
||||||
case 'compare': return 'Сравнить';
|
case 'compare': return 'Сравнить';
|
||||||
case 'tlLeaderboard': return 'Рейтинговая таблица';
|
case 'tlLeaderboard': return 'Рейтинговая таблица';
|
||||||
case 'noRecords': return 'Нет записей';
|
case 'noRecords': return 'Нет записей';
|
||||||
|
case 'noOldRecords': return ({required num n}) => (_root.$meta.cardinalResolver ?? PluralResolvers.cardinal('ru'))(n,
|
||||||
|
zero: 'Нет записей',
|
||||||
|
one: 'Всего один матч',
|
||||||
|
two: 'Всего ${n} матча',
|
||||||
|
few: 'Всего ${n} матча',
|
||||||
|
many: 'Всего ${n} матчей',
|
||||||
|
other: '${n} матчей',
|
||||||
|
);
|
||||||
case 'noRecord': return 'Нет рекорда';
|
case 'noRecord': return 'Нет рекорда';
|
||||||
case 'botRecord': return 'Ботам нельзя ставить рекорды';
|
case 'botRecord': return 'Ботам нельзя ставить рекорды';
|
||||||
case 'anonRecord': return 'Гостям нельзя ставить рекорды';
|
case 'anonRecord': return 'Гостям нельзя ставить рекорды';
|
||||||
|
@ -1901,7 +2092,10 @@ extension on _StringsRu {
|
||||||
case 'assignedManualy': return 'Этот значок был присвоен вручную администрацией TETR.IO';
|
case 'assignedManualy': return 'Этот значок был присвоен вручную администрацией TETR.IO';
|
||||||
case 'comparingWith': return ({required Object newDate, required Object oldDate}) => 'Данные от ${newDate} в сравнении с данными от ${oldDate}';
|
case 'comparingWith': return ({required Object newDate, required Object oldDate}) => 'Данные от ${newDate} в сравнении с данными от ${oldDate}';
|
||||||
case 'top': return 'Топ';
|
case 'top': return 'Топ';
|
||||||
case 'topRank': return 'Топ Ранг';
|
case 'topRank': return 'Топ ранг';
|
||||||
|
case 'verdictGeneral': return ({required Object verdict, required Object rank, required Object n}) => '${verdict} среднего ${rank} ранга на ${n}';
|
||||||
|
case 'verdictBetter': return 'Лучше';
|
||||||
|
case 'verdictWorse': return 'Хуже';
|
||||||
case 'gamesUntilRanked': return ({required Object left}) => '${left} матчей до получения рейтинга';
|
case 'gamesUntilRanked': return ({required Object left}) => '${left} матчей до получения рейтинга';
|
||||||
case 'nerdStats': return 'Для задротов';
|
case 'nerdStats': return 'Для задротов';
|
||||||
case 'playersYouTrack': return 'Отслеживаемые игроки';
|
case 'playersYouTrack': return 'Отслеживаемые игроки';
|
||||||
|
@ -1925,8 +2119,14 @@ extension on _StringsRu {
|
||||||
case 'yourIDAlertTitle': return 'Ваш ник в TETR.IO';
|
case 'yourIDAlertTitle': return 'Ваш ник в TETR.IO';
|
||||||
case 'yourIDText': return 'При запуске приложения оно будет получать статистику этого игрока.';
|
case 'yourIDText': return 'При запуске приложения оно будет получать статистику этого игрока.';
|
||||||
case 'language': return 'Язык (Language)';
|
case 'language': return 'Язык (Language)';
|
||||||
|
case 'customization': return 'Кастомизация';
|
||||||
|
case 'customizationDescription': return 'Здесь только один переключатель, в планах добавить больше';
|
||||||
|
case 'lbStats': return 'Показывать статистику, основанную на рейтинговой таблице';
|
||||||
|
case 'lbStatsDescription': return 'Это повлияет на время загрузки, но позволит видеть положение в рейтинге и сравнение со средними значениями по рангу по каждой стате';
|
||||||
case 'aboutApp': return 'О приложении';
|
case 'aboutApp': return 'О приложении';
|
||||||
case 'aboutAppText': return ({required Object appName, required Object packageName, required Object version, required Object buildNumber}) => '${appName} (${packageName}) Версия ${version} Сборка ${buildNumber}\n\nРазработал dan63047\nФормулы предоставил kerrmunism\nИсторию предоставляет p1nkl0bst3r\nВозможность скачивать повторы из TETR.IO предоставляет szy';
|
case 'aboutAppText': return ({required Object appName, required Object packageName, required Object version, required Object buildNumber}) => '${appName} (${packageName}) Версия ${version} Сборка ${buildNumber}\n\nРазработал dan63047\nФормулы предоставил kerrmunism\nИсторию предоставляет p1nkl0bst3r\nВозможность скачивать повторы из TETR.IO предоставляет szy';
|
||||||
|
case 'oskKagari': return '"Оск Кагари" прикол';
|
||||||
|
case 'oskKagariDescription': return 'Если включено, вместо настоящего ранга оска будет рендерится :kagari:';
|
||||||
case 'stateViewTitle': return ({required Object nickname, required Object date}) => 'Аккаунт ${nickname} ${date}';
|
case 'stateViewTitle': return ({required Object nickname, required Object date}) => 'Аккаунт ${nickname} ${date}';
|
||||||
case 'statesViewTitle': return ({required Object number, required Object nickname}) => '${number} состояний аккаунта ${nickname}';
|
case 'statesViewTitle': return ({required Object number, required Object nickname}) => '${number} состояний аккаунта ${nickname}';
|
||||||
case 'matchesViewTitle': return ({required Object nickname}) => 'Матчи аккаунта ${nickname}';
|
case 'matchesViewTitle': return ({required Object nickname}) => 'Матчи аккаунта ${nickname}';
|
||||||
|
@ -1951,10 +2151,14 @@ extension on _StringsRu {
|
||||||
case 'openReplay': return 'Открыть повтор в TETR.IO';
|
case 'openReplay': return 'Открыть повтор в TETR.IO';
|
||||||
case 'replaySaved': return ({required Object path}) => 'Повтор сохранён по пути ${path}';
|
case 'replaySaved': return ({required Object path}) => 'Повтор сохранён по пути ${path}';
|
||||||
case 'match': return 'Матч';
|
case 'match': return 'Матч';
|
||||||
|
case 'timeWeightedmatch': return 'Матч (взвешенная по времени)';
|
||||||
case 'roundNumber': return ({required Object n}) => 'Раунд ${n}';
|
case 'roundNumber': return ({required Object n}) => 'Раунд ${n}';
|
||||||
case 'statsFor': return 'Статистика за';
|
case 'statsFor': return 'Статистика за';
|
||||||
|
case 'numberOfRounds': return 'Количество раундов';
|
||||||
case 'matchLength': return 'Продолжительность матча';
|
case 'matchLength': return 'Продолжительность матча';
|
||||||
case 'roundLength': return 'Продолжительность раунда';
|
case 'roundLength': return 'Продолжительность раунда';
|
||||||
|
case 'matchStats': return 'Статистика матча';
|
||||||
|
case 'timeWeightedmatchStats': return 'Взвешенная по времени cтатистика матча';
|
||||||
case 'replayIssue': return 'Ошибка обработки повтора';
|
case 'replayIssue': return 'Ошибка обработки повтора';
|
||||||
case 'matchIsTooOld': return 'Информация о повторе недоступна';
|
case 'matchIsTooOld': return 'Информация о повторе недоступна';
|
||||||
case 'winner': return 'Победитель';
|
case 'winner': return 'Победитель';
|
||||||
|
@ -1991,6 +2195,15 @@ extension on _StringsRu {
|
||||||
many: '${n} игроков',
|
many: '${n} игроков',
|
||||||
other: '${n} игроков',
|
other: '${n} игроков',
|
||||||
);
|
);
|
||||||
|
case 'games': return ({required num n}) => (_root.$meta.cardinalResolver ?? PluralResolvers.cardinal('ru'))(n,
|
||||||
|
zero: '${n} игр',
|
||||||
|
one: '${n} игра',
|
||||||
|
two: '${n} игры',
|
||||||
|
few: '${n} игры',
|
||||||
|
many: '${n} игр',
|
||||||
|
other: '${n} игр',
|
||||||
|
);
|
||||||
|
case 'gamesPlayed': return ({required Object games}) => '${games} сыграно';
|
||||||
case 'chart': return 'График';
|
case 'chart': return 'График';
|
||||||
case 'entries': return 'Список';
|
case 'entries': return 'Список';
|
||||||
case 'minimums': return 'Минимумы';
|
case 'minimums': return 'Минимумы';
|
||||||
|
@ -2065,28 +2278,59 @@ extension on _StringsRu {
|
||||||
case 'playerRole.anon': return 'Аноним';
|
case 'playerRole.anon': return 'Аноним';
|
||||||
case 'numOfGameActions.pc': return 'Все чисто';
|
case 'numOfGameActions.pc': return 'Все чисто';
|
||||||
case 'numOfGameActions.hold': return 'В запас';
|
case 'numOfGameActions.hold': return 'В запас';
|
||||||
case 'numOfGameActions.tspinsTotal': return 'T-spins всего';
|
case 'numOfGameActions.inputs': return ({required num n}) => (_root.$meta.cardinalResolver ?? PluralResolvers.cardinal('ru'))(n,
|
||||||
case 'numOfGameActions.lineClears': return 'Линий очищено';
|
zero: '${n} нажатий клавиш',
|
||||||
|
one: '${n} нажатие на клавишу',
|
||||||
|
two: '${n} нажатия на клавишы',
|
||||||
|
few: '${n} нажатия на клавишы',
|
||||||
|
many: '${n} нажатий на клавиш',
|
||||||
|
other: '${n} нажатий на клавиш',
|
||||||
|
);
|
||||||
|
case 'numOfGameActions.tspinsTotal': return ({required num n}) => (_root.$meta.cardinalResolver ?? PluralResolvers.cardinal('ru'))(n,
|
||||||
|
zero: '${n} T-спинов всего',
|
||||||
|
one: 'Всего ${n} T-спин',
|
||||||
|
two: '${n} T-спина всего',
|
||||||
|
few: '${n} T-спина всего',
|
||||||
|
many: '${n} T-спинов всего',
|
||||||
|
other: '${n} T-спинов всего',
|
||||||
|
);
|
||||||
|
case 'numOfGameActions.lineClears': return ({required num n}) => (_root.$meta.cardinalResolver ?? PluralResolvers.cardinal('ru'))(n,
|
||||||
|
zero: '${n} линий очищено',
|
||||||
|
one: '${n} линия очищена',
|
||||||
|
two: '${n} линии очищено',
|
||||||
|
few: '${n} линии очищено',
|
||||||
|
many: '${n} линий очищено',
|
||||||
|
other: '${n} линий очищено',
|
||||||
|
);
|
||||||
case 'popupActions.cancel': return 'Отменить';
|
case 'popupActions.cancel': return 'Отменить';
|
||||||
case 'popupActions.submit': return 'Подтвердить';
|
case 'popupActions.submit': return 'Подтвердить';
|
||||||
case 'popupActions.ok': return 'OK';
|
case 'popupActions.ok': return 'OK';
|
||||||
case 'errors.connection': return ({required Object code, required Object message}) => 'Проблема с подключением: ${code} ${message}';
|
case 'errors.connection': return ({required Object code, required Object message}) => 'Проблема с подключением: ${code} ${message}';
|
||||||
case 'errors.noSuchUser': return 'Нет такого пользователя';
|
case 'errors.noSuchUser': return 'Нет такого пользователя';
|
||||||
|
case 'errors.noSuchUserSub': return 'Либо вы ошиблись при вводе, либо аккаунта больше не существует';
|
||||||
|
case 'errors.discordNotAssigned': return 'К данному Discord ID не привязан аккаунт';
|
||||||
|
case 'errors.discordNotAssignedSub': return 'Убедитесь в том, что вы вставили правильный ID';
|
||||||
case 'errors.history': return 'История данного игрока отсутствует';
|
case 'errors.history': return 'История данного игрока отсутствует';
|
||||||
|
case 'errors.actionSuggestion': return 'Возможно, вы хотите';
|
||||||
case 'errors.p1nkl0bst3rTLmatches': return 'Старых матчей Тетра Лиги не было найдено';
|
case 'errors.p1nkl0bst3rTLmatches': return 'Старых матчей Тетра Лиги не было найдено';
|
||||||
case 'errors.clientException': return 'Нет соединения с интернетом';
|
case 'errors.clientException': return 'Нет соединения с интернетом';
|
||||||
case 'errors.forbidden': return 'Ваш IP адрес заблокирован.\nСмените IP адрес или свяжитесь с osk-ом';
|
case 'errors.forbidden': return 'Ваш IP адрес заблокирован';
|
||||||
case 'errors.tooManyRequests': return 'Слишком много запросов. Попробуйте позже';
|
case 'errors.forbiddenSub': return ({required Object nickname}) => 'Если у вас работает VPN или прокси, выключите его. Если это не помогло, свяжитесь с ${nickname}';
|
||||||
|
case 'errors.tooManyRequests': return 'Слишком много запросов';
|
||||||
|
case 'errors.tooManyRequestsSub': return 'Подождите немного и попробуйте снова';
|
||||||
case 'errors.internal': return 'Что-то случилось на стороне tetr.io';
|
case 'errors.internal': return 'Что-то случилось на стороне tetr.io';
|
||||||
|
case 'errors.internalSub': return 'Скорее всего, osk уже в курсе об этом';
|
||||||
case 'errors.internalWebVersion': return 'Что-то случилось на стороне tetr.io (или на стороне oskware_bridge, я хз если честно)';
|
case 'errors.internalWebVersion': return 'Что-то случилось на стороне tetr.io (или на стороне oskware_bridge, я хз если честно)';
|
||||||
case 'errors.oskwareBridge': return 'Что-то случилось с oskware_bridge. Дайте dan63047 знать';
|
case 'errors.internalWebVersionSub': return 'Если статус страница osk-а говорит, что всё ок - свяжитесь с dan63047';
|
||||||
case 'errors.p1nkl0bst3rForbidden': return 'Стороннее API заблокировало ваш IP адрес.\nСмените IP адрес или свяжитесь с p1nkl0bst3r-ом';
|
case 'errors.oskwareBridge': return 'Что-то случилось с oskware_bridge';
|
||||||
|
case 'errors.oskwareBridgeSub': return 'Дайте dan63047 знать';
|
||||||
|
case 'errors.p1nkl0bst3rForbidden': return 'Стороннее API заблокировало ваш IP адрес';
|
||||||
case 'errors.p1nkl0bst3rTooManyRequests': return 'Слишком много запросов к стороннему API. Попробуйте позже';
|
case 'errors.p1nkl0bst3rTooManyRequests': return 'Слишком много запросов к стороннему API. Попробуйте позже';
|
||||||
case 'errors.p1nkl0bst3rinternal': return 'Что-то случилось на стороне p1nkl0bst3r-а';
|
case 'errors.p1nkl0bst3rinternal': return 'Что-то случилось на стороне p1nkl0bst3r-а';
|
||||||
case 'errors.p1nkl0bst3rinternalWebVersion': return 'Что-то случилось на стороне p1nkl0bst3r-а (или на стороне oskware_bridge, я хз если честно)';
|
case 'errors.p1nkl0bst3rinternalWebVersion': return 'Что-то случилось на стороне p1nkl0bst3r-а (или на стороне oskware_bridge, я хз если честно)';
|
||||||
case 'errors.replayAlreadySaved': return 'Повтор уже сохранён';
|
case 'errors.replayAlreadySaved': return 'Повтор уже сохранён';
|
||||||
case 'errors.replayExpired': return 'Повтор истёк и больше недоступен';
|
case 'errors.replayExpired': return 'Повтор истёк и больше недоступен';
|
||||||
case 'errors.replayRejected': return 'Стороннее API заблокировало ваш IP адрес.\nСмените IP адрес или свяжитесь с szy';
|
case 'errors.replayRejected': return 'Стороннее API заблокировало ваш IP адрес';
|
||||||
case 'countries.': return 'Не выбрана';
|
case 'countries.': return 'Не выбрана';
|
||||||
case 'countries.AF': return 'Афганистан';
|
case 'countries.AF': return 'Афганистан';
|
||||||
case 'countries.AX': return 'Аландские острова';
|
case 'countries.AX': return 'Аландские острова';
|
||||||
|
|
|
@ -14,6 +14,8 @@ class TetrioPlayerAlreadyExist implements Exception {}
|
||||||
|
|
||||||
class TetrioPlayerNotExist implements Exception {}
|
class TetrioPlayerNotExist implements Exception {}
|
||||||
|
|
||||||
|
class TetrioDiscordNotExist implements Exception {}
|
||||||
|
|
||||||
class TetrioHistoryNotExist implements Exception {}
|
class TetrioHistoryNotExist implements Exception {}
|
||||||
|
|
||||||
class TetrioTooManyRequests implements Exception {}
|
class TetrioTooManyRequests implements Exception {}
|
||||||
|
|
|
@ -74,6 +74,7 @@ class TetrioService extends DB {
|
||||||
final Map<String, Map<String, dynamic>> _recordsCache = {};
|
final Map<String, Map<String, dynamic>> _recordsCache = {};
|
||||||
final Map<String, dynamic> _replaysCache = {}; // the only one is different: {"replayID": [replayString, replayBytes]}
|
final Map<String, dynamic> _replaysCache = {}; // the only one is different: {"replayID": [replayString, replayBytes]}
|
||||||
final Map<String, TetrioPlayersLeaderboard> _leaderboardsCache = {};
|
final Map<String, TetrioPlayersLeaderboard> _leaderboardsCache = {};
|
||||||
|
final Map<String, PlayerLeaderboardPosition> _lbPositions = {};
|
||||||
final Map<String, List<News>> _newsCache = {};
|
final Map<String, List<News>> _newsCache = {};
|
||||||
final Map<String, Map<String, double?>> _topTRcache = {};
|
final Map<String, Map<String, double?>> _topTRcache = {};
|
||||||
final Map<String, TetraLeagueAlphaStream> _tlStreamsCache = {};
|
final Map<String, TetraLeagueAlphaStream> _tlStreamsCache = {};
|
||||||
|
@ -142,6 +143,14 @@ class TetrioService extends DB {
|
||||||
db.insert(tetrioTLReplayStatsTable, {idCol: replay.id, "data": jsonEncode(replay.toJson())});
|
db.insert(tetrioTLReplayStatsTable, {idCol: replay.id, "data": jsonEncode(replay.toJson())});
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void cacheLeaderboardPositions(String userID, PlayerLeaderboardPosition positions){
|
||||||
|
_lbPositions[userID] = positions;
|
||||||
|
}
|
||||||
|
|
||||||
|
PlayerLeaderboardPosition? getCachedLeaderboardPositions(String userID){
|
||||||
|
return _lbPositions[userID];
|
||||||
|
}
|
||||||
|
|
||||||
/// Downloads replay from inoue (szy API). Requiers [replayID]. If request have
|
/// Downloads replay from inoue (szy API). Requiers [replayID]. If request have
|
||||||
/// different from 200 statusCode, it will throw an excepction. Returns list, that contains same replay
|
/// different from 200 statusCode, it will throw an excepction. Returns list, that contains same replay
|
||||||
/// as string and as binary.
|
/// as string and as binary.
|
||||||
|
@ -406,12 +415,12 @@ class TetrioService extends DB {
|
||||||
// parsing data into TetraLeagueAlphaRecord objects
|
// parsing data into TetraLeagueAlphaRecord objects
|
||||||
for (var entry in csv){
|
for (var entry in csv){
|
||||||
TetraLeagueAlphaRecord match = TetraLeagueAlphaRecord(
|
TetraLeagueAlphaRecord match = TetraLeagueAlphaRecord(
|
||||||
replayId: entry[0],
|
replayId: entry[0].toString(),
|
||||||
ownId: entry[0], // i gonna disting p1nkl0bst3r entries with it
|
ownId: entry[0].toString(), // i gonna disting p1nkl0bst3r entries with it
|
||||||
timestamp: DateTime.parse(entry[1]),
|
timestamp: DateTime.parse(entry[1]),
|
||||||
endContext: [
|
endContext: [
|
||||||
EndContextMulti(
|
EndContextMulti(
|
||||||
userId: entry[2],
|
userId: entry[2].toString(),
|
||||||
username: entry[3].toString(),
|
username: entry[3].toString(),
|
||||||
naturalOrder: 0,
|
naturalOrder: 0,
|
||||||
inputs: -1,
|
inputs: -1,
|
||||||
|
@ -428,7 +437,7 @@ class TetrioService extends DB {
|
||||||
success: true
|
success: true
|
||||||
),
|
),
|
||||||
EndContextMulti(
|
EndContextMulti(
|
||||||
userId: entry[8],
|
userId: entry[8].toString(),
|
||||||
username: entry[9].toString(),
|
username: entry[9].toString(),
|
||||||
naturalOrder: 1,
|
naturalOrder: 1,
|
||||||
inputs: -1,
|
inputs: -1,
|
||||||
|
@ -504,6 +513,7 @@ class TetrioService extends DB {
|
||||||
|
|
||||||
switch (response.statusCode) {
|
switch (response.statusCode) {
|
||||||
case 200:
|
case 200:
|
||||||
|
_lbPositions.clear();
|
||||||
var rawJson = jsonDecode(response.body);
|
var rawJson = jsonDecode(response.body);
|
||||||
if (rawJson['success']) { // if api confirmed that everything ok
|
if (rawJson['success']) { // if api confirmed that everything ok
|
||||||
TetrioPlayersLeaderboard leaderboard = TetrioPlayersLeaderboard.fromJson(rawJson['data']['users'], "league", DateTime.fromMillisecondsSinceEpoch(rawJson['cache']['cached_at']));
|
TetrioPlayersLeaderboard leaderboard = TetrioPlayersLeaderboard.fromJson(rawJson['data']['users'], "league", DateTime.fromMillisecondsSinceEpoch(rawJson['cache']['cached_at']));
|
||||||
|
@ -535,6 +545,12 @@ class TetrioService extends DB {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
TetrioPlayersLeaderboard? getCachedLeaderboard(){
|
||||||
|
return _leaderboardsCache.entries.firstOrNull?.value;
|
||||||
|
// That function will break if i decide to recive other leaderboards
|
||||||
|
// TODO: Think about better solution
|
||||||
|
}
|
||||||
|
|
||||||
/// Retrieves and returns 100 latest news entries from Tetra Channel api for given [userID]. Throws an exception if fails to retrieve.
|
/// Retrieves and returns 100 latest news entries from Tetra Channel api for given [userID]. Throws an exception if fails to retrieve.
|
||||||
Future<List<News>> fetchNews(String userID) async{
|
Future<List<News>> fetchNews(String userID) async{
|
||||||
try{
|
try{
|
||||||
|
@ -712,6 +728,14 @@ class TetrioService extends DB {
|
||||||
return matches;
|
return matches;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// Gets and returns an amount of stored Tetra League mathes between [ourPlayerID] and [enemyPlayerID].
|
||||||
|
Future<int> getNumberOfTLMatchesBetweenPlayers(String ourPlayerID, String enemyPlayerID) async {
|
||||||
|
await ensureDbIsOpen();
|
||||||
|
final db = getDatabaseOrThrow();
|
||||||
|
final results = await db.rawQuery("SELECT COUNT(*) from tetrioAlphaLeagueMathces WHERE (player1id = $ourPlayerID AND player2id = $enemyPlayerID) OR (player1id = $enemyPlayerID AND player2id = $ourPlayerID)");
|
||||||
|
return results.first.values.first as int;
|
||||||
|
}
|
||||||
|
|
||||||
/// Deletes match and stats of that match with given [matchID] from local DB. Throws an exception if fails.
|
/// Deletes match and stats of that match with given [matchID] from local DB. Throws an exception if fails.
|
||||||
Future<void> deleteTLMatch(String matchID) async {
|
Future<void> deleteTLMatch(String matchID) async {
|
||||||
await ensureDbIsOpen();
|
await ensureDbIsOpen();
|
||||||
|
@ -950,7 +974,7 @@ class TetrioService extends DB {
|
||||||
user = json['data']['user']['_id'];
|
user = json['data']['user']['_id'];
|
||||||
} else { // fail - throw an exception
|
} else { // fail - throw an exception
|
||||||
developer.log("fetchPlayer User dosen't exist", name: "services/tetrio_crud", error: response.body);
|
developer.log("fetchPlayer User dosen't exist", name: "services/tetrio_crud", error: response.body);
|
||||||
throw TetrioPlayerNotExist();
|
throw TetrioDiscordNotExist();
|
||||||
}
|
}
|
||||||
break;
|
break;
|
||||||
// more exceptions to god of exceptions
|
// more exceptions to god of exceptions
|
||||||
|
|
|
@ -0,0 +1,10 @@
|
||||||
|
import 'package:flutter/material.dart';
|
||||||
|
|
||||||
|
Color getColorOfRank(int rank){
|
||||||
|
if (rank == 1) return Colors.yellowAccent;
|
||||||
|
if (rank == 2) return Colors.blueGrey;
|
||||||
|
if (rank == 3) return Colors.brown[400]!;
|
||||||
|
if (rank <= 9) return Colors.blueAccent;
|
||||||
|
if (rank <= 99) return Colors.greenAccent;
|
||||||
|
return Colors.grey;
|
||||||
|
}
|
|
@ -0,0 +1,11 @@
|
||||||
|
import 'package:intl/intl.dart';
|
||||||
|
import 'package:tetra_stats/gen/strings.g.dart';
|
||||||
|
|
||||||
|
final NumberFormat comparef = NumberFormat("+#,###.###;-#,###.###")..maximumFractionDigits = 3;
|
||||||
|
final NumberFormat intf = NumberFormat.decimalPatternDigits(locale: LocaleSettings.currentLocale.languageCode, decimalDigits: 0);
|
||||||
|
final NumberFormat f4 = NumberFormat.decimalPatternDigits(locale: LocaleSettings.currentLocale.languageCode, decimalDigits: 4);
|
||||||
|
final NumberFormat f3 = NumberFormat.decimalPatternDigits(locale: LocaleSettings.currentLocale.languageCode, decimalDigits: 3);
|
||||||
|
final NumberFormat f2 = NumberFormat.decimalPatternDigits(locale: LocaleSettings.currentLocale.languageCode, decimalDigits: 2);
|
||||||
|
final NumberFormat f2l = NumberFormat.decimalPatternDigits(locale: LocaleSettings.currentLocale.languageCode, decimalDigits: 2)..minimumFractionDigits = 0;
|
||||||
|
final NumberFormat f0 = NumberFormat.decimalPattern(LocaleSettings.currentLocale.languageCode);
|
||||||
|
final NumberFormat percentage = NumberFormat.percentPattern(LocaleSettings.currentLocale.languageCode)..maximumFractionDigits = 2;
|
|
@ -13,7 +13,6 @@ double? vs;
|
||||||
NerdStats? nerdStats;
|
NerdStats? nerdStats;
|
||||||
EstTr? estTr;
|
EstTr? estTr;
|
||||||
Playstyle? playstyle;
|
Playstyle? playstyle;
|
||||||
final NumberFormat f2 = NumberFormat.decimalPatternDigits(locale: LocaleSettings.currentLocale.languageCode, decimalDigits: 2);
|
|
||||||
late String oldWindowTitle;
|
late String oldWindowTitle;
|
||||||
|
|
||||||
class CalcView extends StatefulWidget {
|
class CalcView extends StatefulWidget {
|
||||||
|
@ -67,13 +66,12 @@ class CalcState extends State<CalcView> {
|
||||||
title: Text(t.statsCalc),
|
title: Text(t.statsCalc),
|
||||||
),
|
),
|
||||||
backgroundColor: Colors.black,
|
backgroundColor: Colors.black,
|
||||||
body: SafeArea(
|
body: SingleChildScrollView(
|
||||||
child: NestedScrollView(
|
child: Center(
|
||||||
controller: _scrollController,
|
child: Container(
|
||||||
headerSliverBuilder: (context, value) {
|
constraints: const BoxConstraints(maxWidth: 768),
|
||||||
return [
|
child: Column(children: [
|
||||||
SliverToBoxAdapter(
|
Padding(
|
||||||
child: Padding(
|
|
||||||
padding: const EdgeInsets.fromLTRB(14, 16, 16, 32),
|
padding: const EdgeInsets.fromLTRB(14, 16, 16, 32),
|
||||||
child: Row(
|
child: Row(
|
||||||
children: [
|
children: [
|
||||||
|
@ -111,16 +109,9 @@ class CalcState extends State<CalcView> {
|
||||||
],
|
],
|
||||||
),
|
),
|
||||||
),
|
),
|
||||||
),
|
Divider(),
|
||||||
const SliverToBoxAdapter(
|
if (nerdStats == null) Text(t.calcViewNoValues)
|
||||||
child: Divider(),
|
else Column(children: [
|
||||||
)
|
|
||||||
];
|
|
||||||
},
|
|
||||||
body: nerdStats == null
|
|
||||||
? Text(t.calcViewNoValues)
|
|
||||||
: ListView(
|
|
||||||
children: [
|
|
||||||
_ListEntry(value: nerdStats!.app, label: t.statCellNum.app.replaceAll(RegExp(r'\n'), " "), fractionDigits: 3),
|
_ListEntry(value: nerdStats!.app, label: t.statCellNum.app.replaceAll(RegExp(r'\n'), " "), fractionDigits: 3),
|
||||||
_ListEntry(value: nerdStats!.vsapm, label: "VS/APM", fractionDigits: 3),
|
_ListEntry(value: nerdStats!.vsapm, label: "VS/APM", fractionDigits: 3),
|
||||||
_ListEntry(value: nerdStats!.dss, label: t.statCellNum.dss.replaceAll(RegExp(r'\n'), " "), fractionDigits: 3),
|
_ListEntry(value: nerdStats!.dss, label: t.statCellNum.dss.replaceAll(RegExp(r'\n'), " "), fractionDigits: 3),
|
||||||
|
@ -131,9 +122,11 @@ class CalcState extends State<CalcView> {
|
||||||
_ListEntry(value: nerdStats!.nyaapp, label: t.statCellNum.nyaapp.replaceAll(RegExp(r'\n'), " "), fractionDigits: 3),
|
_ListEntry(value: nerdStats!.nyaapp, label: t.statCellNum.nyaapp.replaceAll(RegExp(r'\n'), " "), fractionDigits: 3),
|
||||||
_ListEntry(value: nerdStats!.area, label: t.statCellNum.area.replaceAll(RegExp(r'\n'), " "), fractionDigits: 3),
|
_ListEntry(value: nerdStats!.area, label: t.statCellNum.area.replaceAll(RegExp(r'\n'), " "), fractionDigits: 3),
|
||||||
_ListEntry(value: estTr!.esttr, label: t.statCellNum.estOfTR, fractionDigits: 3),
|
_ListEntry(value: estTr!.esttr, label: t.statCellNum.estOfTR, fractionDigits: 3),
|
||||||
Graphs(apm!, pps!, vs!, nerdStats!, playstyle!),
|
Graphs(apm!, pps!, vs!, nerdStats!, playstyle!)
|
||||||
],
|
],)
|
||||||
)),
|
],),
|
||||||
|
),
|
||||||
|
),
|
||||||
),
|
),
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
|
@ -255,13 +255,14 @@ class CompareState extends State<CompareView> {
|
||||||
return Scaffold(
|
return Scaffold(
|
||||||
appBar: AppBar(title: Text("$titleGreenSide ${t.vs} $titleRedSide")),
|
appBar: AppBar(title: Text("$titleGreenSide ${t.vs} $titleRedSide")),
|
||||||
backgroundColor: Colors.black,
|
backgroundColor: Colors.black,
|
||||||
body: SafeArea(
|
body: SingleChildScrollView(
|
||||||
child: NestedScrollView(
|
|
||||||
controller: _scrollController,
|
controller: _scrollController,
|
||||||
headerSliverBuilder: (context, value) {
|
physics: AlwaysScrollableScrollPhysics(),
|
||||||
return [
|
child: Center(
|
||||||
SliverToBoxAdapter(
|
child: Container(
|
||||||
child: Padding(
|
constraints: const BoxConstraints(maxWidth: 768),
|
||||||
|
child: Column(children: [
|
||||||
|
Padding(
|
||||||
padding: const EdgeInsets.fromLTRB(16, 16, 16, 32),
|
padding: const EdgeInsets.fromLTRB(16, 16, 16, 32),
|
||||||
child: Row(
|
child: Row(
|
||||||
mainAxisAlignment: MainAxisAlignment.spaceBetween,
|
mainAxisAlignment: MainAxisAlignment.spaceBetween,
|
||||||
|
@ -316,18 +317,10 @@ class CompareState extends State<CompareView> {
|
||||||
],
|
],
|
||||||
),
|
),
|
||||||
),
|
),
|
||||||
),
|
Divider(),
|
||||||
const SliverToBoxAdapter(
|
if (!listEquals(theGreenSide, [null, null, null]) && !listEquals(theRedSide, [null, null, null])) Column(
|
||||||
child: Divider(),
|
children: [
|
||||||
)
|
if (theGreenSide[0] != null && theRedSide[0] != null && theGreenSide[0]!.role != "banned" && theRedSide[0]!.role != "banned")
|
||||||
];
|
|
||||||
},
|
|
||||||
body: ListView(
|
|
||||||
children: !listEquals(theGreenSide, [null, null, null]) && !listEquals(theRedSide, [null, null, null])? [
|
|
||||||
if (theGreenSide[0] != null &&
|
|
||||||
theRedSide[0] != null &&
|
|
||||||
theGreenSide[0]!.role != "banned" &&
|
|
||||||
theRedSide[0]!.role != "banned")
|
|
||||||
Column(
|
Column(
|
||||||
children: [
|
children: [
|
||||||
CompareRegTimeThingy(
|
CompareRegTimeThingy(
|
||||||
|
@ -341,8 +334,7 @@ class CompareState extends State<CompareView> {
|
||||||
higherIsBetter: true,
|
higherIsBetter: true,
|
||||||
fractionDigits: 2,
|
fractionDigits: 2,
|
||||||
),
|
),
|
||||||
if (!theGreenSide[0].gameTime.isNegative &&
|
if (!theGreenSide[0].gameTime.isNegative && !theRedSide[0].gameTime.isNegative)
|
||||||
!theRedSide[0].gameTime.isNegative)
|
|
||||||
CompareThingy(
|
CompareThingy(
|
||||||
greenSide: theGreenSide[0].gameTime.inMicroseconds /
|
greenSide: theGreenSide[0].gameTime.inMicroseconds /
|
||||||
1000000 /
|
1000000 /
|
||||||
|
@ -356,16 +348,14 @@ class CompareState extends State<CompareView> {
|
||||||
higherIsBetter: true,
|
higherIsBetter: true,
|
||||||
fractionDigits: 2,
|
fractionDigits: 2,
|
||||||
),
|
),
|
||||||
if (theGreenSide[0].gamesPlayed >= 0 &&
|
if (theGreenSide[0].gamesPlayed >= 0 && theRedSide[0].gamesPlayed >= 0)
|
||||||
theRedSide[0].gamesPlayed >= 0)
|
|
||||||
CompareThingy(
|
CompareThingy(
|
||||||
label: t.statCellNum.onlineGames.replaceAll(RegExp(r'\n'), " "),
|
label: t.statCellNum.onlineGames.replaceAll(RegExp(r'\n'), " "),
|
||||||
greenSide: theGreenSide[0].gamesPlayed,
|
greenSide: theGreenSide[0].gamesPlayed,
|
||||||
redSide: theRedSide[0].gamesPlayed,
|
redSide: theRedSide[0].gamesPlayed,
|
||||||
higherIsBetter: true,
|
higherIsBetter: true,
|
||||||
),
|
),
|
||||||
if (theGreenSide[0].gamesWon >= 0 &&
|
if (theGreenSide[0].gamesWon >= 0 && theRedSide[0].gamesWon >= 0)
|
||||||
theRedSide[0].gamesWon >= 0)
|
|
||||||
CompareThingy(
|
CompareThingy(
|
||||||
label: t.statCellNum.gamesWon.replaceAll(RegExp(r'\n'), " "),
|
label: t.statCellNum.gamesWon.replaceAll(RegExp(r'\n'), " "),
|
||||||
greenSide: theGreenSide[0].gamesWon,
|
greenSide: theGreenSide[0].gamesWon,
|
||||||
|
@ -381,17 +371,14 @@ class CompareState extends State<CompareView> {
|
||||||
const Divider(),
|
const Divider(),
|
||||||
],
|
],
|
||||||
),
|
),
|
||||||
if (theGreenSide[0] != null &&
|
if (theGreenSide[0] != null && theRedSide[0] != null && (theGreenSide[0]!.role == "banned" || theRedSide[0]!.role == "banned"))
|
||||||
theRedSide[0] != null &&
|
|
||||||
(theGreenSide[0]!.role == "banned" ||
|
|
||||||
theRedSide[0]!.role == "banned"))
|
|
||||||
CompareBoolThingy(
|
CompareBoolThingy(
|
||||||
greenSide: theGreenSide[0].role == "banned",
|
greenSide: theGreenSide[0].role == "banned",
|
||||||
redSide: theRedSide[0].role == "banned",
|
redSide: theRedSide[0].role == "banned",
|
||||||
label: t.normalBanned,
|
label: t.normalBanned,
|
||||||
trueIsBetter: false),
|
trueIsBetter: false
|
||||||
(theGreenSide[2].gamesPlayed > 0 || greenSideMode == Mode.stats) &&
|
),
|
||||||
(theRedSide[2].gamesPlayed > 0 || redSideMode == Mode.stats)
|
(theGreenSide[2].gamesPlayed > 0 || greenSideMode == Mode.stats) && (theRedSide[2].gamesPlayed > 0 || redSideMode == Mode.stats)
|
||||||
? Column(
|
? Column(
|
||||||
children: [
|
children: [
|
||||||
Padding(
|
Padding(
|
||||||
|
@ -688,11 +675,15 @@ class CompareState extends State<CompareView> {
|
||||||
),
|
),
|
||||||
],
|
],
|
||||||
)
|
)
|
||||||
] : [Padding(
|
],
|
||||||
|
)
|
||||||
|
else Padding(
|
||||||
padding: const EdgeInsets.all(8.0),
|
padding: const EdgeInsets.all(8.0),
|
||||||
child: Text(t.compareViewNoValues(avgR: "\$avgR"), textAlign: TextAlign.center),
|
child: Text(t.compareViewNoValues(avgR: "\$avgR"), textAlign: TextAlign.center),
|
||||||
)], // This is so fucked up holy shit
|
|
||||||
)
|
)
|
||||||
|
],
|
||||||
|
),
|
||||||
|
),
|
||||||
),
|
),
|
||||||
),
|
),
|
||||||
);
|
);
|
||||||
|
@ -786,6 +777,8 @@ class PlayerSelector extends StatelessWidget {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
const TextStyle verdictStyle = TextStyle(fontSize: 14, fontFamily: "Eurostile Round Condensed", color: Colors.grey, height: 1.1);
|
||||||
|
|
||||||
class CompareThingy extends StatelessWidget {
|
class CompareThingy extends StatelessWidget {
|
||||||
final num greenSide;
|
final num greenSide;
|
||||||
final num redSide;
|
final num redSide;
|
||||||
|
@ -868,7 +861,7 @@ class CompareThingy extends StatelessWidget {
|
||||||
Text(
|
Text(
|
||||||
verdict(greenSide, redSide,
|
verdict(greenSide, redSide,
|
||||||
fractionDigits != null ? fractionDigits! + 2 : 0),
|
fractionDigits != null ? fractionDigits! + 2 : 0),
|
||||||
style: const TextStyle(fontSize: 16),
|
style: verdictStyle,
|
||||||
textAlign: TextAlign.center,
|
textAlign: TextAlign.center,
|
||||||
)
|
)
|
||||||
],
|
],
|
||||||
|
@ -981,11 +974,7 @@ class CompareBoolThingy extends StatelessWidget {
|
||||||
style: const TextStyle(fontSize: 22),
|
style: const TextStyle(fontSize: 22),
|
||||||
textAlign: TextAlign.center,
|
textAlign: TextAlign.center,
|
||||||
),
|
),
|
||||||
const Text(
|
const Text("---", style: verdictStyle, textAlign: TextAlign.center)
|
||||||
"---",
|
|
||||||
style: TextStyle(fontSize: 16),
|
|
||||||
textAlign: TextAlign.center,
|
|
||||||
)
|
|
||||||
],
|
],
|
||||||
),
|
),
|
||||||
Expanded(
|
Expanded(
|
||||||
|
@ -1085,10 +1074,7 @@ class CompareDurationThingy extends StatelessWidget {
|
||||||
textAlign: TextAlign.center,
|
textAlign: TextAlign.center,
|
||||||
),
|
),
|
||||||
Text(
|
Text(
|
||||||
verdict(greenSide, redSide).toString(),
|
verdict(greenSide, redSide).toString(), style: verdictStyle, textAlign: TextAlign.center)
|
||||||
style: const TextStyle(fontSize: 16),
|
|
||||||
textAlign: TextAlign.center,
|
|
||||||
)
|
|
||||||
],
|
],
|
||||||
),
|
),
|
||||||
Expanded(
|
Expanded(
|
||||||
|
@ -1176,11 +1162,7 @@ class CompareRegTimeThingy extends StatelessWidget {
|
||||||
style: const TextStyle(fontSize: 22),
|
style: const TextStyle(fontSize: 22),
|
||||||
textAlign: TextAlign.center,
|
textAlign: TextAlign.center,
|
||||||
),
|
),
|
||||||
Text(
|
Text(verdict(greenSide, redSide), style: verdictStyle, textAlign: TextAlign.center)
|
||||||
verdict(greenSide, redSide),
|
|
||||||
style: const TextStyle(fontSize: 16),
|
|
||||||
textAlign: TextAlign.center,
|
|
||||||
)
|
|
||||||
],
|
],
|
||||||
),
|
),
|
||||||
Expanded(
|
Expanded(
|
||||||
|
|
|
@ -20,6 +20,7 @@ class CustomizationView extends StatefulWidget {
|
||||||
|
|
||||||
class CustomizationState extends State<CustomizationView> {
|
class CustomizationState extends State<CustomizationView> {
|
||||||
late SharedPreferences prefs;
|
late SharedPreferences prefs;
|
||||||
|
late bool oskKagariGimmick;
|
||||||
|
|
||||||
void changeColor(Color color) {
|
void changeColor(Color color) {
|
||||||
setState(() => pickerColor = color);
|
setState(() => pickerColor = color);
|
||||||
|
@ -31,7 +32,7 @@ class CustomizationState extends State<CustomizationView> {
|
||||||
windowManager.getTitle().then((value) => oldWindowTitle = value);
|
windowManager.getTitle().then((value) => oldWindowTitle = value);
|
||||||
windowManager.setTitle("Tetra Stats: ${t.settings}");
|
windowManager.setTitle("Tetra Stats: ${t.settings}");
|
||||||
}
|
}
|
||||||
_getPreferences();
|
_getPreferences().then((value) => setState((){}));
|
||||||
super.initState();
|
super.initState();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -43,6 +44,11 @@ class CustomizationState extends State<CustomizationView> {
|
||||||
|
|
||||||
Future<void> _getPreferences() async {
|
Future<void> _getPreferences() async {
|
||||||
prefs = await SharedPreferences.getInstance();
|
prefs = await SharedPreferences.getInstance();
|
||||||
|
if (prefs.getBool("oskKagariGimmick") != null) {
|
||||||
|
oskKagariGimmick = prefs.getBool("oskKagariGimmick")!;
|
||||||
|
} else {
|
||||||
|
oskKagariGimmick = true;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
ThemeData getTheme(BuildContext context, Color color){
|
ThemeData getTheme(BuildContext context, Color color){
|
||||||
|
@ -66,59 +72,48 @@ class CustomizationState extends State<CustomizationView> {
|
||||||
body: SafeArea(
|
body: SafeArea(
|
||||||
child: ListView(
|
child: ListView(
|
||||||
children: [
|
children: [
|
||||||
ListTile(
|
// ListTile(
|
||||||
title: const Text("Accent Color"),
|
// title: const Text("Accent color"),
|
||||||
trailing: ColorIndicator(HSVColor.fromColor(Theme.of(context).colorScheme.primary)),
|
// trailing: ColorIndicator(HSVColor.fromColor(Theme.of(context).colorScheme.primary)),
|
||||||
onTap: () {
|
// onTap: () {
|
||||||
showDialog(
|
// showDialog(
|
||||||
context: context,
|
// context: context,
|
||||||
builder: (BuildContext context) => AlertDialog(
|
// builder: (BuildContext context) => AlertDialog(
|
||||||
title: const Text('Pick a color!'),
|
// title: const Text('Pick an accent color'),
|
||||||
content: SingleChildScrollView(
|
// content: SingleChildScrollView(
|
||||||
child: ColorPicker(
|
// child: ColorPicker(
|
||||||
pickerColor: pickerColor,
|
|
||||||
onColorChanged: changeColor,
|
|
||||||
),
|
|
||||||
// Use Material color picker:
|
|
||||||
//
|
|
||||||
// child: MaterialPicker(
|
|
||||||
// pickerColor: pickerColor,
|
// pickerColor: pickerColor,
|
||||||
// onColorChanged: changeColor,
|
// onColorChanged: changeColor,
|
||||||
// showLabel: true, // only on portrait mode
|
|
||||||
// ),
|
// ),
|
||||||
//
|
|
||||||
// Use Block color picker:
|
|
||||||
//
|
|
||||||
// child: BlockPicker(
|
|
||||||
// pickerColor: currentColor,
|
|
||||||
// onColorChanged: changeColor,
|
|
||||||
// ),
|
// ),
|
||||||
//
|
// actions: <Widget>[
|
||||||
// child: MultipleChoiceBlockPicker(
|
// ElevatedButton(
|
||||||
// pickerColors: currentColors,
|
// child: const Text('Set'),
|
||||||
// onColorsChanged: changeColors,
|
// onPressed: () {
|
||||||
|
// setState(() {
|
||||||
|
// setAccentColor(pickerColor);
|
||||||
|
// });
|
||||||
|
// Navigator.of(context).pop();
|
||||||
|
// },
|
||||||
// ),
|
// ),
|
||||||
),
|
// ]));
|
||||||
actions: <Widget>[
|
// }),
|
||||||
ElevatedButton(
|
// const ListTile(
|
||||||
child: const Text('Got it'),
|
// title: Text("Font"),
|
||||||
onPressed: () {
|
// subtitle: Text("Not implemented"),
|
||||||
|
// ),
|
||||||
|
// const ListTile(
|
||||||
|
// title: Text("Stats Table in TL mathes list"),
|
||||||
|
// subtitle: Text("Not implemented"),
|
||||||
|
// ),
|
||||||
|
ListTile(title: Text(t.oskKagari),
|
||||||
|
subtitle: Text(t.oskKagariDescription),
|
||||||
|
trailing: Switch(value: oskKagariGimmick, onChanged: (bool value){
|
||||||
|
prefs.setBool("oskKagariGimmick", value);
|
||||||
setState(() {
|
setState(() {
|
||||||
setAccentColor(pickerColor);
|
oskKagariGimmick = value;
|
||||||
});
|
});
|
||||||
Navigator.of(context).pop();
|
}),)
|
||||||
},
|
|
||||||
),
|
|
||||||
]));
|
|
||||||
}),
|
|
||||||
const ListTile(
|
|
||||||
title: Text("Font"),
|
|
||||||
subtitle: Text("Not implemented"),
|
|
||||||
),
|
|
||||||
const ListTile(
|
|
||||||
title: Text("Stats Table in TL mathes list"),
|
|
||||||
subtitle: Text("Not implemented"),
|
|
||||||
),
|
|
||||||
],
|
],
|
||||||
)),
|
)),
|
||||||
);
|
);
|
||||||
|
|
|
@ -8,7 +8,6 @@ import 'package:tetra_stats/views/tl_match_view.dart';
|
||||||
import 'package:window_manager/window_manager.dart';
|
import 'package:window_manager/window_manager.dart';
|
||||||
|
|
||||||
final TetrioService teto = TetrioService();
|
final TetrioService teto = TetrioService();
|
||||||
final NumberFormat f2 = NumberFormat.decimalPatternDigits(locale: LocaleSettings.currentLocale.languageCode, decimalDigits: 2);
|
|
||||||
late String oldWindowTitle;
|
late String oldWindowTitle;
|
||||||
|
|
||||||
class MatchesView extends StatefulWidget {
|
class MatchesView extends StatefulWidget {
|
||||||
|
|
|
@ -16,6 +16,7 @@ Stats _chartsX = Stats.tr;
|
||||||
Stats _chartsY = Stats.apm;
|
Stats _chartsY = Stats.apm;
|
||||||
List<DropdownMenuItem> _itemStats = [for (MapEntry e in chartsShortTitles.entries) DropdownMenuItem(value: e.key, child: Text(e.value))];
|
List<DropdownMenuItem> _itemStats = [for (MapEntry e in chartsShortTitles.entries) DropdownMenuItem(value: e.key, child: Text(e.value))];
|
||||||
Stats _sortBy = Stats.tr;
|
Stats _sortBy = Stats.tr;
|
||||||
|
late List<TetrioPlayerFromLeaderboard> they;
|
||||||
bool _reversed = false;
|
bool _reversed = false;
|
||||||
List<DropdownMenuItem> _itemCountries = [for (MapEntry e in t.countries.entries) DropdownMenuItem(value: e.key, child: Text(e.value))];
|
List<DropdownMenuItem> _itemCountries = [for (MapEntry e in t.countries.entries) DropdownMenuItem(value: e.key, child: Text(e.value))];
|
||||||
String _country = "";
|
String _country = "";
|
||||||
|
@ -61,6 +62,7 @@ class RankState extends State<RankView> with SingleTickerProviderStateMixin {
|
||||||
}
|
}
|
||||||
super.initState();
|
super.initState();
|
||||||
previousAxisTitles = _chartsX.toString()+_chartsY.toString();
|
previousAxisTitles = _chartsX.toString()+_chartsY.toString();
|
||||||
|
they = TetrioPlayersLeaderboard("lol", []).getStatRanking(widget.rank[1]["entries"]!, _sortBy, reversed: _reversed, country: _country);
|
||||||
recalculateBoundaries();
|
recalculateBoundaries();
|
||||||
resetScale();
|
resetScale();
|
||||||
}
|
}
|
||||||
|
@ -73,7 +75,7 @@ class RankState extends State<RankView> with SingleTickerProviderStateMixin {
|
||||||
} else {
|
} else {
|
||||||
return element;
|
return element;
|
||||||
}
|
}
|
||||||
}).getStatByEnum(_chartsX) as double;
|
}).getStatByEnum(_chartsX).toDouble();
|
||||||
actualMaxX = (widget.rank[1]["entries"] as List<TetrioPlayerFromLeaderboard>).reduce((value, element) {
|
actualMaxX = (widget.rank[1]["entries"] as List<TetrioPlayerFromLeaderboard>).reduce((value, element) {
|
||||||
num n = max(value.getStatByEnum(_chartsX), element.getStatByEnum(_chartsX));
|
num n = max(value.getStatByEnum(_chartsX), element.getStatByEnum(_chartsX));
|
||||||
if (value.getStatByEnum(_chartsX) == n) {
|
if (value.getStatByEnum(_chartsX) == n) {
|
||||||
|
@ -81,7 +83,7 @@ class RankState extends State<RankView> with SingleTickerProviderStateMixin {
|
||||||
} else {
|
} else {
|
||||||
return element;
|
return element;
|
||||||
}
|
}
|
||||||
}).getStatByEnum(_chartsX) as double;
|
}).getStatByEnum(_chartsX).toDouble();
|
||||||
actualMinY = (widget.rank[1]["entries"] as List<TetrioPlayerFromLeaderboard>).reduce((value, element) {
|
actualMinY = (widget.rank[1]["entries"] as List<TetrioPlayerFromLeaderboard>).reduce((value, element) {
|
||||||
num n = min(value.getStatByEnum(_chartsY), element.getStatByEnum(_chartsY));
|
num n = min(value.getStatByEnum(_chartsY), element.getStatByEnum(_chartsY));
|
||||||
if (value.getStatByEnum(_chartsY) == n) {
|
if (value.getStatByEnum(_chartsY) == n) {
|
||||||
|
@ -89,7 +91,7 @@ class RankState extends State<RankView> with SingleTickerProviderStateMixin {
|
||||||
} else {
|
} else {
|
||||||
return element;
|
return element;
|
||||||
}
|
}
|
||||||
}).getStatByEnum(_chartsY) as double;
|
}).getStatByEnum(_chartsY).toDouble();
|
||||||
actualMaxY = (widget.rank[1]["entries"] as List<TetrioPlayerFromLeaderboard>).reduce((value, element) {
|
actualMaxY = (widget.rank[1]["entries"] as List<TetrioPlayerFromLeaderboard>).reduce((value, element) {
|
||||||
num n = max(value.getStatByEnum(_chartsY), element.getStatByEnum(_chartsY));
|
num n = max(value.getStatByEnum(_chartsY), element.getStatByEnum(_chartsY));
|
||||||
if (value.getStatByEnum(_chartsY) == n) {
|
if (value.getStatByEnum(_chartsY) == n) {
|
||||||
|
@ -97,7 +99,7 @@ class RankState extends State<RankView> with SingleTickerProviderStateMixin {
|
||||||
} else {
|
} else {
|
||||||
return element;
|
return element;
|
||||||
}
|
}
|
||||||
}).getStatByEnum(_chartsY) as double;
|
}).getStatByEnum(_chartsY).toDouble();
|
||||||
}
|
}
|
||||||
|
|
||||||
void resetScale(){
|
void resetScale(){
|
||||||
|
@ -164,7 +166,7 @@ class RankState extends State<RankView> with SingleTickerProviderStateMixin {
|
||||||
previousAxisTitles = _chartsX.toString()+_chartsY.toString();
|
previousAxisTitles = _chartsX.toString()+_chartsY.toString();
|
||||||
}
|
}
|
||||||
final t = Translations.of(context);
|
final t = Translations.of(context);
|
||||||
List<TetrioPlayerFromLeaderboard> they = TetrioPlayersLeaderboard("lol", []).getStatRanking(widget.rank[1]["entries"]!, _sortBy, reversed: _reversed, country: _country);
|
//they = TetrioPlayersLeaderboard("lol", []).getStatRanking(widget.rank[1]["entries"]!, _sortBy, reversed: _reversed, country: _country);
|
||||||
return Scaffold(
|
return Scaffold(
|
||||||
appBar: AppBar(
|
appBar: AppBar(
|
||||||
title: Text(widget.rank[1]["everyone"] ? t.everyoneAverages : t.rankAverages(rank: widget.rank[0].rank.toUpperCase())),
|
title: Text(widget.rank[1]["everyone"] ? t.everyoneAverages : t.rankAverages(rank: widget.rank[0].rank.toUpperCase())),
|
||||||
|
@ -327,8 +329,8 @@ class RankState extends State<RankView> with SingleTickerProviderStateMixin {
|
||||||
for (TetrioPlayerFromLeaderboard entry in widget.rank[1]["entries"])
|
for (TetrioPlayerFromLeaderboard entry in widget.rank[1]["entries"])
|
||||||
if (entry.apm != 0.0 && entry.vs != 0.0) // prevents from ScatterChart "Offset argument contained a NaN value." exception
|
if (entry.apm != 0.0 && entry.vs != 0.0) // prevents from ScatterChart "Offset argument contained a NaN value." exception
|
||||||
_MyScatterSpot(
|
_MyScatterSpot(
|
||||||
entry.getStatByEnum(_chartsX) as double,
|
entry.getStatByEnum(_chartsX).toDouble(),
|
||||||
entry.getStatByEnum(_chartsY) as double,
|
entry.getStatByEnum(_chartsY).toDouble(),
|
||||||
entry.userId,
|
entry.userId,
|
||||||
entry.username,
|
entry.username,
|
||||||
dotPainter: FlDotCirclePainter(color: rankColors[entry.rank]??Colors.white, radius: 3))
|
dotPainter: FlDotCirclePainter(color: rankColors[entry.rank]??Colors.white, radius: 3))
|
||||||
|
@ -403,7 +405,9 @@ class RankState extends State<RankView> with SingleTickerProviderStateMixin {
|
||||||
value: _sortBy,
|
value: _sortBy,
|
||||||
onChanged: ((value) {
|
onChanged: ((value) {
|
||||||
_sortBy = value;
|
_sortBy = value;
|
||||||
setState(() {});
|
setState(() {
|
||||||
|
they = TetrioPlayersLeaderboard("lol", []).getStatRanking(widget.rank[1]["entries"]!, _sortBy, reversed: _reversed, country: _country);
|
||||||
|
});
|
||||||
}),
|
}),
|
||||||
),
|
),
|
||||||
],
|
],
|
||||||
|
|
|
@ -1,8 +1,8 @@
|
||||||
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:intl/intl.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/views/rank_averages_view.dart';
|
import 'package:tetra_stats/views/rank_averages_view.dart';
|
||||||
import 'package:window_manager/window_manager.dart';
|
import 'package:window_manager/window_manager.dart';
|
||||||
import 'main_view.dart'; // lol
|
import 'main_view.dart'; // lol
|
||||||
|
@ -40,7 +40,6 @@ class RanksAverages extends State<RankAveragesView> {
|
||||||
|
|
||||||
@override
|
@override
|
||||||
Widget build(BuildContext context) {
|
Widget build(BuildContext context) {
|
||||||
final NumberFormat f2 = NumberFormat.decimalPattern(LocaleSettings.currentLocale.languageCode)..maximumFractionDigits = 2;
|
|
||||||
return Scaffold(
|
return Scaffold(
|
||||||
appBar: AppBar(
|
appBar: AppBar(
|
||||||
title: Text(t.rankAveragesViewTitle),
|
title: Text(t.rankAveragesViewTitle),
|
||||||
|
@ -55,7 +54,8 @@ class RanksAverages extends State<RankAveragesView> {
|
||||||
return ListTile(
|
return ListTile(
|
||||||
leading: Image.asset("res/tetrio_tl_alpha_ranks/${keys[index]}.png", height: 48),
|
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")),
|
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"),
|
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: TextStyle(fontFamily: "Eurostile Round Condensed", color: Colors.grey)),
|
||||||
trailing: Text("${f2.format(averages[keys[index]]?[1]["toEnterTR"])} TR", style: bigScreen ? const TextStyle(fontSize: 28) : null),
|
trailing: Text("${f2.format(averages[keys[index]]?[1]["toEnterTR"])} TR", style: bigScreen ? const TextStyle(fontSize: 28) : null),
|
||||||
onTap: (){
|
onTap: (){
|
||||||
if (averages[keys[index]]?[1]["players"] > 0) {
|
if (averages[keys[index]]?[1]["players"] > 0) {
|
||||||
|
|
|
@ -1,4 +1,5 @@
|
||||||
import 'dart:io';
|
import 'dart:io';
|
||||||
|
import 'package:go_router/go_router.dart';
|
||||||
import 'package:tetra_stats/data_objects/tetrio.dart';
|
import 'package:tetra_stats/data_objects/tetrio.dart';
|
||||||
import 'package:tetra_stats/main.dart' show packageInfo;
|
import 'package:tetra_stats/main.dart' show packageInfo;
|
||||||
import 'package:file_selector/file_selector.dart';
|
import 'package:file_selector/file_selector.dart';
|
||||||
|
@ -26,6 +27,7 @@ class SettingsState extends State<SettingsView> {
|
||||||
late SharedPreferences prefs;
|
late SharedPreferences prefs;
|
||||||
final TetrioService teto = TetrioService();
|
final TetrioService teto = TetrioService();
|
||||||
String defaultNickname = "Checking...";
|
String defaultNickname = "Checking...";
|
||||||
|
late bool showPositions;
|
||||||
final TextEditingController _playertext = TextEditingController();
|
final TextEditingController _playertext = TextEditingController();
|
||||||
|
|
||||||
@override
|
@override
|
||||||
|
@ -46,6 +48,11 @@ class SettingsState extends State<SettingsView> {
|
||||||
|
|
||||||
Future<void> _getPreferences() async {
|
Future<void> _getPreferences() async {
|
||||||
prefs = await SharedPreferences.getInstance();
|
prefs = await SharedPreferences.getInstance();
|
||||||
|
if (prefs.getBool("showPositions") != null) {
|
||||||
|
showPositions = prefs.getBool("showPositions")!;
|
||||||
|
} else {
|
||||||
|
showPositions = false;
|
||||||
|
}
|
||||||
_setDefaultNickname(prefs.getString("player"));
|
_setDefaultNickname(prefs.getString("player"));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -254,12 +261,20 @@ class SettingsState extends State<SettingsView> {
|
||||||
},
|
},
|
||||||
),
|
),
|
||||||
),
|
),
|
||||||
ListTile(title: const Text("Customization"),
|
ListTile(title: Text(t.customization),
|
||||||
subtitle: const Text("I don't want to implement this"),
|
subtitle: Text(t.customizationDescription),
|
||||||
trailing: const Icon(Icons.arrow_right),
|
trailing: const Icon(Icons.arrow_right),
|
||||||
onTap: () {
|
onTap: () {
|
||||||
Navigator.pushNamed(context, "/customization");
|
context.go("/customization");
|
||||||
},),
|
},),
|
||||||
|
ListTile(title: Text(t.lbStats),
|
||||||
|
subtitle: Text(t.lbStatsDescription),
|
||||||
|
trailing: Switch(value: showPositions, onChanged: (bool value){
|
||||||
|
prefs.setBool("showPositions", value);
|
||||||
|
setState(() {
|
||||||
|
showPositions = value;
|
||||||
|
});
|
||||||
|
}),),
|
||||||
const Divider(),
|
const Divider(),
|
||||||
ListTile(
|
ListTile(
|
||||||
onTap: (){
|
onTap: (){
|
||||||
|
@ -267,6 +282,7 @@ class SettingsState extends State<SettingsView> {
|
||||||
},
|
},
|
||||||
title: Text(t.aboutApp),
|
title: Text(t.aboutApp),
|
||||||
subtitle: Text(t.aboutAppText(appName: packageInfo.appName, packageName: packageInfo.packageName, version: packageInfo.version, buildNumber: packageInfo.buildNumber)),
|
subtitle: Text(t.aboutAppText(appName: packageInfo.appName, packageName: packageInfo.packageName, version: packageInfo.version, buildNumber: packageInfo.buildNumber)),
|
||||||
|
trailing: const Icon(Icons.arrow_right)
|
||||||
),
|
),
|
||||||
],
|
],
|
||||||
)),
|
)),
|
||||||
|
|
|
@ -71,7 +71,7 @@ class TLLeaderboardState extends State<TLLeaderboardView> {
|
||||||
case ConnectionState.none:
|
case ConnectionState.none:
|
||||||
case ConnectionState.waiting:
|
case ConnectionState.waiting:
|
||||||
case ConnectionState.active:
|
case ConnectionState.active:
|
||||||
return const Center(child: Text('Fetching...'));
|
return const Center(child: CircularProgressIndicator());
|
||||||
case ConnectionState.done:
|
case ConnectionState.done:
|
||||||
final allPlayers = snapshot.data?.getStatRanking(snapshot.data!.leaderboard, _sortBy, reversed: reversed, country: _country);
|
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!.length)}");
|
if (!kIsWeb && !Platform.isAndroid && !Platform.isIOS) windowManager.setTitle("Tetra Stats: ${t.tlLeaderboard} - ${t.players(n: allPlayers!.length)}");
|
||||||
|
@ -175,7 +175,8 @@ class TLLeaderboardState extends State<TLLeaderboardView> {
|
||||||
return ListTile(
|
return ListTile(
|
||||||
leading: Text((index+1).toString(), style: bigScreen ? const TextStyle(fontFamily: "Eurostile Round Extended", fontSize: 28) : null),
|
leading: Text((index+1).toString(), style: bigScreen ? const TextStyle(fontFamily: "Eurostile Round Extended", fontSize: 28) : null),
|
||||||
title: Text(allPlayers[index].username, style: const TextStyle(fontFamily: "Eurostile Round Extended")),
|
title: Text(allPlayers[index].username, style: const TextStyle(fontFamily: "Eurostile Round Extended")),
|
||||||
subtitle: 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]}"),
|
subtitle: 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", color: _sortBy == Stats.tr ? Colors.grey : null)),
|
||||||
trailing: Row(
|
trailing: Row(
|
||||||
mainAxisSize: MainAxisSize.min,
|
mainAxisSize: MainAxisSize.min,
|
||||||
children: [
|
children: [
|
||||||
|
|
|
@ -1,9 +1,11 @@
|
||||||
// ignore_for_file: use_build_context_synchronously
|
// ignore_for_file: use_build_context_synchronously
|
||||||
|
|
||||||
import 'dart:io';
|
import 'dart:io';
|
||||||
|
import 'dart:math';
|
||||||
import 'package:tetra_stats/data_objects/tetrio_multiplayer_replay.dart';
|
import 'package:tetra_stats/data_objects/tetrio_multiplayer_replay.dart';
|
||||||
import 'package:tetra_stats/services/crud_exceptions.dart';
|
import 'package:tetra_stats/services/crud_exceptions.dart';
|
||||||
import 'package:tetra_stats/views/compare_view.dart' show CompareThingy, CompareBoolThingy;
|
import 'package:tetra_stats/views/compare_view.dart' show CompareThingy, CompareBoolThingy;
|
||||||
|
import 'package:tetra_stats/widgets/list_tile_trailing_stats.dart';
|
||||||
import 'package:tetra_stats/widgets/vs_graphs.dart';
|
import 'package:tetra_stats/widgets/vs_graphs.dart';
|
||||||
import 'main_view.dart' show teto, secs;
|
import 'main_view.dart' show teto, secs;
|
||||||
import 'package:flutter/foundation.dart';
|
import 'package:flutter/foundation.dart';
|
||||||
|
@ -20,6 +22,9 @@ import 'package:window_manager/window_manager.dart';
|
||||||
final DateFormat dateFormat = DateFormat.yMMMd(LocaleSettings.currentLocale.languageCode).add_Hms();
|
final DateFormat dateFormat = DateFormat.yMMMd(LocaleSettings.currentLocale.languageCode).add_Hms();
|
||||||
int roundSelector = -1; // -1 = match averages, otherwise round number-1
|
int roundSelector = -1; // -1 = match averages, otherwise round number-1
|
||||||
List<DropdownMenuItem> rounds = []; // index zero will be match stats
|
List<DropdownMenuItem> rounds = []; // index zero will be match stats
|
||||||
|
bool timeWeightedStatsAvaliable = true;
|
||||||
|
int greenSidePlayer = 0;
|
||||||
|
int redSidePlayer = 1;
|
||||||
late String oldWindowTitle;
|
late String oldWindowTitle;
|
||||||
|
|
||||||
Duration framesToTime(int frames){
|
Duration framesToTime(int frames){
|
||||||
|
@ -36,12 +41,10 @@ class TlMatchResultView extends StatefulWidget {
|
||||||
}
|
}
|
||||||
|
|
||||||
class TlMatchResultState extends State<TlMatchResultView> {
|
class TlMatchResultState extends State<TlMatchResultView> {
|
||||||
late ScrollController _scrollController;
|
|
||||||
late Future<ReplayData?> replayData;
|
late Future<ReplayData?> replayData;
|
||||||
|
|
||||||
@override
|
@override
|
||||||
void initState(){
|
void initState(){
|
||||||
_scrollController = ScrollController();
|
|
||||||
rounds = [DropdownMenuItem(value: -1, child: Text(t.match))];
|
rounds = [DropdownMenuItem(value: -1, child: Text(t.match))];
|
||||||
rounds.addAll([for (int i = 0; i < widget.record.endContext.first.secondaryTracking.length; i++) DropdownMenuItem(value: i, child: Text(t.roundNumber(n: i+1)))]);
|
rounds.addAll([for (int i = 0; i < widget.record.endContext.first.secondaryTracking.length; i++) DropdownMenuItem(value: i, child: Text(t.roundNumber(n: i+1)))]);
|
||||||
replayData = teto.analyzeReplay(widget.record.replayId, widget.record.replayAvalable);
|
replayData = teto.analyzeReplay(widget.record.replayId, widget.record.replayAvalable);
|
||||||
|
@ -59,64 +62,44 @@ class TlMatchResultState extends State<TlMatchResultView> {
|
||||||
super.dispose();
|
super.dispose();
|
||||||
}
|
}
|
||||||
|
|
||||||
@override
|
Widget buildComparison(bool bigScreen, bool showMobileSelector){
|
||||||
Widget build(BuildContext context) {
|
return FutureBuilder(future: replayData, builder: (context, snapshot){
|
||||||
final t = Translations.of(context);
|
late Duration time;
|
||||||
bool bigScreen = MediaQuery.of(context).size.width > 768;
|
late String readableTime;
|
||||||
return Scaffold(
|
late String reason;
|
||||||
appBar: AppBar(
|
timeWeightedStatsAvaliable = true;
|
||||||
title: Text("${widget.record.endContext.firstWhere((element) => element.userId == widget.initPlayerId).username.toUpperCase()} ${t.vs} ${widget.record.endContext.firstWhere((element) => element.userId != widget.initPlayerId).username.toUpperCase()} ${t.inTLmatch} ${dateFormat.format(widget.record.timestamp)}"),
|
if (snapshot.connectionState != ConnectionState.done) return const LinearProgressIndicator();
|
||||||
actions: [
|
if (!snapshot.hasError){
|
||||||
PopupMenuButton(
|
if (rounds.indexWhere((element) => element.value == -2) == -1) rounds.insert(1, DropdownMenuItem(value: -2, child: Text(t.timeWeightedmatch)));
|
||||||
enabled: widget.record.replayAvalable,
|
greenSidePlayer = snapshot.data!.endcontext.indexWhere((element) => element.userId == widget.initPlayerId);
|
||||||
itemBuilder: (BuildContext context) => <PopupMenuEntry>[
|
redSidePlayer = snapshot.data!.endcontext.indexWhere((element) => element.userId != widget.initPlayerId);
|
||||||
PopupMenuItem(
|
if (roundSelector.isNegative){
|
||||||
value: 1,
|
time = framesToTime(snapshot.data!.totalLength);
|
||||||
child: Text(t.downloadReplay),
|
readableTime = "${t.matchLength}: ${time.inMinutes}:${secs.format(time.inMicroseconds /1000000 % 60)}";
|
||||||
),
|
|
||||||
PopupMenuItem(
|
|
||||||
value: 2,
|
|
||||||
child: Text(t.openReplay),
|
|
||||||
),
|
|
||||||
],
|
|
||||||
onSelected: (value) async {
|
|
||||||
switch (value) {
|
|
||||||
case 1:
|
|
||||||
if (kIsWeb){
|
|
||||||
// final _base64 = base64Encode([1,2,3,4,5]);
|
|
||||||
// final anchor = AnchorElement(href: 'data:application/octet-stream;base64,$_base64')..target = 'blank';
|
|
||||||
//final anchor = AnchorElement(href: 'https://inoue.szy.lol/api/replay/${widget.record.replayId}')..target = 'blank';
|
|
||||||
//anchor.download = "${widget.record.replayId}.ttrm";
|
|
||||||
//document.body!.append(anchor);
|
|
||||||
//anchor.click();
|
|
||||||
//anchor.remove();
|
|
||||||
}else{
|
}else{
|
||||||
try{
|
time = framesToTime(snapshot.data!.roundLengths[roundSelector]);
|
||||||
String path = await teto.saveReplay(widget.record.replayId);
|
readableTime = "${t.roundLength}: ${time.inMinutes}:${secs.format(time.inMicroseconds /1000000 % 60)}\n${t.winner}: ${snapshot.data!.roundWinners[roundSelector][1]}";
|
||||||
ScaffoldMessenger.of(context).showSnackBar(SnackBar(content: Text(t.replaySaved(path: path))));
|
|
||||||
} on TetrioReplayAlreadyExist{
|
|
||||||
ScaffoldMessenger.of(context).showSnackBar(SnackBar(content: Text(t.errors.replayAlreadySaved)));
|
|
||||||
} on SzyNotFound {
|
|
||||||
ScaffoldMessenger.of(context).showSnackBar(SnackBar(content: Text(t.errors.replayExpired)));
|
|
||||||
} on SzyForbidden {
|
|
||||||
ScaffoldMessenger.of(context).showSnackBar(SnackBar(content: Text(t.errors.replayRejected)));
|
|
||||||
} on SzyTooManyRequests {
|
|
||||||
ScaffoldMessenger.of(context).showSnackBar(SnackBar(content: Text(t.errors.tooManyRequests)));
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
}else{
|
||||||
|
switch (snapshot.error.runtimeType){
|
||||||
|
case ReplayNotAvalable:
|
||||||
|
reason = t.matchIsTooOld;
|
||||||
break;
|
break;
|
||||||
case 2:
|
case SzyNotFound:
|
||||||
await launchInBrowser(Uri.parse("https://tetr.io/#r:${widget.record.replayId}"));
|
reason = t.matchIsTooOld;
|
||||||
|
break;
|
||||||
|
case SzyForbidden:
|
||||||
|
reason = t.errors.replayRejected;
|
||||||
|
break;
|
||||||
|
case SzyTooManyRequests:
|
||||||
|
reason = t.errors.tooManyRequests;
|
||||||
break;
|
break;
|
||||||
default:
|
default:
|
||||||
|
reason = snapshot.error.toString();
|
||||||
|
break;
|
||||||
}
|
}
|
||||||
})
|
}
|
||||||
]
|
return NestedScrollView(
|
||||||
),
|
|
||||||
backgroundColor: Colors.black,
|
|
||||||
body: SafeArea(
|
|
||||||
child: NestedScrollView(
|
|
||||||
controller: _scrollController,
|
|
||||||
headerSliverBuilder: (context, value) {
|
headerSliverBuilder: (context, value) {
|
||||||
return [
|
return [
|
||||||
SliverToBoxAdapter(
|
SliverToBoxAdapter(
|
||||||
|
@ -178,7 +161,7 @@ class TlMatchResultState extends State<TlMatchResultView> {
|
||||||
),
|
),
|
||||||
),
|
),
|
||||||
),
|
),
|
||||||
SliverToBoxAdapter(
|
if (showMobileSelector) SliverToBoxAdapter(
|
||||||
child: Center(
|
child: Center(
|
||||||
child: Row(
|
child: Row(
|
||||||
mainAxisSize: MainAxisSize.min,
|
mainAxisSize: MainAxisSize.min,
|
||||||
|
@ -195,48 +178,10 @@ class TlMatchResultState extends State<TlMatchResultView> {
|
||||||
),
|
),
|
||||||
),
|
),
|
||||||
),
|
),
|
||||||
if (widget.record.ownId == widget.record.replayId) SliverToBoxAdapter(
|
if (widget.record.ownId == widget.record.replayId && showMobileSelector) SliverToBoxAdapter(
|
||||||
child: Center(child: Text(t.p1nkl0bst3rAlert, textAlign: TextAlign.center)),
|
child: Center(child: Text(t.p1nkl0bst3rAlert, textAlign: TextAlign.center)),
|
||||||
),
|
),
|
||||||
SliverToBoxAdapter(child: FutureBuilder(future: replayData, builder: (context, snapshot) {
|
if (showMobileSelector) SliverToBoxAdapter(child: Center(child: Text(snapshot.hasError ? reason : readableTime, textAlign: TextAlign.center))),
|
||||||
switch(snapshot.connectionState){
|
|
||||||
case ConnectionState.none:
|
|
||||||
case ConnectionState.waiting:
|
|
||||||
case ConnectionState.active:
|
|
||||||
return const LinearProgressIndicator();
|
|
||||||
case ConnectionState.done:
|
|
||||||
if (!snapshot.hasError){
|
|
||||||
if (roundSelector.isNegative){
|
|
||||||
var time = framesToTime(snapshot.data!.totalLength);
|
|
||||||
return Center(child: Text("${t.matchLength}: ${time.inMinutes}:${secs.format(time.inMicroseconds /1000000 % 60)}", textAlign: TextAlign.center));
|
|
||||||
}else{
|
|
||||||
var time = framesToTime(snapshot.data!.roundLengths[roundSelector]);
|
|
||||||
return Center(child: Text("${t.roundLength}: ${time.inMinutes}:${secs.format(time.inMicroseconds /1000000 % 60)}\n${t.winner}: ${snapshot.data!.roundWinners[roundSelector][1]}", textAlign: TextAlign.center,));
|
|
||||||
}
|
|
||||||
}else{
|
|
||||||
String reason;
|
|
||||||
switch (snapshot.error.runtimeType){
|
|
||||||
case ReplayNotAvalable:
|
|
||||||
reason = t.matchIsTooOld;
|
|
||||||
break;
|
|
||||||
case SzyNotFound:
|
|
||||||
reason = t.matchIsTooOld;
|
|
||||||
break;
|
|
||||||
case SzyForbidden:
|
|
||||||
reason = t.errors.replayRejected;
|
|
||||||
break;
|
|
||||||
case SzyTooManyRequests:
|
|
||||||
reason = t.errors.tooManyRequests;
|
|
||||||
break;
|
|
||||||
default:
|
|
||||||
reason = snapshot.error.toString();
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
return Text("${t.replayIssue}: $reason", textAlign: TextAlign.center);
|
|
||||||
}
|
|
||||||
|
|
||||||
}
|
|
||||||
},),),
|
|
||||||
const SliverToBoxAdapter(
|
const SliverToBoxAdapter(
|
||||||
child: Divider(),
|
child: Divider(),
|
||||||
)
|
)
|
||||||
|
@ -248,47 +193,47 @@ class TlMatchResultState extends State<TlMatchResultView> {
|
||||||
children: [
|
children: [
|
||||||
CompareThingy(
|
CompareThingy(
|
||||||
label: "APM",
|
label: "APM",
|
||||||
greenSide: roundSelector.isNegative ? widget.record.endContext.firstWhere((element) => element.userId == widget.initPlayerId).secondary : widget.record.endContext.firstWhere((element) => element.userId == widget.initPlayerId).secondaryTracking[roundSelector],
|
greenSide: (roundSelector == -2 && snapshot.hasData) ? snapshot.data!.timeWeightedStats[greenSidePlayer].apm :
|
||||||
redSide: roundSelector.isNegative ? widget.record.endContext.firstWhere((element) => element.userId != widget.initPlayerId).secondary : widget.record.endContext.firstWhere((element) => element.userId != widget.initPlayerId).secondaryTracking[roundSelector],
|
roundSelector.isNegative ? widget.record.endContext.firstWhere((element) => element.userId == widget.initPlayerId).secondary : widget.record.endContext.firstWhere((element) => element.userId == widget.initPlayerId).secondaryTracking[roundSelector],
|
||||||
|
redSide: (roundSelector == -2 && snapshot.hasData) ? snapshot.data!.timeWeightedStats[redSidePlayer].apm :
|
||||||
|
roundSelector == -1 ? widget.record.endContext.firstWhere((element) => element.userId != widget.initPlayerId).secondary : widget.record.endContext.firstWhere((element) => element.userId != widget.initPlayerId).secondaryTracking[roundSelector],
|
||||||
fractionDigits: 2,
|
fractionDigits: 2,
|
||||||
higherIsBetter: true,
|
higherIsBetter: true,
|
||||||
),
|
),
|
||||||
CompareThingy(
|
CompareThingy(
|
||||||
label: "PPS",
|
label: "PPS",
|
||||||
greenSide: roundSelector.isNegative ? widget.record.endContext.firstWhere((element) => element.userId == widget.initPlayerId).tertiary : widget.record.endContext.firstWhere((element) => element.userId == widget.initPlayerId).tertiaryTracking[roundSelector],
|
greenSide: (roundSelector == -2 && snapshot.hasData) ? snapshot.data!.timeWeightedStats[greenSidePlayer].pps:
|
||||||
redSide: roundSelector.isNegative ? widget.record.endContext.firstWhere((element) => element.userId != widget.initPlayerId).tertiary : widget.record.endContext.firstWhere((element) => element.userId != widget.initPlayerId).tertiaryTracking[roundSelector],
|
roundSelector.isNegative ? widget.record.endContext.firstWhere((element) => element.userId == widget.initPlayerId).tertiary : widget.record.endContext.firstWhere((element) => element.userId == widget.initPlayerId).tertiaryTracking[roundSelector],
|
||||||
|
redSide: (roundSelector == -2 && snapshot.hasData) ? snapshot.data!.timeWeightedStats[redSidePlayer].pps :
|
||||||
|
roundSelector.isNegative ? widget.record.endContext.firstWhere((element) => element.userId != widget.initPlayerId).tertiary: widget.record.endContext.firstWhere((element) => element.userId != widget.initPlayerId).tertiaryTracking[roundSelector],
|
||||||
fractionDigits: 2,
|
fractionDigits: 2,
|
||||||
higherIsBetter: true,
|
higherIsBetter: true,
|
||||||
),
|
),
|
||||||
CompareThingy(
|
CompareThingy(
|
||||||
label: "VS",
|
label: "VS",
|
||||||
greenSide: roundSelector.isNegative ? widget.record.endContext.firstWhere((element) => element.userId == widget.initPlayerId).extra : widget.record.endContext.firstWhere((element) => element.userId == widget.initPlayerId).extraTracking[roundSelector],
|
greenSide: (roundSelector == -2 && snapshot.hasData) ? snapshot.data!.timeWeightedStats[greenSidePlayer].vs :
|
||||||
redSide: roundSelector.isNegative ? widget.record.endContext.firstWhere((element) => element.userId != widget.initPlayerId).extra : widget.record.endContext.firstWhere((element) => element.userId != widget.initPlayerId).extraTracking[roundSelector],
|
roundSelector.isNegative ? widget.record.endContext.firstWhere((element) => element.userId == widget.initPlayerId).extra : widget.record.endContext.firstWhere((element) => element.userId == widget.initPlayerId).extraTracking[roundSelector],
|
||||||
|
redSide: (roundSelector == -2 && snapshot.hasData) ? snapshot.data!.timeWeightedStats[redSidePlayer].vs :
|
||||||
|
roundSelector.isNegative ? widget.record.endContext.firstWhere((element) => element.userId != widget.initPlayerId).extra : widget.record.endContext.firstWhere((element) => element.userId != widget.initPlayerId).extraTracking[roundSelector],
|
||||||
fractionDigits: 2,
|
fractionDigits: 2,
|
||||||
higherIsBetter: true,
|
higherIsBetter: true,
|
||||||
),
|
),
|
||||||
FutureBuilder(future: replayData, builder: (BuildContext context, AsyncSnapshot<ReplayData?> snapshot){
|
if (snapshot.hasData) Column(children: [
|
||||||
switch(snapshot.connectionState){
|
|
||||||
case ConnectionState.none:
|
|
||||||
case ConnectionState.waiting:
|
|
||||||
case ConnectionState.active:
|
|
||||||
return const LinearProgressIndicator();
|
|
||||||
case ConnectionState.done:
|
|
||||||
if (!snapshot.hasError){
|
|
||||||
var greenSidePlayer = snapshot.data!.endcontext.indexWhere((element) => element.userId == widget.initPlayerId);
|
|
||||||
var redSidePlayer = snapshot.data!.endcontext.indexWhere((element) => element.userId != widget.initPlayerId);
|
|
||||||
return Column(children: [
|
|
||||||
CompareThingy(greenSide: roundSelector.isNegative ? snapshot.data!.totalStats[greenSidePlayer].inputs : snapshot.data!.stats[roundSelector][greenSidePlayer].inputs,
|
CompareThingy(greenSide: roundSelector.isNegative ? snapshot.data!.totalStats[greenSidePlayer].inputs : snapshot.data!.stats[roundSelector][greenSidePlayer].inputs,
|
||||||
redSide: roundSelector.isNegative ? snapshot.data!.totalStats[redSidePlayer].inputs : snapshot.data!.stats[roundSelector][redSidePlayer].inputs,
|
redSide: roundSelector.isNegative ? snapshot.data!.totalStats[redSidePlayer].inputs : snapshot.data!.stats[roundSelector][redSidePlayer].inputs,
|
||||||
label: "Inputs", higherIsBetter: true),
|
label: "Inputs", higherIsBetter: true),
|
||||||
CompareThingy(greenSide: roundSelector.isNegative ? snapshot.data!.totalStats[greenSidePlayer].piecesPlaced : snapshot.data!.stats[roundSelector][greenSidePlayer].piecesPlaced,
|
CompareThingy(greenSide: roundSelector.isNegative ? snapshot.data!.totalStats[greenSidePlayer].piecesPlaced : snapshot.data!.stats[roundSelector][greenSidePlayer].piecesPlaced,
|
||||||
redSide: roundSelector.isNegative ? snapshot.data!.totalStats[redSidePlayer].piecesPlaced : snapshot.data!.stats[roundSelector][redSidePlayer].piecesPlaced,
|
redSide: roundSelector.isNegative ? snapshot.data!.totalStats[redSidePlayer].piecesPlaced : snapshot.data!.stats[roundSelector][redSidePlayer].piecesPlaced,
|
||||||
label: "Pieces Placed", higherIsBetter: true),
|
label: "Pieces Placed", higherIsBetter: true),
|
||||||
CompareThingy(greenSide: roundSelector.isNegative ? snapshot.data!.totalStats[greenSidePlayer].kpp : snapshot.data!.stats[roundSelector][greenSidePlayer].kpp,
|
CompareThingy(greenSide: (roundSelector == -2 && snapshot.hasData) ? snapshot.data!.timeWeightedStats[greenSidePlayer].kpp :
|
||||||
redSide: roundSelector.isNegative ? snapshot.data!.totalStats[redSidePlayer].kpp : snapshot.data!.stats[roundSelector][redSidePlayer].kpp,
|
roundSelector.isNegative ? snapshot.data!.totalStats[greenSidePlayer].kpp : snapshot.data!.stats[roundSelector][greenSidePlayer].kpp,
|
||||||
|
redSide: (roundSelector == -2 && snapshot.hasData) ? snapshot.data!.timeWeightedStats[redSidePlayer].kpp :
|
||||||
|
roundSelector.isNegative ? snapshot.data!.totalStats[redSidePlayer].kpp : snapshot.data!.stats[roundSelector][redSidePlayer].kpp,
|
||||||
label: "KpP", higherIsBetter: false, fractionDigits: 2,),
|
label: "KpP", higherIsBetter: false, fractionDigits: 2,),
|
||||||
CompareThingy(greenSide: roundSelector.isNegative ? snapshot.data!.totalStats[greenSidePlayer].kps : snapshot.data!.stats[roundSelector][greenSidePlayer].kps,
|
CompareThingy(greenSide: (roundSelector == -2 && snapshot.hasData) ? snapshot.data!.timeWeightedStats[greenSidePlayer].kps :
|
||||||
redSide: roundSelector.isNegative ? snapshot.data!.totalStats[redSidePlayer].kps : snapshot.data!.stats[roundSelector][redSidePlayer].kps,
|
roundSelector.isNegative ? snapshot.data!.totalStats[greenSidePlayer].kps : snapshot.data!.stats[roundSelector][greenSidePlayer].kps,
|
||||||
|
redSide: (roundSelector == -2 && snapshot.hasData) ? snapshot.data!.timeWeightedStats[redSidePlayer].kps :
|
||||||
|
roundSelector.isNegative ? snapshot.data!.totalStats[redSidePlayer].kps : snapshot.data!.stats[roundSelector][redSidePlayer].kps,
|
||||||
label: "KpS", higherIsBetter: true, fractionDigits: 2,),
|
label: "KpS", higherIsBetter: true, fractionDigits: 2,),
|
||||||
CompareThingy(greenSide: roundSelector.isNegative ? snapshot.data!.totalStats[greenSidePlayer].linesCleared : snapshot.data!.stats[roundSelector][greenSidePlayer].linesCleared,
|
CompareThingy(greenSide: roundSelector.isNegative ? snapshot.data!.totalStats[greenSidePlayer].linesCleared : snapshot.data!.stats[roundSelector][greenSidePlayer].linesCleared,
|
||||||
redSide: roundSelector.isNegative ? snapshot.data!.totalStats[redSidePlayer].linesCleared : snapshot.data!.stats[roundSelector][redSidePlayer].linesCleared,
|
redSide: roundSelector.isNegative ? snapshot.data!.totalStats[redSidePlayer].linesCleared : snapshot.data!.stats[roundSelector][redSidePlayer].linesCleared,
|
||||||
|
@ -296,8 +241,10 @@ class TlMatchResultState extends State<TlMatchResultView> {
|
||||||
CompareThingy(greenSide: roundSelector.isNegative ? snapshot.data!.totalStats[greenSidePlayer].score : snapshot.data!.stats[roundSelector][greenSidePlayer].score,
|
CompareThingy(greenSide: roundSelector.isNegative ? snapshot.data!.totalStats[greenSidePlayer].score : snapshot.data!.stats[roundSelector][greenSidePlayer].score,
|
||||||
redSide: roundSelector.isNegative ? snapshot.data!.totalStats[redSidePlayer].score : snapshot.data!.stats[roundSelector][redSidePlayer].score,
|
redSide: roundSelector.isNegative ? snapshot.data!.totalStats[redSidePlayer].score : snapshot.data!.stats[roundSelector][redSidePlayer].score,
|
||||||
label: "Score", higherIsBetter: true),
|
label: "Score", higherIsBetter: true),
|
||||||
CompareThingy(greenSide: roundSelector.isNegative ? snapshot.data!.totalStats[greenSidePlayer].spp : snapshot.data!.stats[roundSelector][greenSidePlayer].spp,
|
CompareThingy(greenSide: (roundSelector == -2 && snapshot.hasData) ? snapshot.data!.timeWeightedStats[greenSidePlayer].spp :
|
||||||
redSide: roundSelector.isNegative ? snapshot.data!.totalStats[redSidePlayer].spp : snapshot.data!.stats[roundSelector][redSidePlayer].spp,
|
roundSelector.isNegative ? snapshot.data!.totalStats[greenSidePlayer].spp : snapshot.data!.stats[roundSelector][greenSidePlayer].spp,
|
||||||
|
redSide: (roundSelector == -2 && snapshot.hasData) ? snapshot.data!.timeWeightedStats[redSidePlayer].spp :
|
||||||
|
roundSelector.isNegative ? snapshot.data!.totalStats[redSidePlayer].spp : snapshot.data!.stats[roundSelector][redSidePlayer].spp,
|
||||||
label: "SpP", higherIsBetter: true, fractionDigits: 2,),
|
label: "SpP", higherIsBetter: true, fractionDigits: 2,),
|
||||||
CompareThingy(greenSide: roundSelector.isNegative ? snapshot.data!.totalStats[greenSidePlayer].finessePercentage * 100 : snapshot.data!.stats[roundSelector][greenSidePlayer].finessePercentage * 100,
|
CompareThingy(greenSide: roundSelector.isNegative ? snapshot.data!.totalStats[greenSidePlayer].finessePercentage * 100 : snapshot.data!.stats[roundSelector][greenSidePlayer].finessePercentage * 100,
|
||||||
redSide: roundSelector.isNegative ? snapshot.data!.totalStats[redSidePlayer].finessePercentage * 100 : snapshot.data!.stats[roundSelector][redSidePlayer].finessePercentage * 100,
|
redSide: roundSelector.isNegative ? snapshot.data!.totalStats[redSidePlayer].finessePercentage * 100 : snapshot.data!.stats[roundSelector][redSidePlayer].finessePercentage * 100,
|
||||||
|
@ -342,13 +289,7 @@ class TlMatchResultState extends State<TlMatchResultView> {
|
||||||
CompareThingy(greenSide: roundSelector.isNegative ? snapshot.data!.totalStats[greenSidePlayer].clears.quads : snapshot.data!.stats[roundSelector][greenSidePlayer].clears.quads,
|
CompareThingy(greenSide: roundSelector.isNegative ? snapshot.data!.totalStats[greenSidePlayer].clears.quads : snapshot.data!.stats[roundSelector][greenSidePlayer].clears.quads,
|
||||||
redSide: roundSelector.isNegative ? snapshot.data!.totalStats[redSidePlayer].clears.quads : snapshot.data!.stats[roundSelector][redSidePlayer].clears.quads,
|
redSide: roundSelector.isNegative ? snapshot.data!.totalStats[redSidePlayer].clears.quads : snapshot.data!.stats[roundSelector][redSidePlayer].clears.quads,
|
||||||
label: "Quads", higherIsBetter: true),
|
label: "Quads", higherIsBetter: true),
|
||||||
],);
|
],),
|
||||||
}else{
|
|
||||||
return Container();
|
|
||||||
}
|
|
||||||
|
|
||||||
}
|
|
||||||
})
|
|
||||||
],
|
],
|
||||||
),
|
),
|
||||||
const Divider(),
|
const Divider(),
|
||||||
|
@ -363,113 +304,141 @@ class TlMatchResultState extends State<TlMatchResultView> {
|
||||||
),
|
),
|
||||||
CompareThingy(
|
CompareThingy(
|
||||||
label: "APP",
|
label: "APP",
|
||||||
greenSide: roundSelector.isNegative ? widget.record.endContext.firstWhere((element) => element.userId == widget.initPlayerId).nerdStats.app : widget.record.endContext.firstWhere((element) => element.userId == widget.initPlayerId).nerdStatsTracking[roundSelector].app,
|
greenSide: (roundSelector == -2 && snapshot.hasData) ? snapshot.data!.timeWeightedStats[greenSidePlayer].nerdStats.app :
|
||||||
redSide: roundSelector.isNegative ? widget.record.endContext.firstWhere((element) => element.userId != widget.initPlayerId).nerdStats.app : widget.record.endContext.firstWhere((element) => element.userId != widget.initPlayerId).nerdStatsTracking[roundSelector].app,
|
roundSelector.isNegative ? widget.record.endContext.firstWhere((element) => element.userId == widget.initPlayerId).nerdStats.app : widget.record.endContext.firstWhere((element) => element.userId == widget.initPlayerId).nerdStatsTracking[roundSelector].app,
|
||||||
|
redSide: (roundSelector == -2 && snapshot.hasData) ? snapshot.data!.timeWeightedStats[redSidePlayer].nerdStats.app :
|
||||||
|
roundSelector.isNegative ? widget.record.endContext.firstWhere((element) => element.userId != widget.initPlayerId).nerdStats.app : widget.record.endContext.firstWhere((element) => element.userId != widget.initPlayerId).nerdStatsTracking[roundSelector].app,
|
||||||
fractionDigits: 3,
|
fractionDigits: 3,
|
||||||
higherIsBetter: true,
|
higherIsBetter: true,
|
||||||
),
|
),
|
||||||
CompareThingy(
|
CompareThingy(
|
||||||
label: "VS/APM",
|
label: "VS/APM",
|
||||||
greenSide: roundSelector.isNegative ? widget.record.endContext.firstWhere((element) => element.userId == widget.initPlayerId).nerdStats.vsapm : widget.record.endContext.firstWhere((element) => element.userId == widget.initPlayerId).nerdStatsTracking[roundSelector].vsapm,
|
greenSide: (roundSelector == -2 && snapshot.hasData) ? snapshot.data!.timeWeightedStats[greenSidePlayer].nerdStats.vsapm :
|
||||||
redSide: roundSelector.isNegative ? widget.record.endContext.firstWhere((element) => element.userId != widget.initPlayerId).nerdStats.vsapm : widget.record.endContext.firstWhere((element) => element.userId != widget.initPlayerId).nerdStatsTracking[roundSelector].vsapm,
|
roundSelector.isNegative ? widget.record.endContext.firstWhere((element) => element.userId == widget.initPlayerId).nerdStats.vsapm : widget.record.endContext.firstWhere((element) => element.userId == widget.initPlayerId).nerdStatsTracking[roundSelector].vsapm,
|
||||||
|
redSide: (roundSelector == -2 && snapshot.hasData) ? snapshot.data!.timeWeightedStats[redSidePlayer].nerdStats.vsapm :
|
||||||
|
roundSelector.isNegative ? widget.record.endContext.firstWhere((element) => element.userId != widget.initPlayerId).nerdStats.vsapm : widget.record.endContext.firstWhere((element) => element.userId != widget.initPlayerId).nerdStatsTracking[roundSelector].vsapm,
|
||||||
fractionDigits: 3,
|
fractionDigits: 3,
|
||||||
higherIsBetter: true,
|
higherIsBetter: true,
|
||||||
),
|
),
|
||||||
CompareThingy(
|
CompareThingy(
|
||||||
label: "DS/S",
|
label: "DS/S",
|
||||||
greenSide: roundSelector.isNegative ? widget.record.endContext.firstWhere((element) => element.userId == widget.initPlayerId).nerdStats.dss : widget.record.endContext.firstWhere((element) => element.userId == widget.initPlayerId).nerdStatsTracking[roundSelector].dss,
|
greenSide: (roundSelector == -2 && snapshot.hasData) ? snapshot.data!.timeWeightedStats[greenSidePlayer].nerdStats.dss :
|
||||||
redSide: roundSelector.isNegative ? widget.record.endContext.firstWhere((element) => element.userId != widget.initPlayerId).nerdStats.dss : widget.record.endContext.firstWhere((element) => element.userId != widget.initPlayerId).nerdStatsTracking[roundSelector].dss,
|
roundSelector.isNegative ? widget.record.endContext.firstWhere((element) => element.userId == widget.initPlayerId).nerdStats.dss : widget.record.endContext.firstWhere((element) => element.userId == widget.initPlayerId).nerdStatsTracking[roundSelector].dss,
|
||||||
|
redSide: (roundSelector == -2 && snapshot.hasData) ? snapshot.data!.timeWeightedStats[redSidePlayer].nerdStats.dss :
|
||||||
|
roundSelector.isNegative ? widget.record.endContext.firstWhere((element) => element.userId != widget.initPlayerId).nerdStats.dss : widget.record.endContext.firstWhere((element) => element.userId != widget.initPlayerId).nerdStatsTracking[roundSelector].dss,
|
||||||
fractionDigits: 3,
|
fractionDigits: 3,
|
||||||
higherIsBetter: true,
|
higherIsBetter: true,
|
||||||
),
|
),
|
||||||
CompareThingy(
|
CompareThingy(
|
||||||
label: "DS/P",
|
label: "DS/P",
|
||||||
greenSide: roundSelector.isNegative ? widget.record.endContext.firstWhere((element) => element.userId == widget.initPlayerId).nerdStats.dsp : widget.record.endContext.firstWhere((element) => element.userId == widget.initPlayerId).nerdStatsTracking[roundSelector].dsp,
|
greenSide: (roundSelector == -2 && snapshot.hasData) ? snapshot.data!.timeWeightedStats[greenSidePlayer].nerdStats.dsp :
|
||||||
redSide: roundSelector.isNegative ? widget.record.endContext.firstWhere((element) => element.userId != widget.initPlayerId).nerdStats.dsp : widget.record.endContext.firstWhere((element) => element.userId != widget.initPlayerId).nerdStatsTracking[roundSelector].dsp,
|
roundSelector.isNegative ? widget.record.endContext.firstWhere((element) => element.userId == widget.initPlayerId).nerdStats.dsp : widget.record.endContext.firstWhere((element) => element.userId == widget.initPlayerId).nerdStatsTracking[roundSelector].dsp,
|
||||||
|
redSide: (roundSelector == -2 && snapshot.hasData) ? snapshot.data!.timeWeightedStats[redSidePlayer].nerdStats.dsp :
|
||||||
|
roundSelector.isNegative ? widget.record.endContext.firstWhere((element) => element.userId != widget.initPlayerId).nerdStats.dsp : widget.record.endContext.firstWhere((element) => element.userId != widget.initPlayerId).nerdStatsTracking[roundSelector].dsp,
|
||||||
fractionDigits: 3,
|
fractionDigits: 3,
|
||||||
higherIsBetter: true,
|
higherIsBetter: true,
|
||||||
),
|
),
|
||||||
CompareThingy(
|
CompareThingy(
|
||||||
label: "APP + DS/P",
|
label: "APP + DS/P",
|
||||||
greenSide: roundSelector.isNegative ? widget.record.endContext.firstWhere((element) => element.userId == widget.initPlayerId).nerdStats.appdsp : widget.record.endContext.firstWhere((element) => element.userId == widget.initPlayerId).nerdStatsTracking[roundSelector].appdsp,
|
greenSide: (roundSelector == -2 && snapshot.hasData) ? snapshot.data!.timeWeightedStats[greenSidePlayer].nerdStats.appdsp :
|
||||||
redSide: roundSelector.isNegative ? widget.record.endContext.firstWhere((element) => element.userId != widget.initPlayerId).nerdStats.appdsp : widget.record.endContext.firstWhere((element) => element.userId != widget.initPlayerId).nerdStatsTracking[roundSelector].appdsp,
|
roundSelector.isNegative ? widget.record.endContext.firstWhere((element) => element.userId == widget.initPlayerId).nerdStats.appdsp : widget.record.endContext.firstWhere((element) => element.userId == widget.initPlayerId).nerdStatsTracking[roundSelector].appdsp,
|
||||||
|
redSide: (roundSelector == -2 && snapshot.hasData) ? snapshot.data!.timeWeightedStats[redSidePlayer].nerdStats.appdsp :
|
||||||
|
roundSelector.isNegative ? widget.record.endContext.firstWhere((element) => element.userId != widget.initPlayerId).nerdStats.appdsp : widget.record.endContext.firstWhere((element) => element.userId != widget.initPlayerId).nerdStatsTracking[roundSelector].appdsp,
|
||||||
fractionDigits: 3,
|
fractionDigits: 3,
|
||||||
higherIsBetter: true,
|
higherIsBetter: true,
|
||||||
),
|
),
|
||||||
CompareThingy(
|
CompareThingy(
|
||||||
label: t.statCellNum.cheese.replaceAll(RegExp(r'\n'), " "),
|
label: t.statCellNum.cheese.replaceAll(RegExp(r'\n'), " "),
|
||||||
greenSide: roundSelector.isNegative ? widget.record.endContext.firstWhere((element) => element.userId == widget.initPlayerId).nerdStats.cheese : widget.record.endContext.firstWhere((element) => element.userId == widget.initPlayerId).nerdStatsTracking[roundSelector].cheese,
|
greenSide: (roundSelector == -2 && snapshot.hasData) ? snapshot.data!.timeWeightedStats[greenSidePlayer].nerdStats.cheese :
|
||||||
redSide: roundSelector.isNegative ? widget.record.endContext.firstWhere((element) => element.userId != widget.initPlayerId).nerdStats.cheese : widget.record.endContext.firstWhere((element) => element.userId != widget.initPlayerId).nerdStatsTracking[roundSelector].cheese,
|
roundSelector.isNegative ? widget.record.endContext.firstWhere((element) => element.userId == widget.initPlayerId).nerdStats.cheese : widget.record.endContext.firstWhere((element) => element.userId == widget.initPlayerId).nerdStatsTracking[roundSelector].cheese,
|
||||||
|
redSide: (roundSelector == -2 && snapshot.hasData) ? snapshot.data!.timeWeightedStats[redSidePlayer].nerdStats.cheese :
|
||||||
|
roundSelector.isNegative ? widget.record.endContext.firstWhere((element) => element.userId != widget.initPlayerId).nerdStats.cheese : widget.record.endContext.firstWhere((element) => element.userId != widget.initPlayerId).nerdStatsTracking[roundSelector].cheese,
|
||||||
fractionDigits: 2,
|
fractionDigits: 2,
|
||||||
higherIsBetter: true,
|
higherIsBetter: false,
|
||||||
),
|
),
|
||||||
CompareThingy(
|
CompareThingy(
|
||||||
label: "Gb Eff.",
|
label: "Gb Eff.",
|
||||||
greenSide: roundSelector.isNegative ? widget.record.endContext.firstWhere((element) => element.userId == widget.initPlayerId).nerdStats.gbe : widget.record.endContext.firstWhere((element) => element.userId == widget.initPlayerId).nerdStatsTracking[roundSelector].gbe,
|
greenSide: (roundSelector == -2 && snapshot.hasData) ? snapshot.data!.timeWeightedStats[greenSidePlayer].nerdStats.gbe :
|
||||||
redSide: roundSelector.isNegative ? widget.record.endContext.firstWhere((element) => element.userId != widget.initPlayerId).nerdStats.gbe : widget.record.endContext.firstWhere((element) => element.userId != widget.initPlayerId).nerdStatsTracking[roundSelector].gbe,
|
roundSelector.isNegative ? widget.record.endContext.firstWhere((element) => element.userId == widget.initPlayerId).nerdStats.gbe : widget.record.endContext.firstWhere((element) => element.userId == widget.initPlayerId).nerdStatsTracking[roundSelector].gbe,
|
||||||
|
redSide: (roundSelector == -2 && snapshot.hasData) ? snapshot.data!.timeWeightedStats[redSidePlayer].nerdStats.gbe :
|
||||||
|
roundSelector.isNegative ? widget.record.endContext.firstWhere((element) => element.userId != widget.initPlayerId).nerdStats.gbe : widget.record.endContext.firstWhere((element) => element.userId != widget.initPlayerId).nerdStatsTracking[roundSelector].gbe,
|
||||||
fractionDigits: 3,
|
fractionDigits: 3,
|
||||||
higherIsBetter: true,
|
higherIsBetter: true,
|
||||||
),
|
),
|
||||||
CompareThingy(
|
CompareThingy(
|
||||||
label: "wAPP",
|
label: "wAPP",
|
||||||
greenSide: roundSelector.isNegative ? widget.record.endContext.firstWhere((element) => element.userId == widget.initPlayerId).nerdStats.nyaapp : widget.record.endContext.firstWhere((element) => element.userId == widget.initPlayerId).nerdStatsTracking[roundSelector].nyaapp,
|
greenSide: (roundSelector == -2 && snapshot.hasData) ? snapshot.data!.timeWeightedStats[greenSidePlayer].nerdStats.nyaapp :
|
||||||
redSide: roundSelector.isNegative ? widget.record.endContext.firstWhere((element) => element.userId != widget.initPlayerId).nerdStats.nyaapp : widget.record.endContext.firstWhere((element) => element.userId != widget.initPlayerId).nerdStatsTracking[roundSelector].nyaapp,
|
roundSelector.isNegative ? widget.record.endContext.firstWhere((element) => element.userId == widget.initPlayerId).nerdStats.nyaapp : widget.record.endContext.firstWhere((element) => element.userId == widget.initPlayerId).nerdStatsTracking[roundSelector].nyaapp,
|
||||||
|
redSide: (roundSelector == -2 && snapshot.hasData) ? snapshot.data!.timeWeightedStats[redSidePlayer].nerdStats.nyaapp :
|
||||||
|
roundSelector.isNegative ? widget.record.endContext.firstWhere((element) => element.userId != widget.initPlayerId).nerdStats.nyaapp : widget.record.endContext.firstWhere((element) => element.userId != widget.initPlayerId).nerdStatsTracking[roundSelector].nyaapp,
|
||||||
fractionDigits: 3,
|
fractionDigits: 3,
|
||||||
higherIsBetter: true,
|
higherIsBetter: true,
|
||||||
),
|
),
|
||||||
CompareThingy(
|
CompareThingy(
|
||||||
label: "Area",
|
label: "Area",
|
||||||
greenSide: roundSelector.isNegative ? widget.record.endContext.firstWhere((element) => element.userId == widget.initPlayerId).nerdStats.area : widget.record.endContext.firstWhere((element) => element.userId == widget.initPlayerId).nerdStatsTracking[roundSelector].area,
|
greenSide: (roundSelector == -2 && snapshot.hasData) ? snapshot.data!.timeWeightedStats[greenSidePlayer].nerdStats.area :
|
||||||
redSide: roundSelector.isNegative ? widget.record.endContext.firstWhere((element) => element.userId != widget.initPlayerId).nerdStats.area : widget.record.endContext.firstWhere((element) => element.userId != widget.initPlayerId).nerdStatsTracking[roundSelector].area,
|
roundSelector.isNegative ? widget.record.endContext.firstWhere((element) => element.userId == widget.initPlayerId).nerdStats.area : widget.record.endContext.firstWhere((element) => element.userId == widget.initPlayerId).nerdStatsTracking[roundSelector].area,
|
||||||
|
redSide: (roundSelector == -2 && snapshot.hasData) ? snapshot.data!.timeWeightedStats[redSidePlayer].nerdStats.area :
|
||||||
|
roundSelector.isNegative ? widget.record.endContext.firstWhere((element) => element.userId != widget.initPlayerId).nerdStats.area : widget.record.endContext.firstWhere((element) => element.userId != widget.initPlayerId).nerdStatsTracking[roundSelector].area,
|
||||||
fractionDigits: 2,
|
fractionDigits: 2,
|
||||||
higherIsBetter: true,
|
higherIsBetter: true,
|
||||||
),
|
),
|
||||||
CompareThingy(
|
CompareThingy(
|
||||||
label: t.statCellNum.estOfTRShort,
|
label: t.statCellNum.estOfTRShort,
|
||||||
greenSide: roundSelector.isNegative ? widget.record.endContext.firstWhere((element) => element.userId == widget.initPlayerId).estTr.esttr : widget.record.endContext.firstWhere((element) => element.userId == widget.initPlayerId).estTrTracking[roundSelector].esttr,
|
greenSide: (roundSelector == -2 && snapshot.hasData) ? snapshot.data!.timeWeightedStats[greenSidePlayer].estTr.esttr :
|
||||||
redSide: roundSelector.isNegative ? widget.record.endContext.firstWhere((element) => element.userId != widget.initPlayerId).estTr.esttr : widget.record.endContext.firstWhere((element) => element.userId != widget.initPlayerId).estTrTracking[roundSelector].esttr,
|
roundSelector.isNegative ? widget.record.endContext.firstWhere((element) => element.userId == widget.initPlayerId).estTr.esttr : widget.record.endContext.firstWhere((element) => element.userId == widget.initPlayerId).estTrTracking[roundSelector].esttr,
|
||||||
|
redSide: (roundSelector == -2 && snapshot.hasData) ? snapshot.data!.timeWeightedStats[redSidePlayer].estTr.esttr :
|
||||||
|
roundSelector.isNegative ? widget.record.endContext.firstWhere((element) => element.userId != widget.initPlayerId).estTr.esttr : widget.record.endContext.firstWhere((element) => element.userId != widget.initPlayerId).estTrTracking[roundSelector].esttr,
|
||||||
fractionDigits: 2,
|
fractionDigits: 2,
|
||||||
higherIsBetter: true,
|
higherIsBetter: true,
|
||||||
),
|
),
|
||||||
CompareThingy(
|
CompareThingy(
|
||||||
label: "Opener",
|
label: "Opener",
|
||||||
greenSide: roundSelector.isNegative ? widget.record.endContext.firstWhere((element) => element.userId == widget.initPlayerId).playstyle.opener : widget.record.endContext.firstWhere((element) => element.userId == widget.initPlayerId).playstyleTracking[roundSelector].opener,
|
greenSide: (roundSelector == -2 && snapshot.hasData) ? snapshot.data!.timeWeightedStats[greenSidePlayer].playstyle.opener :
|
||||||
redSide: roundSelector.isNegative ? widget.record.endContext.firstWhere((element) => element.userId != widget.initPlayerId).playstyle.opener : widget.record.endContext.firstWhere((element) => element.userId != widget.initPlayerId).playstyleTracking[roundSelector].opener,
|
roundSelector.isNegative ? widget.record.endContext.firstWhere((element) => element.userId == widget.initPlayerId).playstyle.opener : widget.record.endContext.firstWhere((element) => element.userId == widget.initPlayerId).playstyleTracking[roundSelector].opener,
|
||||||
|
redSide: (roundSelector == -2 && snapshot.hasData) ? snapshot.data!.timeWeightedStats[redSidePlayer].playstyle.opener :
|
||||||
|
roundSelector.isNegative ? widget.record.endContext.firstWhere((element) => element.userId != widget.initPlayerId).playstyle.opener : widget.record.endContext.firstWhere((element) => element.userId != widget.initPlayerId).playstyleTracking[roundSelector].opener,
|
||||||
fractionDigits: 3,
|
fractionDigits: 3,
|
||||||
higherIsBetter: true,
|
higherIsBetter: true,
|
||||||
),
|
),
|
||||||
CompareThingy(
|
CompareThingy(
|
||||||
label: "Plonk",
|
label: "Plonk",
|
||||||
greenSide: roundSelector.isNegative ? widget.record.endContext.firstWhere((element) => element.userId == widget.initPlayerId).playstyle.plonk : widget.record.endContext.firstWhere((element) => element.userId == widget.initPlayerId).playstyleTracking[roundSelector].plonk,
|
greenSide: (roundSelector == -2 && snapshot.hasData) ? snapshot.data!.timeWeightedStats[greenSidePlayer].playstyle.plonk :
|
||||||
redSide: roundSelector.isNegative ? widget.record.endContext.firstWhere((element) => element.userId != widget.initPlayerId).playstyle.plonk : widget.record.endContext.firstWhere((element) => element.userId != widget.initPlayerId).playstyleTracking[roundSelector].plonk,
|
roundSelector.isNegative ? widget.record.endContext.firstWhere((element) => element.userId == widget.initPlayerId).playstyle.plonk : widget.record.endContext.firstWhere((element) => element.userId == widget.initPlayerId).playstyleTracking[roundSelector].plonk,
|
||||||
|
redSide: (roundSelector == -2 && snapshot.hasData) ? snapshot.data!.timeWeightedStats[redSidePlayer].playstyle.plonk :
|
||||||
|
roundSelector.isNegative ? widget.record.endContext.firstWhere((element) => element.userId != widget.initPlayerId).playstyle.plonk : widget.record.endContext.firstWhere((element) => element.userId != widget.initPlayerId).playstyleTracking[roundSelector].plonk,
|
||||||
fractionDigits: 3,
|
fractionDigits: 3,
|
||||||
higherIsBetter: true,
|
higherIsBetter: true,
|
||||||
),
|
),
|
||||||
CompareThingy(
|
CompareThingy(
|
||||||
label: "Stride",
|
label: "Stride",
|
||||||
greenSide: roundSelector.isNegative ? widget.record.endContext.firstWhere((element) => element.userId == widget.initPlayerId).playstyle.stride : widget.record.endContext.firstWhere((element) => element.userId == widget.initPlayerId).playstyleTracking[roundSelector].stride,
|
greenSide: (roundSelector == -2 && snapshot.hasData) ? snapshot.data!.timeWeightedStats[greenSidePlayer].playstyle.stride :
|
||||||
redSide: roundSelector.isNegative ? widget.record.endContext.firstWhere((element) => element.userId != widget.initPlayerId).playstyle.stride : widget.record.endContext.firstWhere((element) => element.userId != widget.initPlayerId).playstyleTracking[roundSelector].stride,
|
roundSelector.isNegative ? widget.record.endContext.firstWhere((element) => element.userId == widget.initPlayerId).playstyle.stride : widget.record.endContext.firstWhere((element) => element.userId == widget.initPlayerId).playstyleTracking[roundSelector].stride,
|
||||||
|
redSide: (roundSelector == -2 && snapshot.hasData) ? snapshot.data!.timeWeightedStats[redSidePlayer].playstyle.stride :
|
||||||
|
roundSelector.isNegative ? widget.record.endContext.firstWhere((element) => element.userId != widget.initPlayerId).playstyle.stride : widget.record.endContext.firstWhere((element) => element.userId != widget.initPlayerId).playstyleTracking[roundSelector].stride,
|
||||||
fractionDigits: 3,
|
fractionDigits: 3,
|
||||||
higherIsBetter: true,
|
higherIsBetter: true,
|
||||||
),
|
),
|
||||||
CompareThingy(
|
CompareThingy(
|
||||||
label: "Inf. DS",
|
label: "Inf. DS",
|
||||||
greenSide: roundSelector.isNegative ? widget.record.endContext.firstWhere((element) => element.userId == widget.initPlayerId).playstyle.infds : widget.record.endContext.firstWhere((element) => element.userId == widget.initPlayerId).playstyleTracking[roundSelector].infds,
|
greenSide: (roundSelector == -2 && snapshot.hasData) ? snapshot.data!.timeWeightedStats[greenSidePlayer].playstyle.infds :
|
||||||
redSide: roundSelector.isNegative ? widget.record.endContext.firstWhere((element) => element.userId != widget.initPlayerId).playstyle.infds : widget.record.endContext.firstWhere((element) => element.userId != widget.initPlayerId).playstyleTracking[roundSelector].infds,
|
roundSelector.isNegative ? widget.record.endContext.firstWhere((element) => element.userId == widget.initPlayerId).playstyle.infds : widget.record.endContext.firstWhere((element) => element.userId == widget.initPlayerId).playstyleTracking[roundSelector].infds,
|
||||||
|
redSide: (roundSelector == -2 && snapshot.hasData) ? snapshot.data!.timeWeightedStats[redSidePlayer].playstyle.infds :
|
||||||
|
roundSelector.isNegative ? widget.record.endContext.firstWhere((element) => element.userId != widget.initPlayerId).playstyle.infds : widget.record.endContext.firstWhere((element) => element.userId != widget.initPlayerId).playstyleTracking[roundSelector].infds,
|
||||||
fractionDigits: 3,
|
fractionDigits: 3,
|
||||||
higherIsBetter: true,
|
higherIsBetter: true,
|
||||||
),
|
),
|
||||||
VsGraphs(
|
VsGraphs(
|
||||||
roundSelector.isNegative ? widget.record.endContext.firstWhere((element) => element.userId == widget.initPlayerId).secondary : widget.record.endContext.firstWhere((element) => element.userId == widget.initPlayerId).secondaryTracking[roundSelector],
|
(roundSelector == -2 && snapshot.hasData) ? snapshot.data!.timeWeightedStats[greenSidePlayer].apm : roundSelector.isNegative ? widget.record.endContext.firstWhere((element) => element.userId == widget.initPlayerId).secondary : widget.record.endContext.firstWhere((element) => element.userId == widget.initPlayerId).secondaryTracking[roundSelector],
|
||||||
roundSelector.isNegative ? widget.record.endContext.firstWhere((element) => element.userId == widget.initPlayerId).tertiary : widget.record.endContext.firstWhere((element) => element.userId == widget.initPlayerId).tertiaryTracking[roundSelector],
|
(roundSelector == -2 && snapshot.hasData) ? snapshot.data!.timeWeightedStats[greenSidePlayer].pps : roundSelector.isNegative ? widget.record.endContext.firstWhere((element) => element.userId == widget.initPlayerId).tertiary : widget.record.endContext.firstWhere((element) => element.userId == widget.initPlayerId).tertiaryTracking[roundSelector],
|
||||||
roundSelector.isNegative ? widget.record.endContext.firstWhere((element) => element.userId == widget.initPlayerId).extra : widget.record.endContext.firstWhere((element) => element.userId == widget.initPlayerId).extraTracking[roundSelector],
|
(roundSelector == -2 && snapshot.hasData) ? snapshot.data!.timeWeightedStats[greenSidePlayer].vs : roundSelector.isNegative ? widget.record.endContext.firstWhere((element) => element.userId == widget.initPlayerId).extra : widget.record.endContext.firstWhere((element) => element.userId == widget.initPlayerId).extraTracking[roundSelector],
|
||||||
roundSelector.isNegative ? widget.record.endContext.firstWhere((element) => element.userId == widget.initPlayerId).nerdStats : widget.record.endContext.firstWhere((element) => element.userId == widget.initPlayerId).nerdStatsTracking[roundSelector],
|
(roundSelector == -2 && snapshot.hasData) ? snapshot.data!.timeWeightedStats[greenSidePlayer].nerdStats : roundSelector.isNegative ? widget.record.endContext.firstWhere((element) => element.userId == widget.initPlayerId).nerdStats : widget.record.endContext.firstWhere((element) => element.userId == widget.initPlayerId).nerdStatsTracking[roundSelector],
|
||||||
roundSelector.isNegative ? widget.record.endContext.firstWhere((element) => element.userId == widget.initPlayerId).playstyle : widget.record.endContext.firstWhere((element) => element.userId == widget.initPlayerId).playstyleTracking[roundSelector],
|
(roundSelector == -2 && snapshot.hasData) ? snapshot.data!.timeWeightedStats[greenSidePlayer].playstyle : roundSelector.isNegative ? widget.record.endContext.firstWhere((element) => element.userId == widget.initPlayerId).playstyle : widget.record.endContext.firstWhere((element) => element.userId == widget.initPlayerId).playstyleTracking[roundSelector],
|
||||||
roundSelector.isNegative ? widget.record.endContext.firstWhere((element) => element.userId != widget.initPlayerId).secondary : widget.record.endContext.firstWhere((element) => element.userId != widget.initPlayerId).secondaryTracking[roundSelector],
|
(roundSelector == -2 && snapshot.hasData) ? snapshot.data!.timeWeightedStats[redSidePlayer].apm : roundSelector.isNegative ? widget.record.endContext.firstWhere((element) => element.userId != widget.initPlayerId).secondary : widget.record.endContext.firstWhere((element) => element.userId != widget.initPlayerId).secondaryTracking[roundSelector],
|
||||||
roundSelector.isNegative ? widget.record.endContext.firstWhere((element) => element.userId != widget.initPlayerId).tertiary : widget.record.endContext.firstWhere((element) => element.userId != widget.initPlayerId).tertiaryTracking[roundSelector],
|
(roundSelector == -2 && snapshot.hasData) ? snapshot.data!.timeWeightedStats[redSidePlayer].pps : roundSelector.isNegative ? widget.record.endContext.firstWhere((element) => element.userId != widget.initPlayerId).tertiary : widget.record.endContext.firstWhere((element) => element.userId != widget.initPlayerId).tertiaryTracking[roundSelector],
|
||||||
roundSelector.isNegative ? widget.record.endContext.firstWhere((element) => element.userId != widget.initPlayerId).extra : widget.record.endContext.firstWhere((element) => element.userId != widget.initPlayerId).extraTracking[roundSelector],
|
(roundSelector == -2 && snapshot.hasData) ? snapshot.data!.timeWeightedStats[redSidePlayer].vs : roundSelector.isNegative ? widget.record.endContext.firstWhere((element) => element.userId != widget.initPlayerId).extra : widget.record.endContext.firstWhere((element) => element.userId != widget.initPlayerId).extraTracking[roundSelector],
|
||||||
roundSelector.isNegative ? widget.record.endContext.firstWhere((element) => element.userId != widget.initPlayerId).nerdStats : widget.record.endContext.firstWhere((element) => element.userId != widget.initPlayerId).nerdStatsTracking[roundSelector],
|
(roundSelector == -2 && snapshot.hasData) ? snapshot.data!.timeWeightedStats[redSidePlayer].nerdStats : roundSelector.isNegative ? widget.record.endContext.firstWhere((element) => element.userId != widget.initPlayerId).nerdStats : widget.record.endContext.firstWhere((element) => element.userId != widget.initPlayerId).nerdStatsTracking[roundSelector],
|
||||||
roundSelector.isNegative ? widget.record.endContext.firstWhere((element) => element.userId != widget.initPlayerId).playstyle : widget.record.endContext.firstWhere((element) => element.userId != widget.initPlayerId).playstyleTracking[roundSelector]
|
(roundSelector == -2 && snapshot.hasData) ? snapshot.data!.timeWeightedStats[redSidePlayer].playstyle : roundSelector.isNegative ? widget.record.endContext.firstWhere((element) => element.userId != widget.initPlayerId).playstyle : widget.record.endContext.firstWhere((element) => element.userId != widget.initPlayerId).playstyleTracking[roundSelector]
|
||||||
)
|
)
|
||||||
],
|
],
|
||||||
),
|
),
|
||||||
|
@ -507,8 +476,268 @@ class TlMatchResultState extends State<TlMatchResultView> {
|
||||||
)
|
)
|
||||||
],
|
],
|
||||||
)
|
)
|
||||||
|
);
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
Widget buildRoundSelector(double width){
|
||||||
|
return Padding(
|
||||||
|
padding: const EdgeInsets.all(8.000000),
|
||||||
|
child: SizedBox(
|
||||||
|
width: width,
|
||||||
|
child: NestedScrollView(
|
||||||
|
headerSliverBuilder: (BuildContext context, bool innerBoxIsScrolled) {
|
||||||
|
return [
|
||||||
|
SliverToBoxAdapter(child:
|
||||||
|
Wrap(
|
||||||
|
alignment: WrapAlignment.spaceBetween,
|
||||||
|
children: [
|
||||||
|
FutureBuilder(future: replayData, builder: (context, snapshot) {
|
||||||
|
switch(snapshot.connectionState){
|
||||||
|
case ConnectionState.none:
|
||||||
|
case ConnectionState.waiting:
|
||||||
|
case ConnectionState.active:
|
||||||
|
return const CircularProgressIndicator();
|
||||||
|
case ConnectionState.done:
|
||||||
|
if (!snapshot.hasError){
|
||||||
|
var time = framesToTime(snapshot.data!.totalLength);
|
||||||
|
return Column(
|
||||||
|
crossAxisAlignment: CrossAxisAlignment.start,
|
||||||
|
children: [
|
||||||
|
Text(t.matchLength),
|
||||||
|
RichText(
|
||||||
|
text: TextSpan(
|
||||||
|
text: "${time.inMinutes}:${NumberFormat("00", LocaleSettings.currentLocale.languageCode).format(time.inSeconds%60)}",
|
||||||
|
style: const TextStyle(fontFamily: "Eurostile Round Extended", fontSize: 28, fontWeight: FontWeight.w500, color: Colors.white),
|
||||||
|
children: [TextSpan(text: ".${NumberFormat("000", LocaleSettings.currentLocale.languageCode).format(time.inMilliseconds%1000)}", style: const TextStyle(fontFamily: "Eurostile Round", fontSize: 14, fontWeight: FontWeight.w100))]
|
||||||
),
|
),
|
||||||
|
)
|
||||||
|
],);
|
||||||
|
}else{
|
||||||
|
String reason;
|
||||||
|
switch (snapshot.error.runtimeType){
|
||||||
|
case ReplayNotAvalable:
|
||||||
|
reason = t.matchIsTooOld;
|
||||||
|
break;
|
||||||
|
case SzyNotFound:
|
||||||
|
reason = t.matchIsTooOld;
|
||||||
|
break;
|
||||||
|
case SzyForbidden:
|
||||||
|
reason = t.errors.replayRejected;
|
||||||
|
break;
|
||||||
|
case SzyTooManyRequests:
|
||||||
|
reason = t.errors.tooManyRequests;
|
||||||
|
break;
|
||||||
|
default:
|
||||||
|
reason = snapshot.error.toString();
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
timeWeightedStatsAvaliable = false;
|
||||||
|
return Column(
|
||||||
|
crossAxisAlignment: CrossAxisAlignment.start,
|
||||||
|
children: [
|
||||||
|
if (widget.record.ownId != widget.record.replayId) Text("${t.replayIssue}: $reason"),
|
||||||
|
if (widget.record.ownId == widget.record.replayId) Center(child: Text(t.p1nkl0bst3rAlert, textAlign: TextAlign.center)),
|
||||||
|
if (widget.record.ownId != widget.record.replayId) RichText(
|
||||||
|
text: const TextSpan(
|
||||||
|
text: "-:--",
|
||||||
|
style: TextStyle(fontFamily: "Eurostile Round Extended", fontSize: 28, fontWeight: FontWeight.w500, color: Colors.grey),
|
||||||
|
children: [TextSpan(text: ".---", style: TextStyle(fontFamily: "Eurostile Round", fontSize: 14, fontWeight: FontWeight.w100))]
|
||||||
|
),
|
||||||
|
)
|
||||||
|
],);
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
},),
|
||||||
|
if (widget.record.ownId != widget.record.replayId) Column(
|
||||||
|
crossAxisAlignment: CrossAxisAlignment.end,
|
||||||
|
children: [
|
||||||
|
Text(t.numberOfRounds),
|
||||||
|
RichText(
|
||||||
|
text: TextSpan(
|
||||||
|
text: widget.record.endContext.first.secondaryTracking.isNotEmpty ? widget.record.endContext.first.secondaryTracking.length.toString() : "---",
|
||||||
|
style: TextStyle(
|
||||||
|
fontFamily: "Eurostile Round Extended",
|
||||||
|
fontSize: 28,
|
||||||
|
fontWeight: FontWeight.w500,
|
||||||
|
color: widget.record.endContext.first.secondaryTracking.isEmpty ? Colors.grey : Colors.white
|
||||||
|
),
|
||||||
|
),
|
||||||
|
)
|
||||||
|
],),
|
||||||
|
Column(children: [
|
||||||
|
OverflowBar(
|
||||||
|
alignment: MainAxisAlignment.spaceEvenly,
|
||||||
|
children: <Widget>[
|
||||||
|
TextButton( style: roundSelector == -1 ? ButtonStyle(backgroundColor: MaterialStatePropertyAll(Colors.grey.shade900)) : null,
|
||||||
|
onPressed: () {
|
||||||
|
roundSelector = -1;
|
||||||
|
setState(() {});
|
||||||
|
}, child: Text(t.matchStats)),
|
||||||
|
TextButton( style: roundSelector == -2 ? ButtonStyle(backgroundColor: MaterialStatePropertyAll(Colors.grey.shade900)) : null,
|
||||||
|
onPressed: timeWeightedStatsAvaliable ? () {
|
||||||
|
roundSelector = -2;
|
||||||
|
setState(() {});
|
||||||
|
} : null, child: Text(t.timeWeightedmatchStats)) ,
|
||||||
|
//TextButton( child: const Text('Button 3'), onPressed: () {}),
|
||||||
|
],
|
||||||
|
)
|
||||||
|
]),
|
||||||
|
// Column(
|
||||||
|
// children: [
|
||||||
|
// ListTile(
|
||||||
|
// leading: Text("Round time"),
|
||||||
|
// title: Text("Winner", textAlign: TextAlign.center,),
|
||||||
|
// trailing: Text("Round stats"),
|
||||||
|
// )
|
||||||
|
// ],
|
||||||
|
// )
|
||||||
|
],
|
||||||
|
)
|
||||||
|
)
|
||||||
|
];
|
||||||
|
},
|
||||||
|
body: ListView.builder(itemCount: widget.record.endContext.first.secondaryTracking.length,
|
||||||
|
itemBuilder: (BuildContext context, int index) {
|
||||||
|
return FutureBuilder(future: replayData, builder: (context, snapshot) {
|
||||||
|
switch(snapshot.connectionState){
|
||||||
|
case ConnectionState.none:
|
||||||
|
case ConnectionState.waiting:
|
||||||
|
case ConnectionState.active:
|
||||||
|
return const LinearProgressIndicator();
|
||||||
|
case ConnectionState.done:
|
||||||
|
if (!snapshot.hasError){
|
||||||
|
var time = framesToTime(snapshot.data!.roundLengths[index]);
|
||||||
|
var accentColor = snapshot.data!.roundWinners[index][0] == widget.initPlayerId ? Colors.green : Colors.red;
|
||||||
|
var bgColor = roundSelector == index ? Colors.grey.shade900 : Colors.transparent;
|
||||||
|
return Container(
|
||||||
|
decoration: BoxDecoration(
|
||||||
|
gradient: LinearGradient(
|
||||||
|
stops: const [0, 0.05],
|
||||||
|
colors: [accentColor, bgColor]
|
||||||
|
)
|
||||||
|
),
|
||||||
|
child: ListTile(
|
||||||
|
leading:RichText(
|
||||||
|
text: TextSpan(
|
||||||
|
text: "${time.inMinutes}:${NumberFormat("00", LocaleSettings.currentLocale.languageCode).format(time.inSeconds%60)}",
|
||||||
|
style: const TextStyle(fontFamily: "Eurostile Round", fontSize: 22, fontWeight: FontWeight.w500, color: Colors.white),
|
||||||
|
children: [TextSpan(text: ".${NumberFormat("000", LocaleSettings.currentLocale.languageCode).format(time.inMilliseconds%1000)}", style: const TextStyle(fontFamily: "Eurostile Round", fontSize: 14, fontWeight: FontWeight.w100))]
|
||||||
|
),
|
||||||
|
),
|
||||||
|
title: Text(snapshot.data!.roundWinners[index][1], textAlign: TextAlign.center),
|
||||||
|
trailing: TrailingStats(
|
||||||
|
widget.record.endContext.firstWhere((element) => element.userId == widget.initPlayerId).secondaryTracking[index],
|
||||||
|
widget.record.endContext.firstWhere((element) => element.userId == widget.initPlayerId).tertiaryTracking[index],
|
||||||
|
widget.record.endContext.firstWhere((element) => element.userId == widget.initPlayerId).extraTracking[index],
|
||||||
|
widget.record.endContext.firstWhere((element) => element.userId != widget.initPlayerId).secondaryTracking[index],
|
||||||
|
widget.record.endContext.firstWhere((element) => element.userId != widget.initPlayerId).tertiaryTracking[index],
|
||||||
|
widget.record.endContext.firstWhere((element) => element.userId != widget.initPlayerId).extraTracking[index]
|
||||||
|
),
|
||||||
|
onTap:(){
|
||||||
|
roundSelector = index;
|
||||||
|
setState(() {});
|
||||||
|
},
|
||||||
|
),
|
||||||
|
);
|
||||||
|
}else{
|
||||||
|
return Container(
|
||||||
|
decoration: BoxDecoration(
|
||||||
|
color: roundSelector == index ? Colors.grey.shade900 : Colors.transparent
|
||||||
|
),
|
||||||
|
child: ListTile(
|
||||||
|
leading: RichText(
|
||||||
|
text: const TextSpan(
|
||||||
|
text: "-:--",
|
||||||
|
style: TextStyle(fontFamily: "Eurostile Round", fontSize: 22, fontWeight: FontWeight.w500, color: Colors.grey),
|
||||||
|
children: [TextSpan(text: ".---", style: TextStyle(fontFamily: "Eurostile Round", fontSize: 14, fontWeight: FontWeight.w100))]
|
||||||
|
),
|
||||||
|
),
|
||||||
|
title: const Text("---", style: TextStyle(color: Colors.grey), textAlign: TextAlign.center),
|
||||||
|
trailing: TrailingStats(
|
||||||
|
widget.record.endContext.firstWhere((element) => element.userId == widget.initPlayerId).secondaryTracking[index],
|
||||||
|
widget.record.endContext.firstWhere((element) => element.userId == widget.initPlayerId).tertiaryTracking[index],
|
||||||
|
widget.record.endContext.firstWhere((element) => element.userId == widget.initPlayerId).extraTracking[index],
|
||||||
|
widget.record.endContext.firstWhere((element) => element.userId != widget.initPlayerId).secondaryTracking[index],
|
||||||
|
widget.record.endContext.firstWhere((element) => element.userId != widget.initPlayerId).tertiaryTracking[index],
|
||||||
|
widget.record.endContext.firstWhere((element) => element.userId != widget.initPlayerId).extraTracking[index]
|
||||||
|
),
|
||||||
|
onTap:(){
|
||||||
|
roundSelector = index;
|
||||||
|
setState(() {});
|
||||||
|
},
|
||||||
),
|
),
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
);
|
||||||
|
})
|
||||||
|
),
|
||||||
|
),
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
Widget getMainWidget(double viewportWidth) {
|
||||||
|
if (viewportWidth <= 1200) {
|
||||||
|
return Center(
|
||||||
|
child: Container(
|
||||||
|
constraints: const BoxConstraints(maxWidth: 768),
|
||||||
|
child: buildComparison(viewportWidth > 768, true)
|
||||||
|
),
|
||||||
|
);
|
||||||
|
} else {
|
||||||
|
return Row(
|
||||||
|
mainAxisAlignment: MainAxisAlignment.center,
|
||||||
|
children: [
|
||||||
|
SizedBox(
|
||||||
|
width: 768,
|
||||||
|
child: buildComparison(true, false)
|
||||||
|
),
|
||||||
|
Container(
|
||||||
|
constraints: const BoxConstraints(maxWidth: 768),
|
||||||
|
child: buildRoundSelector(max(viewportWidth-768-16, 200)),
|
||||||
|
)
|
||||||
|
],
|
||||||
|
);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
@override
|
||||||
|
Widget build(BuildContext context) {
|
||||||
|
final t = Translations.of(context);
|
||||||
|
return Scaffold(
|
||||||
|
appBar: AppBar(
|
||||||
|
title: Text("${widget.record.endContext.firstWhere((element) => element.userId == widget.initPlayerId).username.toUpperCase()} ${t.vs} ${widget.record.endContext.firstWhere((element) => element.userId != widget.initPlayerId).username.toUpperCase()} ${t.inTLmatch} ${dateFormat.format(widget.record.timestamp)}"),
|
||||||
|
actions: [
|
||||||
|
PopupMenuButton(
|
||||||
|
enabled: widget.record.replayAvalable,
|
||||||
|
itemBuilder: (BuildContext context) => <PopupMenuEntry>[
|
||||||
|
PopupMenuItem(
|
||||||
|
value: 1,
|
||||||
|
child: Text(t.downloadReplay),
|
||||||
|
),
|
||||||
|
PopupMenuItem(
|
||||||
|
value: 2,
|
||||||
|
child: Text(t.openReplay),
|
||||||
|
),
|
||||||
|
],
|
||||||
|
onSelected: (value) async {
|
||||||
|
switch (value) {
|
||||||
|
case 1:
|
||||||
|
await launchInBrowser(Uri.parse("https://inoue.szy.lol/api/replay/${widget.record.replayId}"));
|
||||||
|
break;
|
||||||
|
case 2:
|
||||||
|
await launchInBrowser(Uri.parse("https://tetr.io/#r:${widget.record.replayId}"));
|
||||||
|
break;
|
||||||
|
default:
|
||||||
|
}
|
||||||
|
})
|
||||||
|
]
|
||||||
|
),
|
||||||
|
backgroundColor: Colors.black,
|
||||||
|
body: getMainWidget(MediaQuery.of(context).size.width),
|
||||||
|
);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
|
@ -0,0 +1,47 @@
|
||||||
|
import 'package:flutter/material.dart';
|
||||||
|
import 'package:tetra_stats/data_objects/tetrio.dart';
|
||||||
|
import 'package:tetra_stats/utils/numers_formats.dart';
|
||||||
|
import 'package:tetra_stats/utils/text_shadow.dart';
|
||||||
|
|
||||||
|
class FinesseThingy extends StatelessWidget{
|
||||||
|
final Finesse? finesse;
|
||||||
|
final double? finessePercentage;
|
||||||
|
|
||||||
|
const FinesseThingy(this.finesse, this.finessePercentage, {super.key});
|
||||||
|
|
||||||
|
Color getFinesseColor(){
|
||||||
|
if (finesse == null) return Colors.grey;
|
||||||
|
if (finesse!.faults == 0) return Colors.purpleAccent;
|
||||||
|
if (finessePercentage! > 0.4) return Colors.white;
|
||||||
|
else return Colors.redAccent;
|
||||||
|
}
|
||||||
|
|
||||||
|
@override
|
||||||
|
Widget build(BuildContext context) {
|
||||||
|
return Stack(
|
||||||
|
alignment: AlignmentDirectional.bottomStart,
|
||||||
|
children: [
|
||||||
|
Text("f", style: TextStyle(
|
||||||
|
fontStyle: FontStyle.italic,
|
||||||
|
fontSize: 65,
|
||||||
|
height: 1.2,
|
||||||
|
)),
|
||||||
|
Positioned(child: Text("inesse", style: TextStyle(fontFamily: "Eurostile Round Extended")), left: 25, top: 20),
|
||||||
|
Positioned(
|
||||||
|
child: Text("${finesse != null ? finesse!.faults : "---"}F", style: TextStyle(
|
||||||
|
color: getFinesseColor()
|
||||||
|
)), right: 0, top: 20),
|
||||||
|
Padding(
|
||||||
|
padding: const EdgeInsets.only(left: 10.0),
|
||||||
|
child: Text("${finesse != null ? f2.format(finessePercentage! * 100) : "---.--"}%", style: TextStyle(
|
||||||
|
shadows: textShadow,
|
||||||
|
fontFamily: "Eurostile Round Extended",
|
||||||
|
fontSize: 36,
|
||||||
|
fontWeight: FontWeight.w500,
|
||||||
|
color: getFinesseColor()
|
||||||
|
)),
|
||||||
|
)
|
||||||
|
],
|
||||||
|
);
|
||||||
|
}
|
||||||
|
}
|
|
@ -0,0 +1,110 @@
|
||||||
|
import 'package:flutter/material.dart';
|
||||||
|
import 'package:syncfusion_flutter_gauges/gauges.dart';
|
||||||
|
import 'package:tetra_stats/data_objects/tetrio.dart';
|
||||||
|
import 'package:tetra_stats/gen/strings.g.dart';
|
||||||
|
import 'package:tetra_stats/utils/colors_functions.dart';
|
||||||
|
import 'package:tetra_stats/utils/numers_formats.dart';
|
||||||
|
import 'package:tetra_stats/widgets/tl_thingy.dart';
|
||||||
|
|
||||||
|
class GaugetNum extends StatelessWidget {
|
||||||
|
final num playerStat;
|
||||||
|
final num? oldPlayerStat;
|
||||||
|
final bool higherIsBetter;
|
||||||
|
final List<GaugeRange> ranges;
|
||||||
|
final double minimum;
|
||||||
|
final double maximum;
|
||||||
|
final String playerStatLabel;
|
||||||
|
final String? okText;
|
||||||
|
final String? alertTitle;
|
||||||
|
final List<Widget>? alertWidgets;
|
||||||
|
final LeaderboardPosition? pos;
|
||||||
|
final num? averageStat;
|
||||||
|
|
||||||
|
const GaugetNum(
|
||||||
|
{super.key,
|
||||||
|
required this.playerStat,
|
||||||
|
required this.playerStatLabel,
|
||||||
|
this.alertWidgets,
|
||||||
|
this.oldPlayerStat,
|
||||||
|
required this.higherIsBetter,
|
||||||
|
required this.minimum,
|
||||||
|
required this.maximum,
|
||||||
|
required this.ranges,
|
||||||
|
this.okText, this.alertTitle, this.pos, this.averageStat});
|
||||||
|
|
||||||
|
Color getStatColor(){
|
||||||
|
if (averageStat == null) return Colors.white;
|
||||||
|
num percentile = (higherIsBetter ? playerStat / averageStat! : averageStat! / playerStat).abs();
|
||||||
|
if (percentile > 1.50) return Colors.purpleAccent;
|
||||||
|
else if (percentile > 1.20) return Colors.blueAccent;
|
||||||
|
else if (percentile > 0.90) return Colors.greenAccent;
|
||||||
|
else if (percentile > 0.70) return Colors.yellowAccent;
|
||||||
|
else return Colors.redAccent;
|
||||||
|
}
|
||||||
|
|
||||||
|
@override
|
||||||
|
Widget build(BuildContext context) {
|
||||||
|
return SizedBox(
|
||||||
|
width: 200,
|
||||||
|
height: 120,
|
||||||
|
child: SfRadialGauge(
|
||||||
|
title: GaugeTitle(text: playerStatLabel),
|
||||||
|
axes: [RadialAxis(
|
||||||
|
startAngle: 180,
|
||||||
|
endAngle: 360,
|
||||||
|
showLabels: false,
|
||||||
|
showTicks: false,
|
||||||
|
radiusFactor: 2.1,
|
||||||
|
centerY: 0.5,
|
||||||
|
minimum: minimum,
|
||||||
|
maximum: maximum,
|
||||||
|
ranges: ranges,
|
||||||
|
pointers: [
|
||||||
|
NeedlePointer(
|
||||||
|
value: playerStat as double,
|
||||||
|
enableAnimation: true,
|
||||||
|
needleLength: 0.9,
|
||||||
|
needleStartWidth: 2,
|
||||||
|
needleEndWidth: 15,
|
||||||
|
knobStyle: const KnobStyle(color: Colors.transparent),
|
||||||
|
gradient: const LinearGradient(colors: [Colors.transparent, Colors.white], begin: Alignment.bottomCenter, end: Alignment.topCenter, stops: [0.5, 1]),)
|
||||||
|
],
|
||||||
|
annotations: [GaugeAnnotation(
|
||||||
|
widget: TextButton(child: Text(f3.format(playerStat),
|
||||||
|
style: TextStyle(fontFamily: "Eurostile Round Extended", fontSize: 36, color: getStatColor())),
|
||||||
|
onPressed: (){
|
||||||
|
showDialog(
|
||||||
|
context: context,
|
||||||
|
builder: (BuildContext context) => AlertDialog(
|
||||||
|
title: Text(alertTitle??playerStatLabel, style: const TextStyle(fontFamily: "Eurostile Round Extended")),
|
||||||
|
content: SingleChildScrollView(child: ListBody(children: alertWidgets!)),
|
||||||
|
actions: <Widget>[
|
||||||
|
TextButton(
|
||||||
|
child: Text(okText??t.popupActions.ok),
|
||||||
|
onPressed: () {
|
||||||
|
Navigator.of(context).pop();
|
||||||
|
},
|
||||||
|
)
|
||||||
|
],
|
||||||
|
));
|
||||||
|
},), verticalAlignment: GaugeAlignment.far, positionFactor: 0.05),
|
||||||
|
if (oldPlayerStat != null || pos != null) GaugeAnnotation(
|
||||||
|
widget: RichText(text: TextSpan(
|
||||||
|
text: "",
|
||||||
|
style: const TextStyle(fontFamily: "Eurostile Round", fontSize: 14, color: Colors.grey),
|
||||||
|
children: [
|
||||||
|
if (oldPlayerStat != null) TextSpan(text: comparef.format(playerStat - oldPlayerStat!), style: TextStyle(
|
||||||
|
color: higherIsBetter ?
|
||||||
|
oldPlayerStat! > playerStat ? Colors.redAccent : Colors.greenAccent :
|
||||||
|
oldPlayerStat! < playerStat ? Colors.redAccent : Colors.greenAccent
|
||||||
|
),),
|
||||||
|
if ((oldTl != null && oldTl!.gamesPlayed > 0) && pos != null) const TextSpan(text: " • "),
|
||||||
|
if (pos != null) TextSpan(text: pos!.position >= 1000 ? "${t.top} ${f2.format(pos!.percentage*100)}%" : "№${pos!.position}", style: TextStyle(color: getColorOfRank(pos!.position)))
|
||||||
|
]
|
||||||
|
),
|
||||||
|
),
|
||||||
|
positionFactor: 0.05)],
|
||||||
|
)],),
|
||||||
|
);
|
||||||
|
}
|
||||||
|
}
|
|
@ -1,10 +1,7 @@
|
||||||
import 'package:fl_chart/fl_chart.dart';
|
import 'package:fl_chart/fl_chart.dart';
|
||||||
import 'package:flutter/material.dart';
|
import 'package:flutter/material.dart';
|
||||||
import 'package:intl/intl.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/utils/numers_formats.dart';
|
||||||
|
|
||||||
final NumberFormat _f2 = NumberFormat.decimalPatternDigits(locale: LocaleSettings.currentLocale.languageCode, decimalDigits: 2);
|
|
||||||
|
|
||||||
class Graphs extends StatelessWidget{
|
class Graphs extends StatelessWidget{
|
||||||
const Graphs(
|
const Graphs(
|
||||||
|
@ -125,13 +122,13 @@ class Graphs extends StatelessWidget{
|
||||||
getTitle: (index, angle) {
|
getTitle: (index, angle) {
|
||||||
switch (index) {
|
switch (index) {
|
||||||
case 0:
|
case 0:
|
||||||
return RadarChartTitle(text: 'Opener\n${_f2.format(playstyle.opener)}', angle: 0, positionPercentageOffset: 0.05);
|
return RadarChartTitle(text: 'Opener\n${percentage.format(playstyle.opener)}', angle: 0, positionPercentageOffset: 0.05);
|
||||||
case 1:
|
case 1:
|
||||||
return RadarChartTitle(text: 'Stride\n${_f2.format(playstyle.stride)}', angle: 0, positionPercentageOffset: 0.05);
|
return RadarChartTitle(text: 'Stride\n${percentage.format(playstyle.stride)}', angle: 0, positionPercentageOffset: 0.05);
|
||||||
case 2:
|
case 2:
|
||||||
return RadarChartTitle(text: 'Inf Ds\n${_f2.format(playstyle.infds)}', angle: angle + 180, positionPercentageOffset: 0.05);
|
return RadarChartTitle(text: 'Inf Ds\n${percentage.format(playstyle.infds)}', angle: angle + 180, positionPercentageOffset: 0.05);
|
||||||
case 3:
|
case 3:
|
||||||
return RadarChartTitle(text: 'Plonk\n${_f2.format(playstyle.plonk)}', angle: 0, positionPercentageOffset: 0.05);
|
return RadarChartTitle(text: 'Plonk\n${percentage.format(playstyle.plonk)}', angle: 0, positionPercentageOffset: 0.05);
|
||||||
default:
|
default:
|
||||||
return const RadarChartTitle(text: '');
|
return const RadarChartTitle(text: '');
|
||||||
}
|
}
|
||||||
|
|
|
@ -0,0 +1,52 @@
|
||||||
|
import 'package:flutter/material.dart';
|
||||||
|
import 'package:tetra_stats/data_objects/tetrio.dart';
|
||||||
|
import 'package:tetra_stats/gen/strings.g.dart';
|
||||||
|
|
||||||
|
class LineclearsThingy extends StatelessWidget{
|
||||||
|
final Clears clears;
|
||||||
|
final int lines;
|
||||||
|
final int holds;
|
||||||
|
final int tSpins;
|
||||||
|
|
||||||
|
const LineclearsThingy(this.clears, this.lines, this.holds, this.tSpins, {super.key});
|
||||||
|
|
||||||
|
@override
|
||||||
|
Widget build(BuildContext context) {
|
||||||
|
return Wrap(
|
||||||
|
spacing: 20,
|
||||||
|
children: [
|
||||||
|
SizedBox(
|
||||||
|
width: 150,
|
||||||
|
child: Column(
|
||||||
|
mainAxisSize: MainAxisSize.min,
|
||||||
|
children: [
|
||||||
|
Text(t.numOfGameActions.lineClears(n: lines), style: const TextStyle(color: Colors.white, fontFamily: "Eurostile Round Extended"), textAlign: TextAlign.center),
|
||||||
|
Row(mainAxisAlignment: MainAxisAlignment.spaceBetween, children: [const Text("Quads"), Text(clears.quads.toString())]),
|
||||||
|
Row(mainAxisAlignment: MainAxisAlignment.spaceBetween, children: [const Text("Triples"), Text(clears.triples.toString())]),
|
||||||
|
Row(mainAxisAlignment: MainAxisAlignment.spaceBetween, children: [const Text("Doubles"), Text(clears.doubles.toString())]),
|
||||||
|
Row(mainAxisAlignment: MainAxisAlignment.spaceBetween, children: [const Text("Singles"), Text(clears.singles.toString())]),
|
||||||
|
Row(mainAxisAlignment: MainAxisAlignment.spaceBetween, children: [Text("\n${t.numOfGameActions.pc}"), Text("\n${clears.allClears.toString()}")]),
|
||||||
|
Row(mainAxisAlignment: MainAxisAlignment.spaceBetween, children: [Text(t.numOfGameActions.hold), Text(holds.toString())]),
|
||||||
|
],
|
||||||
|
),
|
||||||
|
),
|
||||||
|
SizedBox(
|
||||||
|
width: 150,
|
||||||
|
child: Column(
|
||||||
|
mainAxisSize: MainAxisSize.min,
|
||||||
|
children: [
|
||||||
|
Text(t.numOfGameActions.tspinsTotal(n: tSpins), style: const TextStyle(color: Colors.white, fontFamily: "Eurostile Round Extended"), textAlign: TextAlign.center),
|
||||||
|
Row(mainAxisAlignment: MainAxisAlignment.spaceBetween, children: [const Text("T-spins triples"), Text(clears.tSpinTriples.toString())]),
|
||||||
|
Row(mainAxisAlignment: MainAxisAlignment.spaceBetween, children: [const Text("T-spins doubles"), Text(clears.tSpinDoubles.toString())]),
|
||||||
|
Row(mainAxisAlignment: MainAxisAlignment.spaceBetween, children: [const Text("T-spins singles"), Text(clears.tSpinSingles.toString())]),
|
||||||
|
Row(mainAxisAlignment: MainAxisAlignment.spaceBetween, children: [const Text("T-spins zeros"), Text(clears.tSpinZeros.toString())]),
|
||||||
|
Row(mainAxisAlignment: MainAxisAlignment.spaceBetween, children: [const Text("Mini T-spins doubles"), Text(clears.tSpinMiniDoubles.toString())]),
|
||||||
|
Row(mainAxisAlignment: MainAxisAlignment.spaceBetween, children: [const Text("Mini T-spins singles"), Text(clears.tSpinMiniSingles.toString())]),
|
||||||
|
Row(mainAxisAlignment: MainAxisAlignment.spaceBetween, children: [const Text("Mini T-spins zeros"), Text(clears.tSpinMiniZeros.toString())]),
|
||||||
|
],
|
||||||
|
),
|
||||||
|
),
|
||||||
|
],
|
||||||
|
);
|
||||||
|
}
|
||||||
|
}
|
|
@ -0,0 +1,32 @@
|
||||||
|
import 'package:flutter/material.dart';
|
||||||
|
import 'package:tetra_stats/utils/numers_formats.dart';
|
||||||
|
|
||||||
|
class TrailingStats extends StatelessWidget{
|
||||||
|
final double yourAPM;
|
||||||
|
final double yourPPS;
|
||||||
|
final double yourVS;
|
||||||
|
final double notyourAPM;
|
||||||
|
final double notyourPPS;
|
||||||
|
final double notyourVS;
|
||||||
|
|
||||||
|
const TrailingStats(this.yourAPM, this.yourPPS, this.yourVS, this.notyourAPM, this.notyourPPS, this.notyourVS, {super.key});
|
||||||
|
|
||||||
|
@override
|
||||||
|
Widget build(BuildContext context) {
|
||||||
|
const TextStyle style = TextStyle(height: 1.1, fontWeight: FontWeight.w100);
|
||||||
|
return Table(
|
||||||
|
defaultColumnWidth: const IntrinsicColumnWidth(),
|
||||||
|
defaultVerticalAlignment: TableCellVerticalAlignment.baseline,
|
||||||
|
textBaseline: TextBaseline.alphabetic,
|
||||||
|
columnWidths: const {
|
||||||
|
0: FixedColumnWidth(42),
|
||||||
|
2: FixedColumnWidth(42),
|
||||||
|
},
|
||||||
|
children: [
|
||||||
|
TableRow(children: [Text(f2.format(yourAPM), textAlign: TextAlign.right, style: style), const Text(" :", style: style), Text(f2.format(notyourAPM), textAlign: TextAlign.right, style: style), const Text(" APM", textAlign: TextAlign.right, style: style)]),
|
||||||
|
TableRow(children: [Text(f2.format(yourPPS), textAlign: TextAlign.right, style: style), const Text(" :", style: style), Text(f2.format(notyourPPS), textAlign: TextAlign.right, style: style), const Text(" PPS", textAlign: TextAlign.right, style: style)]),
|
||||||
|
TableRow(children: [Text(f2.format(yourVS), textAlign: TextAlign.right, style: style), const Text(" :", style: style), Text(f2.format(notyourVS), textAlign: TextAlign.right, style: style), const Text(" VS", textAlign: TextAlign.right, style: style)]),
|
||||||
|
],
|
||||||
|
);
|
||||||
|
}
|
||||||
|
}
|
|
@ -1,6 +1,9 @@
|
||||||
import 'package:flutter/material.dart';
|
import 'package:flutter/material.dart';
|
||||||
import 'package:intl/intl.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/gen/strings.g.dart';
|
||||||
|
import 'package:tetra_stats/utils/colors_functions.dart';
|
||||||
|
import 'package:tetra_stats/utils/numers_formats.dart';
|
||||||
|
|
||||||
class StatCellNum extends StatelessWidget {
|
class StatCellNum extends StatelessWidget {
|
||||||
const StatCellNum(
|
const StatCellNum(
|
||||||
|
@ -8,11 +11,12 @@ class StatCellNum extends StatelessWidget {
|
||||||
required this.playerStat,
|
required this.playerStat,
|
||||||
required this.playerStatLabel,
|
required this.playerStatLabel,
|
||||||
required this.isScreenBig,
|
required this.isScreenBig,
|
||||||
|
this.smallDecimal = true,
|
||||||
this.alertWidgets,
|
this.alertWidgets,
|
||||||
this.fractionDigits,
|
this.fractionDigits,
|
||||||
this.oldPlayerStat,
|
this.oldPlayerStat,
|
||||||
required this.higherIsBetter,
|
required this.higherIsBetter,
|
||||||
this.okText, this.alertTitle});
|
this.okText, this.alertTitle, this.pos, this.averageStat});
|
||||||
|
|
||||||
final num playerStat;
|
final num playerStat;
|
||||||
final num? oldPlayerStat;
|
final num? oldPlayerStat;
|
||||||
|
@ -20,39 +24,57 @@ class StatCellNum extends StatelessWidget {
|
||||||
final String playerStatLabel;
|
final String playerStatLabel;
|
||||||
final String? okText;
|
final String? okText;
|
||||||
final bool isScreenBig;
|
final bool isScreenBig;
|
||||||
|
final bool smallDecimal;
|
||||||
final String? alertTitle;
|
final String? alertTitle;
|
||||||
final List<Widget>? alertWidgets;
|
final List<Widget>? alertWidgets;
|
||||||
final int? fractionDigits;
|
final int? fractionDigits;
|
||||||
|
final LeaderboardPosition? pos;
|
||||||
|
final num? averageStat;
|
||||||
|
|
||||||
|
Color getStatColor(){
|
||||||
|
if (averageStat == null) return Colors.white;
|
||||||
|
num percentile = (higherIsBetter ? playerStat / averageStat! : averageStat! / playerStat).abs();
|
||||||
|
if (percentile > 1.50) return Colors.purpleAccent;
|
||||||
|
if (percentile > 1.20) return Colors.blueAccent;
|
||||||
|
if (percentile > 0.90) return Colors.greenAccent;
|
||||||
|
if (percentile > 0.70) return Colors.yellowAccent;
|
||||||
|
return Colors.redAccent;
|
||||||
|
}
|
||||||
|
|
||||||
@override
|
@override
|
||||||
Widget build(BuildContext context) {
|
Widget build(BuildContext context) {
|
||||||
NumberFormat comparef = NumberFormat("+#,###.###;-#,###.###")..maximumFractionDigits = fractionDigits ?? 0;
|
NumberFormat comparef = NumberFormat("+#,###.###;-#,###.###")..maximumFractionDigits = fractionDigits ?? 0;
|
||||||
NumberFormat intf = NumberFormat.decimalPatternDigits(locale: LocaleSettings.currentLocale.languageCode, decimalDigits: 0);
|
|
||||||
NumberFormat fractionf = NumberFormat.decimalPatternDigits(locale: LocaleSettings.currentLocale.languageCode, decimalDigits: fractionDigits ?? 0)..maximumIntegerDigits = 0;
|
NumberFormat fractionf = NumberFormat.decimalPatternDigits(locale: LocaleSettings.currentLocale.languageCode, decimalDigits: fractionDigits ?? 0)..maximumIntegerDigits = 0;
|
||||||
num fraction = playerStat.isNegative ? 1 - (playerStat - playerStat.floor()) : playerStat - playerStat.floor();
|
num fraction = playerStat.isNegative ? 1 - (playerStat - playerStat.floor()) : playerStat - playerStat.floor();
|
||||||
int integer = playerStat.isNegative ? (playerStat + fraction).toInt() : (playerStat - fraction).toInt();
|
int integer = playerStat.isNegative ? (playerStat + fraction).toInt() : (playerStat - fraction).toInt();
|
||||||
// String valueAsString = fractionDigits == null ? f.format(playerStat.floor()) : f.format(playerStat);
|
|
||||||
// var exploded = valueAsString.split(".");
|
|
||||||
return Column(
|
return Column(
|
||||||
children: [
|
children: [
|
||||||
RichText(
|
RichText(
|
||||||
text: TextSpan(text: intf.format(integer),
|
text: TextSpan(text: intf.format(integer),
|
||||||
children: [
|
children: [
|
||||||
TextSpan(text: fractionf.format(fraction).substring(1), style: const TextStyle(fontSize: 16))
|
TextSpan(text: fractionf.format(fraction).substring(1), style: smallDecimal ? const TextStyle(fontSize: 16) : null)
|
||||||
],
|
],
|
||||||
style: TextStyle(
|
style: TextStyle(
|
||||||
fontFamily: "Eurostile Round Extended",
|
fontFamily: "Eurostile Round Extended",
|
||||||
//fontWeight: FontWeight.bold,
|
|
||||||
fontSize: isScreenBig ? 32 : 24,
|
fontSize: isScreenBig ? 32 : 24,
|
||||||
color: Colors.white
|
color: getStatColor()
|
||||||
)
|
)
|
||||||
)
|
)
|
||||||
),
|
),
|
||||||
if (oldPlayerStat != null) Text(comparef.format(playerStat - oldPlayerStat!), style: TextStyle(
|
if (oldPlayerStat != null || pos != null) RichText(text: TextSpan(
|
||||||
|
text: "",
|
||||||
|
style: const TextStyle(fontFamily: "Eurostile Round", fontSize: 14, color: Colors.grey),
|
||||||
|
children: [
|
||||||
|
if (oldPlayerStat != null) TextSpan(text: comparef.format(playerStat - oldPlayerStat!), style: TextStyle(
|
||||||
color: higherIsBetter ?
|
color: higherIsBetter ?
|
||||||
oldPlayerStat! > playerStat ? Colors.red : Colors.green :
|
oldPlayerStat! > playerStat ? Colors.redAccent : Colors.greenAccent :
|
||||||
oldPlayerStat! < playerStat ? Colors.red : Colors.green
|
oldPlayerStat! < playerStat ? Colors.redAccent : Colors.greenAccent
|
||||||
),),
|
),),
|
||||||
|
if (oldPlayerStat != null && pos != null) const TextSpan(text: " • "),
|
||||||
|
if (pos != null) TextSpan(text: pos!.position >= 1000 ? "${t.top} ${f2.format(pos!.percentage*100)}%" : "№${pos!.position}", style: TextStyle(color: getColorOfRank(pos!.position)))
|
||||||
|
]
|
||||||
|
),
|
||||||
|
),
|
||||||
alertWidgets == null
|
alertWidgets == null
|
||||||
? Text(
|
? Text(
|
||||||
playerStatLabel,
|
playerStatLabel,
|
||||||
|
|
|
@ -3,13 +3,16 @@ import 'package:intl/intl.dart';
|
||||||
import 'package:tetra_stats/data_objects/tetrio.dart';
|
import 'package:tetra_stats/data_objects/tetrio.dart';
|
||||||
import 'package:syncfusion_flutter_gauges/gauges.dart';
|
import 'package:syncfusion_flutter_gauges/gauges.dart';
|
||||||
import 'package:tetra_stats/gen/strings.g.dart';
|
import 'package:tetra_stats/gen/strings.g.dart';
|
||||||
|
import 'package:tetra_stats/main.dart';
|
||||||
|
import 'package:tetra_stats/utils/colors_functions.dart';
|
||||||
|
import 'package:tetra_stats/utils/numers_formats.dart';
|
||||||
|
import 'package:tetra_stats/widgets/gauget_num.dart';
|
||||||
import 'package:tetra_stats/widgets/graphs.dart';
|
import 'package:tetra_stats/widgets/graphs.dart';
|
||||||
import 'package:tetra_stats/widgets/stat_sell_num.dart';
|
import 'package:tetra_stats/widgets/stat_sell_num.dart';
|
||||||
|
|
||||||
var fDiff = NumberFormat("+#,###.###;-#,###.###");
|
var fDiff = NumberFormat("+#,###.###;-#,###.###");
|
||||||
|
var intFDiff = NumberFormat("+#,###;-#,###");
|
||||||
final DateFormat dateFormat = DateFormat.yMMMd(LocaleSettings.currentLocale.languageCode).add_Hms();
|
final DateFormat dateFormat = DateFormat.yMMMd(LocaleSettings.currentLocale.languageCode).add_Hms();
|
||||||
final NumberFormat f2 = NumberFormat.decimalPatternDigits(locale: LocaleSettings.currentLocale.languageCode, decimalDigits: 2);
|
|
||||||
final NumberFormat f3 = NumberFormat.decimalPatternDigits(locale: LocaleSettings.currentLocale.languageCode, decimalDigits: 3);
|
|
||||||
late RangeValues _currentRangeValues;
|
late RangeValues _currentRangeValues;
|
||||||
TetraLeagueAlpha? oldTl;
|
TetraLeagueAlpha? oldTl;
|
||||||
late TetraLeagueAlpha currentTl;
|
late TetraLeagueAlpha currentTl;
|
||||||
|
@ -23,18 +26,26 @@ class TLThingy extends StatefulWidget {
|
||||||
final bool bot;
|
final bool bot;
|
||||||
final bool guest;
|
final bool guest;
|
||||||
final double? topTR;
|
final double? topTR;
|
||||||
const TLThingy({super.key, required this.tl, required this.userID, required this.states, this.showTitle = true, this.bot=false, this.guest=false, this.topTR});
|
final PlayerLeaderboardPosition? lbPositions;
|
||||||
|
final TetraLeagueAlpha? averages;
|
||||||
|
final double? thatRankCutoff;
|
||||||
|
final double? thatRankTarget;
|
||||||
|
final double? nextRankCutoff;
|
||||||
|
final double? nextRankTarget;
|
||||||
|
const TLThingy({super.key, required this.tl, required this.userID, required this.states, this.showTitle = true, this.bot=false, this.guest=false, this.topTR, this.lbPositions, this.averages, this.nextRankCutoff = 25000, this.thatRankCutoff = 0, this.nextRankTarget = 25000, this.thatRankTarget = 0});
|
||||||
|
|
||||||
@override
|
@override
|
||||||
State<TLThingy> createState() => _TLThingyState();
|
State<TLThingy> createState() => _TLThingyState();
|
||||||
}
|
}
|
||||||
|
|
||||||
class _TLThingyState extends State<TLThingy> {
|
class _TLThingyState extends State<TLThingy> {
|
||||||
|
late bool oskKagariGimmick;
|
||||||
|
|
||||||
@override
|
@override
|
||||||
void initState() {
|
void initState() {
|
||||||
_currentRangeValues = const RangeValues(0, 1);
|
_currentRangeValues = const RangeValues(0, 1);
|
||||||
sortedStates = widget.states.reversed.toList();
|
sortedStates = widget.states.reversed.toList();
|
||||||
|
oskKagariGimmick = prefs.getBool("oskKagariGimmick")??true;
|
||||||
try{
|
try{
|
||||||
oldTl = sortedStates[1].tlSeason1;
|
oldTl = sortedStates[1].tlSeason1;
|
||||||
}on RangeError{
|
}on RangeError{
|
||||||
|
@ -47,9 +58,11 @@ class _TLThingyState extends State<TLThingy> {
|
||||||
@override
|
@override
|
||||||
Widget build(BuildContext context) {
|
Widget build(BuildContext context) {
|
||||||
final t = Translations.of(context);
|
final t = Translations.of(context);
|
||||||
|
NumberFormat fractionfEstTR = NumberFormat.decimalPatternDigits(locale: LocaleSettings.currentLocale.languageCode, decimalDigits: 2)..maximumIntegerDigits = 0;
|
||||||
|
NumberFormat fractionfEstTRAcc = NumberFormat.decimalPatternDigits(locale: LocaleSettings.currentLocale.languageCode, decimalDigits: 3)..maximumIntegerDigits = 0;
|
||||||
if (currentTl.gamesPlayed == 0) return Center(child: Text(widget.guest ? t.anonTL : widget.bot ? t.botTL : t.neverPlayedTL, style: const TextStyle(fontFamily: "Eurostile Round", fontSize: 28), textAlign: TextAlign.center,));
|
if (currentTl.gamesPlayed == 0) return Center(child: Text(widget.guest ? t.anonTL : widget.bot ? t.botTL : t.neverPlayedTL, style: const TextStyle(fontFamily: "Eurostile Round", fontSize: 28), textAlign: TextAlign.center,));
|
||||||
return LayoutBuilder(builder: (context, constraints) {
|
return LayoutBuilder(builder: (context, constraints) {
|
||||||
bool bigScreen = constraints.maxWidth > 768;
|
bool bigScreen = constraints.maxWidth >= 768;
|
||||||
return ListView.builder(
|
return ListView.builder(
|
||||||
physics: const ClampingScrollPhysics(),
|
physics: const ClampingScrollPhysics(),
|
||||||
itemCount: 1,
|
itemCount: 1,
|
||||||
|
@ -87,7 +100,7 @@ class _TLThingyState extends State<TLThingy> {
|
||||||
crossAxisAlignment: WrapCrossAlignment.center,
|
crossAxisAlignment: WrapCrossAlignment.center,
|
||||||
clipBehavior: Clip.hardEdge,
|
clipBehavior: Clip.hardEdge,
|
||||||
children: [
|
children: [
|
||||||
widget.userID == "5e32fc85ab319c2ab1beb07c" // he love her so much, you can't even imagine
|
(widget.userID == "5e32fc85ab319c2ab1beb07c" && oskKagariGimmick) // he love her so much, you can't even imagine
|
||||||
? Image.asset("res/icons/kagari.png", height: 128) // Btw why she wearing Kazamatsuri high school uniform?
|
? Image.asset("res/icons/kagari.png", height: 128) // Btw why she wearing Kazamatsuri high school uniform?
|
||||||
: Image.asset("res/tetrio_tl_alpha_ranks/${currentTl.rank}.png", height: 128),
|
: Image.asset("res/tetrio_tl_alpha_ranks/${currentTl.rank}.png", height: 128),
|
||||||
Column(
|
Column(
|
||||||
|
@ -146,12 +159,12 @@ class _TLThingyState extends State<TLThingy> {
|
||||||
softWrap: true,
|
softWrap: true,
|
||||||
textAlign: TextAlign.center,
|
textAlign: TextAlign.center,
|
||||||
style: TextStyle(
|
style: TextStyle(
|
||||||
fontFamily: "Eurostile Round Extended",
|
fontFamily: "Eurostile Round",
|
||||||
fontSize: bigScreen ? 42 : 28,
|
fontSize: bigScreen ? 42 : 28,
|
||||||
overflow: TextOverflow.visible,
|
overflow: TextOverflow.visible,
|
||||||
)),
|
)),
|
||||||
Padding(
|
Padding(
|
||||||
padding: const EdgeInsets.fromLTRB(0, 16, 0, 48),
|
padding: const EdgeInsets.fromLTRB(8, 16, 8, 48),
|
||||||
child: Wrap(
|
child: Wrap(
|
||||||
direction: Axis.horizontal,
|
direction: Axis.horizontal,
|
||||||
alignment: WrapAlignment.center,
|
alignment: WrapAlignment.center,
|
||||||
|
@ -159,13 +172,13 @@ class _TLThingyState extends State<TLThingy> {
|
||||||
crossAxisAlignment: WrapCrossAlignment.start,
|
crossAxisAlignment: WrapCrossAlignment.start,
|
||||||
clipBehavior: Clip.hardEdge,
|
clipBehavior: Clip.hardEdge,
|
||||||
children: [
|
children: [
|
||||||
if (currentTl.apm != null) StatCellNum(playerStat: currentTl.apm!, isScreenBig: bigScreen, fractionDigits: 2, playerStatLabel: t.statCellNum.apm, higherIsBetter: true, oldPlayerStat: oldTl?.apm),
|
if (currentTl.apm != null) StatCellNum(playerStat: currentTl.apm!, isScreenBig: bigScreen, fractionDigits: 2, playerStatLabel: t.statCellNum.apm, higherIsBetter: true, oldPlayerStat: oldTl?.apm, pos: widget.lbPositions?.apm, averageStat: widget.averages?.apm),
|
||||||
if (currentTl.pps != null) StatCellNum(playerStat: currentTl.pps!, isScreenBig: bigScreen, fractionDigits: 2, playerStatLabel: t.statCellNum.pps, higherIsBetter: true, oldPlayerStat: oldTl?.pps),
|
if (currentTl.pps != null) StatCellNum(playerStat: currentTl.pps!, isScreenBig: bigScreen, fractionDigits: 2, playerStatLabel: t.statCellNum.pps, higherIsBetter: true, oldPlayerStat: oldTl?.pps, pos: widget.lbPositions?.pps, averageStat: widget.averages?.pps, smallDecimal: false),
|
||||||
if (currentTl.vs != null) StatCellNum(playerStat: currentTl.vs!, isScreenBig: bigScreen, fractionDigits: 2, playerStatLabel: t.statCellNum.vs, higherIsBetter: true, oldPlayerStat: oldTl?.vs),
|
if (currentTl.vs != null) StatCellNum(playerStat: currentTl.vs!, isScreenBig: bigScreen, fractionDigits: 2, playerStatLabel: t.statCellNum.vs, higherIsBetter: true, oldPlayerStat: oldTl?.vs, pos: widget.lbPositions?.vs, averageStat: widget.averages?.vs),
|
||||||
if (currentTl.standingLocal > 0) StatCellNum(playerStat: currentTl.standingLocal, isScreenBig: bigScreen, playerStatLabel: t.statCellNum.lbpc, higherIsBetter: false, oldPlayerStat: oldTl?.standingLocal),
|
if (currentTl.standingLocal > 0) StatCellNum(playerStat: currentTl.standingLocal, isScreenBig: bigScreen, playerStatLabel: t.statCellNum.lbpc, higherIsBetter: false, oldPlayerStat: oldTl?.standingLocal),
|
||||||
StatCellNum(playerStat: currentTl.gamesPlayed, isScreenBig: bigScreen, playerStatLabel: t.statCellNum.gamesPlayed, higherIsBetter: true, oldPlayerStat: oldTl?.gamesPlayed),
|
StatCellNum(playerStat: currentTl.gamesPlayed, isScreenBig: bigScreen, playerStatLabel: t.statCellNum.gamesPlayed, higherIsBetter: true, oldPlayerStat: oldTl?.gamesPlayed, pos: widget.lbPositions?.gamesPlayed),
|
||||||
StatCellNum(playerStat: currentTl.gamesWon, isScreenBig: bigScreen, playerStatLabel: t.statCellNum.gamesWonTL, higherIsBetter: true, oldPlayerStat: oldTl?.gamesWon),
|
StatCellNum(playerStat: currentTl.gamesWon, isScreenBig: bigScreen, playerStatLabel: t.statCellNum.gamesWonTL, higherIsBetter: true, oldPlayerStat: oldTl?.gamesWon, pos: widget.lbPositions?.gamesWon),
|
||||||
StatCellNum(playerStat: currentTl.winrate * 100, isScreenBig: bigScreen, fractionDigits: 2, playerStatLabel: t.statCellNum.winrate, higherIsBetter: true, oldPlayerStat: oldTl != null ? oldTl!.winrate*100 : null),
|
StatCellNum(playerStat: currentTl.winrate * 100, isScreenBig: bigScreen, fractionDigits: 2, playerStatLabel: t.statCellNum.winrate, higherIsBetter: true, oldPlayerStat: oldTl != null ? oldTl!.winrate*100 : null, pos: widget.lbPositions?.winrate, averageStat: widget.averages != null ? widget.averages!.winrate * 100 : null),
|
||||||
],
|
],
|
||||||
),
|
),
|
||||||
),
|
),
|
||||||
|
@ -182,134 +195,31 @@ class _TLThingyState extends State<TLThingy> {
|
||||||
crossAxisAlignment: WrapCrossAlignment.start,
|
crossAxisAlignment: WrapCrossAlignment.start,
|
||||||
clipBehavior: Clip.hardEdge,
|
clipBehavior: Clip.hardEdge,
|
||||||
children: [
|
children: [
|
||||||
SizedBox(
|
GaugetNum(playerStat: currentTl.nerdStats!.app, playerStatLabel: t.statCellNum.app, higherIsBetter: true, minimum: 0, maximum: 1, ranges: [
|
||||||
width: 200,
|
|
||||||
height: 120,
|
|
||||||
child: SfRadialGauge(
|
|
||||||
title: GaugeTitle(text: t.statCellNum.app),
|
|
||||||
axes: [RadialAxis(
|
|
||||||
startAngle: 180,
|
|
||||||
endAngle: 360,
|
|
||||||
showLabels: false,
|
|
||||||
showTicks: false,
|
|
||||||
radiusFactor: 2.1,
|
|
||||||
centerY: 0.5,
|
|
||||||
minimum: 0,
|
|
||||||
maximum: 1,
|
|
||||||
ranges: [
|
|
||||||
GaugeRange(startValue: 0, endValue: 0.2, color: Colors.red),
|
GaugeRange(startValue: 0, endValue: 0.2, color: Colors.red),
|
||||||
GaugeRange(startValue: 0.2, endValue: 0.4, color: Colors.yellow),
|
GaugeRange(startValue: 0.2, endValue: 0.4, color: Colors.yellow),
|
||||||
GaugeRange(startValue: 0.4, endValue: 0.6, color: Colors.green),
|
GaugeRange(startValue: 0.4, endValue: 0.6, color: Colors.green),
|
||||||
GaugeRange(startValue: 0.6, endValue: 0.8, color: Colors.blue),
|
GaugeRange(startValue: 0.6, endValue: 0.8, color: Colors.blue),
|
||||||
GaugeRange(startValue: 0.8, endValue: 1, color: Colors.purple),
|
GaugeRange(startValue: 0.8, endValue: 1, color: Colors.purple),
|
||||||
],
|
], alertWidgets: [
|
||||||
pointers: [
|
|
||||||
NeedlePointer(
|
|
||||||
value: currentTl.nerdStats!.app,
|
|
||||||
enableAnimation: true,
|
|
||||||
needleLength: 0.9,
|
|
||||||
needleStartWidth: 2,
|
|
||||||
needleEndWidth: 15,
|
|
||||||
knobStyle: const KnobStyle(color: Colors.transparent),
|
|
||||||
gradient: const LinearGradient(colors: [Colors.transparent, Colors.white], begin: Alignment.bottomCenter, end: Alignment.topCenter, stops: [0.5, 1]),)
|
|
||||||
],
|
|
||||||
annotations: [GaugeAnnotation(
|
|
||||||
widget: TextButton(child: Text(f3.format(currentTl.nerdStats!.app),
|
|
||||||
style: const TextStyle(fontFamily: "Eurostile Round Extended", fontSize: 36, color: Colors.white)),
|
|
||||||
onPressed: (){
|
|
||||||
showDialog(
|
|
||||||
context: context,
|
|
||||||
builder: (BuildContext context) => AlertDialog(
|
|
||||||
title: Text(t.statCellNum.app,
|
|
||||||
style: const TextStyle(
|
|
||||||
fontFamily: "Eurostile Round Extended")),
|
|
||||||
content: SingleChildScrollView(
|
|
||||||
child: ListBody(children: [
|
|
||||||
Text(t.statCellNum.appDescription),
|
Text(t.statCellNum.appDescription),
|
||||||
Text("${t.exactValue}: ${currentTl.nerdStats!.app}")
|
Text("${t.exactValue}: ${currentTl.nerdStats!.app}")
|
||||||
]),
|
], oldPlayerStat: oldTl?.nerdStats?.app, pos: widget.lbPositions?.app,
|
||||||
),
|
averageStat: widget.averages?.nerdStats?.app),
|
||||||
actions: <Widget>[
|
GaugetNum(playerStat: currentTl.nerdStats!.vsapm, playerStatLabel: "VS / APM", higherIsBetter: true, minimum: 1.8, maximum: 2.4, ranges: [
|
||||||
TextButton(
|
|
||||||
child: Text(t.popupActions.ok),
|
|
||||||
onPressed: () {
|
|
||||||
Navigator.of(context).pop();
|
|
||||||
},
|
|
||||||
)
|
|
||||||
],
|
|
||||||
));
|
|
||||||
},), verticalAlignment: GaugeAlignment.far, positionFactor: 0.05,),
|
|
||||||
if (oldTl != null && oldTl!.gamesPlayed > 0) GaugeAnnotation(widget: Text(fDiff.format(currentTl.nerdStats!.app - oldTl!.nerdStats!.app), style: TextStyle(
|
|
||||||
color: currentTl.nerdStats!.app - oldTl!.nerdStats!.app < 0 ?
|
|
||||||
Colors.red :
|
|
||||||
Colors.green
|
|
||||||
),), positionFactor: 0.05,)],
|
|
||||||
)],),
|
|
||||||
),
|
|
||||||
SizedBox(
|
|
||||||
width: 200,
|
|
||||||
height: 120,
|
|
||||||
child: SfRadialGauge(
|
|
||||||
title: const GaugeTitle(text: "VS / APM"),
|
|
||||||
axes: [RadialAxis(
|
|
||||||
startAngle: 180,
|
|
||||||
endAngle: 360,
|
|
||||||
showTicks: false,
|
|
||||||
showLabels: false,
|
|
||||||
radiusFactor: 2.1,
|
|
||||||
centerY: 0.5,
|
|
||||||
minimum: 1.8,
|
|
||||||
maximum: 2.4,
|
|
||||||
ranges: [
|
|
||||||
GaugeRange(startValue: 1.8, endValue: 2.0, color: Colors.green),
|
GaugeRange(startValue: 1.8, endValue: 2.0, color: Colors.green),
|
||||||
GaugeRange(startValue: 2.0, endValue: 2.2, color: Colors.blue),
|
GaugeRange(startValue: 2.0, endValue: 2.2, color: Colors.blue),
|
||||||
GaugeRange(startValue: 2.2, endValue: 2.4, color: Colors.purple),
|
GaugeRange(startValue: 2.2, endValue: 2.4, color: Colors.purple),
|
||||||
],
|
], alertWidgets: [
|
||||||
pointers: [
|
|
||||||
NeedlePointer(
|
|
||||||
value: currentTl.nerdStats!.vsapm,
|
|
||||||
enableAnimation: true,
|
|
||||||
needleLength: 0.9,
|
|
||||||
needleStartWidth: 2,
|
|
||||||
needleEndWidth: 15,
|
|
||||||
knobStyle: const KnobStyle(color: Colors.transparent),
|
|
||||||
gradient: const LinearGradient(colors: [Colors.transparent, Colors.white], begin: Alignment.bottomCenter, end: Alignment.topCenter, stops: [0.5, 1]),)
|
|
||||||
],
|
|
||||||
annotations: [GaugeAnnotation(
|
|
||||||
widget: TextButton(child: Text(f3.format(currentTl.nerdStats!.vsapm),
|
|
||||||
style: const TextStyle(fontFamily: "Eurostile Round Extended", fontSize: 36, color: Colors.white)),
|
|
||||||
onPressed: (){
|
|
||||||
showDialog(
|
|
||||||
context: context,
|
|
||||||
builder: (BuildContext context) => AlertDialog(
|
|
||||||
title: const Text("VS / APM",
|
|
||||||
style: TextStyle(
|
|
||||||
fontFamily: "Eurostile Round Extended")),
|
|
||||||
content: SingleChildScrollView(
|
|
||||||
child: ListBody(children: [
|
|
||||||
Text(t.statCellNum.vsapmDescription),
|
Text(t.statCellNum.vsapmDescription),
|
||||||
Text("${t.exactValue}: ${currentTl.nerdStats!.vsapm}")
|
Text("${t.exactValue}: ${currentTl.nerdStats!.vsapm}")
|
||||||
|
], oldPlayerStat: oldTl?.nerdStats?.vsapm, pos: widget.lbPositions?.vsapm,
|
||||||
|
averageStat: widget.averages?.nerdStats?.vsapm)
|
||||||
]),
|
]),
|
||||||
),
|
),
|
||||||
actions: <Widget>[
|
Padding(
|
||||||
TextButton(
|
padding: const EdgeInsets.fromLTRB(8, 0, 8, 0),
|
||||||
child: Text(t.popupActions.ok),
|
child: Wrap(
|
||||||
onPressed: () {
|
|
||||||
Navigator.of(context).pop();
|
|
||||||
},
|
|
||||||
)
|
|
||||||
],
|
|
||||||
));
|
|
||||||
},), verticalAlignment: GaugeAlignment.far, positionFactor: 0.05),
|
|
||||||
if (oldTl != null && oldTl!.gamesPlayed > 0) GaugeAnnotation(widget: Text(fDiff.format(currentTl.nerdStats!.vsapm - oldTl!.nerdStats!.vsapm), style: TextStyle(
|
|
||||||
color: currentTl.nerdStats!.vsapm - oldTl!.nerdStats!.vsapm < 0 ?
|
|
||||||
Colors.red :
|
|
||||||
Colors.green
|
|
||||||
),), positionFactor: 0.05,)],
|
|
||||||
)],),
|
|
||||||
),]),
|
|
||||||
),
|
|
||||||
Wrap(
|
|
||||||
direction: Axis.horizontal,
|
direction: Axis.horizontal,
|
||||||
alignment: WrapAlignment.center,
|
alignment: WrapAlignment.center,
|
||||||
spacing: 25,
|
spacing: 25,
|
||||||
|
@ -317,6 +227,8 @@ class _TLThingyState extends State<TLThingy> {
|
||||||
clipBehavior: Clip.hardEdge,
|
clipBehavior: Clip.hardEdge,
|
||||||
children: [
|
children: [
|
||||||
StatCellNum(playerStat: currentTl.nerdStats!.dss, isScreenBig: bigScreen, fractionDigits: 3, playerStatLabel: t.statCellNum.dss,
|
StatCellNum(playerStat: currentTl.nerdStats!.dss, isScreenBig: bigScreen, fractionDigits: 3, playerStatLabel: t.statCellNum.dss,
|
||||||
|
pos: widget.lbPositions?.dss,
|
||||||
|
averageStat: widget.averages?.nerdStats?.dss, smallDecimal: false,
|
||||||
alertWidgets: [Text(t.statCellNum.dssDescription),
|
alertWidgets: [Text(t.statCellNum.dssDescription),
|
||||||
Text("${t.formula}: (VS / 100) - (APM / 60)"),
|
Text("${t.formula}: (VS / 100) - (APM / 60)"),
|
||||||
Text("${t.exactValue}: ${currentTl.nerdStats!.dss}"),],
|
Text("${t.exactValue}: ${currentTl.nerdStats!.dss}"),],
|
||||||
|
@ -324,6 +236,8 @@ class _TLThingyState extends State<TLThingy> {
|
||||||
higherIsBetter: true,
|
higherIsBetter: true,
|
||||||
oldPlayerStat: oldTl?.nerdStats?.dss,),
|
oldPlayerStat: oldTl?.nerdStats?.dss,),
|
||||||
StatCellNum(playerStat: currentTl.nerdStats!.dsp, isScreenBig: bigScreen, fractionDigits: 3, playerStatLabel: t.statCellNum.dsp,
|
StatCellNum(playerStat: currentTl.nerdStats!.dsp, isScreenBig: bigScreen, fractionDigits: 3, playerStatLabel: t.statCellNum.dsp,
|
||||||
|
pos: widget.lbPositions?.dsp,
|
||||||
|
averageStat: widget.averages?.nerdStats?.dsp, smallDecimal: false,
|
||||||
alertWidgets: [Text(t.statCellNum.dspDescription),
|
alertWidgets: [Text(t.statCellNum.dspDescription),
|
||||||
Text("${t.formula}: DS/S / PPS"),
|
Text("${t.formula}: DS/S / PPS"),
|
||||||
Text("${t.exactValue}: ${currentTl.nerdStats!.dsp}"),],
|
Text("${t.exactValue}: ${currentTl.nerdStats!.dsp}"),],
|
||||||
|
@ -331,6 +245,8 @@ class _TLThingyState extends State<TLThingy> {
|
||||||
higherIsBetter: true,
|
higherIsBetter: true,
|
||||||
oldPlayerStat: oldTl?.nerdStats?.dsp,),
|
oldPlayerStat: oldTl?.nerdStats?.dsp,),
|
||||||
StatCellNum(playerStat: currentTl.nerdStats!.appdsp, isScreenBig: bigScreen, fractionDigits: 3, playerStatLabel: t.statCellNum.appdsp,
|
StatCellNum(playerStat: currentTl.nerdStats!.appdsp, isScreenBig: bigScreen, fractionDigits: 3, playerStatLabel: t.statCellNum.appdsp,
|
||||||
|
pos: widget.lbPositions?.appdsp,
|
||||||
|
averageStat: widget.averages?.nerdStats?.appdsp, smallDecimal: false,
|
||||||
alertWidgets: [Text(t.statCellNum.appdspDescription),
|
alertWidgets: [Text(t.statCellNum.appdspDescription),
|
||||||
Text("${t.formula}: APP + DS/P"),
|
Text("${t.formula}: APP + DS/P"),
|
||||||
Text("${t.exactValue}: ${currentTl.nerdStats!.appdsp}"),],
|
Text("${t.exactValue}: ${currentTl.nerdStats!.appdsp}"),],
|
||||||
|
@ -338,13 +254,17 @@ class _TLThingyState extends State<TLThingy> {
|
||||||
higherIsBetter: true,
|
higherIsBetter: true,
|
||||||
oldPlayerStat: oldTl?.nerdStats?.appdsp,),
|
oldPlayerStat: oldTl?.nerdStats?.appdsp,),
|
||||||
StatCellNum(playerStat: currentTl.nerdStats!.cheese, isScreenBig: bigScreen, fractionDigits: 2, playerStatLabel: t.statCellNum.cheese,
|
StatCellNum(playerStat: currentTl.nerdStats!.cheese, isScreenBig: bigScreen, fractionDigits: 2, playerStatLabel: t.statCellNum.cheese,
|
||||||
|
pos: widget.lbPositions?.cheese,
|
||||||
|
//averageStat: rankAverages?.nerdStats?.cheese, TODO: questonable
|
||||||
alertWidgets: [Text(t.statCellNum.cheeseDescription),
|
alertWidgets: [Text(t.statCellNum.cheeseDescription),
|
||||||
Text("${t.formula}: (DS/P * 150) + ((VS/APM - 2) * 50) + (0.6 - APP) * 125"),
|
Text("${t.formula}: (DS/P * 150) + ((VS/APM - 2) * 50) + (0.6 - APP) * 125"),
|
||||||
Text("${t.exactValue}: ${currentTl.nerdStats!.cheese}"),],
|
Text("${t.exactValue}: ${currentTl.nerdStats!.cheese}"),],
|
||||||
okText: t.popupActions.ok,
|
okText: t.popupActions.ok,
|
||||||
higherIsBetter: true,
|
higherIsBetter: false,
|
||||||
oldPlayerStat: oldTl?.nerdStats?.cheese,),
|
oldPlayerStat: oldTl?.nerdStats?.cheese,),
|
||||||
StatCellNum(playerStat: currentTl.nerdStats!.gbe, isScreenBig: bigScreen, fractionDigits: 3, playerStatLabel: t.statCellNum.gbe,
|
StatCellNum(playerStat: currentTl.nerdStats!.gbe, isScreenBig: bigScreen, fractionDigits: 3, playerStatLabel: t.statCellNum.gbe,
|
||||||
|
pos: widget.lbPositions?.gbe,
|
||||||
|
averageStat: widget.averages?.nerdStats?.gbe, smallDecimal: false,
|
||||||
alertWidgets: [Text(t.statCellNum.gbeDescription),
|
alertWidgets: [Text(t.statCellNum.gbeDescription),
|
||||||
Text("${t.formula}: APP * DS/P * 2"),
|
Text("${t.formula}: APP * DS/P * 2"),
|
||||||
Text("${t.exactValue}: ${currentTl.nerdStats!.gbe}"),],
|
Text("${t.exactValue}: ${currentTl.nerdStats!.gbe}"),],
|
||||||
|
@ -352,6 +272,8 @@ class _TLThingyState extends State<TLThingy> {
|
||||||
higherIsBetter: true,
|
higherIsBetter: true,
|
||||||
oldPlayerStat: oldTl?.nerdStats?.gbe,),
|
oldPlayerStat: oldTl?.nerdStats?.gbe,),
|
||||||
StatCellNum(playerStat: currentTl.nerdStats!.nyaapp, isScreenBig: bigScreen, fractionDigits: 3, playerStatLabel: t.statCellNum.nyaapp,
|
StatCellNum(playerStat: currentTl.nerdStats!.nyaapp, isScreenBig: bigScreen, fractionDigits: 3, playerStatLabel: t.statCellNum.nyaapp,
|
||||||
|
pos: widget.lbPositions?.nyaapp,
|
||||||
|
averageStat: widget.averages?.nerdStats?.nyaapp, smallDecimal: false,
|
||||||
alertWidgets: [Text(t.statCellNum.nyaappDescription),
|
alertWidgets: [Text(t.statCellNum.nyaappDescription),
|
||||||
Text("${t.formula}: APP - 5 * tan(radians((Cheese Index / -30) + 1))"),
|
Text("${t.formula}: APP - 5 * tan(radians((Cheese Index / -30) + 1))"),
|
||||||
Text("${t.exactValue}: ${currentTl.nerdStats!.nyaapp}"),],
|
Text("${t.exactValue}: ${currentTl.nerdStats!.nyaapp}"),],
|
||||||
|
@ -359,53 +281,89 @@ class _TLThingyState extends State<TLThingy> {
|
||||||
higherIsBetter: true,
|
higherIsBetter: true,
|
||||||
oldPlayerStat: oldTl?.nerdStats?.nyaapp,),
|
oldPlayerStat: oldTl?.nerdStats?.nyaapp,),
|
||||||
StatCellNum(playerStat: currentTl.nerdStats!.area, isScreenBig: bigScreen, fractionDigits: 1, playerStatLabel: t.statCellNum.area,
|
StatCellNum(playerStat: currentTl.nerdStats!.area, isScreenBig: bigScreen, fractionDigits: 1, playerStatLabel: t.statCellNum.area,
|
||||||
|
pos: widget.lbPositions?.area,
|
||||||
|
averageStat: widget.averages?.nerdStats?.area,
|
||||||
alertWidgets: [Text(t.statCellNum.areaDescription),
|
alertWidgets: [Text(t.statCellNum.areaDescription),
|
||||||
Text("${t.formula}: APM * 1 + PPS * 45 + VS * 0.444 + APP * 185 + DS/S * 175 + DS/P * 450 + Garbage Effi * 315"),
|
Text("${t.formula}: APM * 1 + PPS * 45 + VS * 0.444 + APP * 185 + DS/S * 175 + DS/P * 450 + Garbage Effi * 315"),
|
||||||
Text("${t.exactValue}: ${currentTl.nerdStats!.area}"),],
|
Text("${t.exactValue}: ${currentTl.nerdStats!.area}"),],
|
||||||
okText: t.popupActions.ok,
|
okText: t.popupActions.ok,
|
||||||
higherIsBetter: true,
|
higherIsBetter: true,
|
||||||
oldPlayerStat: oldTl?.nerdStats?.area,)
|
oldPlayerStat: oldTl?.nerdStats?.area,)
|
||||||
])
|
]),
|
||||||
|
)
|
||||||
],
|
],
|
||||||
),
|
),
|
||||||
if (currentTl.estTr != null)
|
if (currentTl.estTr != null)
|
||||||
Padding(
|
Padding(
|
||||||
padding: const EdgeInsets.fromLTRB(0, 16, 0, 48),
|
padding: const EdgeInsets.fromLTRB(0, 20, 0, 20),
|
||||||
child: SizedBox(
|
child: Container(
|
||||||
|
//alignment: Alignment.center,
|
||||||
width: bigScreen ? MediaQuery.of(context).size.width * 0.4 : MediaQuery.of(context).size.width * 0.85,
|
width: bigScreen ? MediaQuery.of(context).size.width * 0.4 : MediaQuery.of(context).size.width * 0.85,
|
||||||
|
height: 70,
|
||||||
|
constraints: const BoxConstraints(maxWidth: 768),
|
||||||
|
child: Stack(
|
||||||
|
children: [
|
||||||
|
Positioned(
|
||||||
|
left: 0,
|
||||||
child: Column(
|
child: Column(
|
||||||
crossAxisAlignment: CrossAxisAlignment.start,
|
crossAxisAlignment: CrossAxisAlignment.start,
|
||||||
children: [
|
children: [
|
||||||
Row(
|
Text(t.statCellNum.estOfTR, style: const TextStyle(height: 0.1),),
|
||||||
mainAxisAlignment: MainAxisAlignment.spaceBetween,
|
RichText(
|
||||||
|
text: TextSpan(
|
||||||
|
text: intf.format(currentTl.estTr!.esttr.truncate()),
|
||||||
|
style: TextStyle(fontFamily: "Eurostile Round Extended", fontSize: bigScreen ? 36 : 30, fontWeight: FontWeight.w500, color: Colors.white),
|
||||||
|
children: [TextSpan(text: fractionfEstTR.format(currentTl.estTr!.esttr - currentTl.estTr!.esttr.truncate()).substring(1), style: const TextStyle(fontFamily: "Eurostile Round", fontSize: 14, fontWeight: FontWeight.w100))]
|
||||||
|
),
|
||||||
|
),
|
||||||
|
RichText(text: TextSpan(
|
||||||
|
text: "",
|
||||||
|
style: const TextStyle(fontFamily: "Eurostile Round", fontSize: 14, color: Colors.grey, height: 0.5),
|
||||||
children: [
|
children: [
|
||||||
Text(
|
if (oldTl?.estTr?.esttr != null) TextSpan(text: comparef.format(currentTl.estTr!.esttr - oldTl!.estTr!.esttr), style: TextStyle(
|
||||||
"${bigScreen ? t.statCellNum.estOfTR : t.statCellNum.estOfTRShort}:",
|
color: oldTl!.estTr!.esttr > currentTl.estTr!.esttr ? Colors.redAccent : Colors.greenAccent
|
||||||
style: const TextStyle(fontSize: 24),
|
),),
|
||||||
|
if (oldTl?.estTr?.esttr != null && widget.lbPositions?.estTr != null) const TextSpan(text: " • "),
|
||||||
|
if (widget.lbPositions?.estTr != null) TextSpan(text: widget.lbPositions!.estTr!.position >= 1000 ? "${t.top} ${f2.format(widget.lbPositions!.estTr!.percentage*100)}%" : "№${widget.lbPositions!.estTr!.position}", style: TextStyle(color: getColorOfRank(widget.lbPositions!.estTr!.position))),
|
||||||
|
if (widget.lbPositions?.estTr != null) const TextSpan(text: " • "),
|
||||||
|
TextSpan(text: "Glicko: ${f2.format(currentTl.estTr!.estglicko)}")
|
||||||
|
]
|
||||||
),
|
),
|
||||||
Text(
|
|
||||||
f2.format(currentTl.estTr!.esttr),
|
|
||||||
style: const TextStyle(fontSize: 24),
|
|
||||||
),
|
),
|
||||||
],
|
],),
|
||||||
),
|
),
|
||||||
if (currentTl.rating >= 0)
|
Positioned(
|
||||||
Row(
|
right: 0,
|
||||||
mainAxisAlignment: MainAxisAlignment.spaceBetween,
|
child: Column(
|
||||||
|
crossAxisAlignment: CrossAxisAlignment.end,
|
||||||
children: [
|
children: [
|
||||||
Text(
|
Text(t.statCellNum.accOfEst, style: const TextStyle(height: 0.1),),
|
||||||
"${bigScreen ? t.statCellNum.accOfEst : t.statCellNum.accOfEstShort}:",
|
RichText(
|
||||||
style: const TextStyle(fontSize: 24),
|
text: TextSpan(
|
||||||
|
text: (currentTl.esttracc != null && currentTl.bestRank != "z") ? intFDiff.format(currentTl.esttracc!.truncate()) : "---",
|
||||||
|
style: TextStyle(fontFamily: "Eurostile Round", fontSize: bigScreen ? 36 : 30, fontWeight: FontWeight.w500, color: Colors.white),
|
||||||
|
children: [
|
||||||
|
TextSpan(text: (currentTl.esttracc != null && currentTl.bestRank != "z") ? fractionfEstTRAcc.format(currentTl.esttracc!.isNegative ? 1 - (currentTl.esttracc! - currentTl.esttracc!.truncate()) : (currentTl.esttracc! - currentTl.esttracc!.truncate())).substring(1) : ".---", style: const TextStyle(fontFamily: "Eurostile Round", fontSize: 14, fontWeight: FontWeight.w100))
|
||||||
|
]
|
||||||
),
|
),
|
||||||
Text(
|
|
||||||
fDiff.format(currentTl.esttracc!),
|
|
||||||
style: const TextStyle(fontSize: 24),
|
|
||||||
),
|
),
|
||||||
|
if ((oldTl?.esttracc != null || widget.lbPositions != null) && currentTl.bestRank != "z") RichText(text: TextSpan(
|
||||||
|
text: "",
|
||||||
|
style: const TextStyle(fontFamily: "Eurostile Round", fontSize: 14, color: Colors.grey, height: 0.5),
|
||||||
|
children: [
|
||||||
|
if (oldTl?.esttracc != null) TextSpan(text: comparef.format(currentTl.esttracc! - oldTl!.esttracc!), style: TextStyle(
|
||||||
|
color: oldTl!.esttracc! > currentTl.esttracc! ? Colors.redAccent : Colors.greenAccent
|
||||||
|
),),
|
||||||
|
if (oldTl?.esttracc != null && widget.lbPositions?.accOfEst != null) const TextSpan(text: " • "),
|
||||||
|
if (widget.lbPositions?.accOfEst != null) TextSpan(text: widget.lbPositions!.accOfEst!.position >= 1000 ? "${t.top} ${f2.format(widget.lbPositions!.accOfEst!.percentage*100)}%" : "№${widget.lbPositions!.accOfEst!.position}", style: TextStyle(color: getColorOfRank(widget.lbPositions!.accOfEst!.position)))
|
||||||
|
]
|
||||||
|
),
|
||||||
|
),
|
||||||
|
],),
|
||||||
|
)
|
||||||
],
|
],
|
||||||
),
|
),
|
||||||
],
|
)
|
||||||
),
|
|
||||||
),
|
|
||||||
),
|
),
|
||||||
if (currentTl.nerdStats != null) Graphs(currentTl.apm!, currentTl.pps!, currentTl.vs!, currentTl.nerdStats!, currentTl.playstyle!)
|
if (currentTl.nerdStats != null) Graphs(currentTl.apm!, currentTl.pps!, currentTl.vs!, currentTl.nerdStats!, currentTl.playstyle!)
|
||||||
]
|
]
|
||||||
|
|
|
@ -91,6 +91,7 @@ class UserThingy extends StatelessWidget {
|
||||||
? Image.asset("res/avatars/tetrio_banned.png", fit: BoxFit.fitHeight, height: pfpHeight,)
|
? Image.asset("res/avatars/tetrio_banned.png", fit: BoxFit.fitHeight, height: pfpHeight,)
|
||||||
: player.avatarRevision != null
|
: player.avatarRevision != null
|
||||||
? Image.network("https://tetr.io/user-content/avatars/${player.userId}.jpg?rv=${player.avatarRevision}",
|
? Image.network("https://tetr.io/user-content/avatars/${player.userId}.jpg?rv=${player.avatarRevision}",
|
||||||
|
// TODO: osk banner can cause memory leak
|
||||||
fit: BoxFit.fitHeight, height: 128, errorBuilder: (context, error, stackTrace) {
|
fit: BoxFit.fitHeight, height: 128, errorBuilder: (context, error, stackTrace) {
|
||||||
developer.log("Error with building profile picture", name: "main_view", error: error, stackTrace: stackTrace);
|
developer.log("Error with building profile picture", name: "main_view", error: error, stackTrace: stackTrace);
|
||||||
return Image.asset("res/avatars/tetrio_anon.png", fit: BoxFit.fitHeight, height: pfpHeight);
|
return Image.asset("res/avatars/tetrio_anon.png", fit: BoxFit.fitHeight, height: pfpHeight);
|
||||||
|
@ -271,7 +272,7 @@ class UserThingy extends StatelessWidget {
|
||||||
playerStatLabel: t.statCellNum.hoursPlayed,
|
playerStatLabel: t.statCellNum.hoursPlayed,
|
||||||
isScreenBig: bigScreen,
|
isScreenBig: bigScreen,
|
||||||
alertTitle: t.exactGametime,
|
alertTitle: t.exactGametime,
|
||||||
alertWidgets: [Text(player.gameTime.toString(), style: const TextStyle(fontFamily: "Eurostile Round Extended"),)],
|
alertWidgets: [Text(player.gameTime.toString(), style: const TextStyle(fontFamily: "Eurostile Round", fontSize: 24),)],
|
||||||
higherIsBetter: true,),
|
higherIsBetter: true,),
|
||||||
if (player.gamesPlayed >= 0)
|
if (player.gamesPlayed >= 0)
|
||||||
StatCellNum(
|
StatCellNum(
|
||||||
|
@ -328,13 +329,29 @@ class UserThingy extends StatelessWidget {
|
||||||
mainAxisAlignment: MainAxisAlignment.center,
|
mainAxisAlignment: MainAxisAlignment.center,
|
||||||
children: [
|
children: [
|
||||||
Expanded(
|
Expanded(
|
||||||
child: Text(
|
child: RichText(
|
||||||
"${player.country != null ? "${t.countries[player.country]} • " : ""}${t.playerRole[player.role]}${t.playerRoleAccount}${player.registrationTime == null ? t.wasFromBeginning : '${t.created} ${dateFormat.format(player.registrationTime!)}'}${player.botmaster != null ? " ${t.botCreatedBy} ${player.botmaster}" : ""} • ${player.supporterTier == 0 ? t.notSupporter : t.supporter(tier: player.supporterTier)}",
|
|
||||||
textAlign: TextAlign.center,
|
textAlign: TextAlign.center,
|
||||||
style: const TextStyle(
|
text: TextSpan(text: "", style: const TextStyle(
|
||||||
fontFamily: "Eurostile Round",
|
fontFamily: "Eurostile Round",
|
||||||
fontSize: 16,
|
fontSize: 16,
|
||||||
)),
|
color: Colors.white,
|
||||||
|
),
|
||||||
|
children: [
|
||||||
|
if (player.country != null) TextSpan(text: "${t.countries[player.country]} • "),
|
||||||
|
TextSpan(text: "${t.playerRole[player.role]}${t.playerRoleAccount}${player.registrationTime == null ? t.wasFromBeginning : '${t.created} ${dateFormat.format(player.registrationTime!)}'}"),
|
||||||
|
if (player.supporterTier > 0) const TextSpan(text: " • "),
|
||||||
|
if (player.supporterTier > 0) WidgetSpan(child: Icon(player.supporterTier > 1 ? Icons.star : Icons.star_border, color: player.supporterTier > 1 ? Colors.yellowAccent : Colors.white), alignment: PlaceholderAlignment.middle, baseline: TextBaseline.alphabetic),
|
||||||
|
if (player.supporterTier > 0) TextSpan(text: player.supporterTier.toString(), style: TextStyle(color: player.supporterTier > 1 ? Colors.yellowAccent : Colors.white))
|
||||||
|
]
|
||||||
|
)
|
||||||
|
),
|
||||||
|
// Text(
|
||||||
|
// "${player.country != null ? "${t.countries[player.country]} • " : ""}${t.playerRole[player.role]}${t.playerRoleAccount}${player.registrationTime == null ? t.wasFromBeginning : '${t.created} ${dateFormat.format(player.registrationTime!)}'}${player.botmaster != null ? " ${t.botCreatedBy} ${player.botmaster}" : ""} • ${player.supporterTier == 0 ? t.notSupporter : t.supporter(tier: player.supporterTier)}",
|
||||||
|
// textAlign: TextAlign.center,
|
||||||
|
// style: const TextStyle(
|
||||||
|
// fontFamily: "Eurostile Round",
|
||||||
|
// fontSize: 16,
|
||||||
|
// )),
|
||||||
)
|
)
|
||||||
],
|
],
|
||||||
),
|
),
|
||||||
|
|
244
pubspec.lock
|
@ -5,26 +5,26 @@ packages:
|
||||||
dependency: transitive
|
dependency: transitive
|
||||||
description:
|
description:
|
||||||
name: _fe_analyzer_shared
|
name: _fe_analyzer_shared
|
||||||
sha256: eb376e9acf6938204f90eb3b1f00b578640d3188b4c8a8ec054f9f479af8d051
|
sha256: "0b2f2bd91ba804e53a61d757b986f89f1f9eaed5b11e4b2f5a2468d86d6c9fc7"
|
||||||
url: "https://pub.dev"
|
url: "https://pub.dev"
|
||||||
source: hosted
|
source: hosted
|
||||||
version: "64.0.0"
|
version: "67.0.0"
|
||||||
analyzer:
|
analyzer:
|
||||||
dependency: transitive
|
dependency: transitive
|
||||||
description:
|
description:
|
||||||
name: analyzer
|
name: analyzer
|
||||||
sha256: "69f54f967773f6c26c7dcb13e93d7ccee8b17a641689da39e878d5cf13b06893"
|
sha256: "37577842a27e4338429a1cbc32679d508836510b056f1eedf0c8d20e39c1383d"
|
||||||
url: "https://pub.dev"
|
url: "https://pub.dev"
|
||||||
source: hosted
|
source: hosted
|
||||||
version: "6.2.0"
|
version: "6.4.1"
|
||||||
archive:
|
archive:
|
||||||
dependency: transitive
|
dependency: transitive
|
||||||
description:
|
description:
|
||||||
name: archive
|
name: archive
|
||||||
sha256: "7b875fd4a20b165a3084bd2d210439b22ebc653f21cea4842729c0c30c82596b"
|
sha256: "22600aa1e926be775fa5fe7e6894e7fb3df9efda8891c73f70fb3262399a432d"
|
||||||
url: "https://pub.dev"
|
url: "https://pub.dev"
|
||||||
source: hosted
|
source: hosted
|
||||||
version: "3.4.9"
|
version: "3.4.10"
|
||||||
args:
|
args:
|
||||||
dependency: transitive
|
dependency: transitive
|
||||||
description:
|
description:
|
||||||
|
@ -141,10 +141,10 @@ packages:
|
||||||
dependency: transitive
|
dependency: transitive
|
||||||
description:
|
description:
|
||||||
name: dev_build
|
name: dev_build
|
||||||
sha256: e476ac99174842cdb01e64c1d379d041d2150f9ad2cdd2713eb1ca1bdbf30507
|
sha256: e5d575f3de4b0e5f004e065e1e2d98fa012d634b61b5855216b5698ed7f1e443
|
||||||
url: "https://pub.dev"
|
url: "https://pub.dev"
|
||||||
source: hosted
|
source: hosted
|
||||||
version: "0.16.3+2"
|
version: "0.16.4+3"
|
||||||
equatable:
|
equatable:
|
||||||
dependency: transitive
|
dependency: transitive
|
||||||
description:
|
description:
|
||||||
|
@ -165,10 +165,10 @@ packages:
|
||||||
dependency: transitive
|
dependency: transitive
|
||||||
description:
|
description:
|
||||||
name: ffi
|
name: ffi
|
||||||
sha256: "7bf0adc28a23d395f19f3f1eb21dd7cfd1dd9f8e1c50051c069122e6853bc878"
|
sha256: "493f37e7df1804778ff3a53bd691d8692ddf69702cf4c1c1096a2e41b4779e21"
|
||||||
url: "https://pub.dev"
|
url: "https://pub.dev"
|
||||||
source: hosted
|
source: hosted
|
||||||
version: "2.1.0"
|
version: "2.1.2"
|
||||||
file:
|
file:
|
||||||
dependency: transitive
|
dependency: transitive
|
||||||
description:
|
description:
|
||||||
|
@ -181,34 +181,34 @@ packages:
|
||||||
dependency: "direct main"
|
dependency: "direct main"
|
||||||
description:
|
description:
|
||||||
name: file_picker
|
name: file_picker
|
||||||
sha256: "4e42aacde3b993c5947467ab640882c56947d9d27342a5b6f2895b23956954a6"
|
sha256: "1bbf65dd997458a08b531042ec3794112a6c39c07c37ff22113d2e7e4f81d4e4"
|
||||||
url: "https://pub.dev"
|
url: "https://pub.dev"
|
||||||
source: hosted
|
source: hosted
|
||||||
version: "6.1.1"
|
version: "6.2.1"
|
||||||
file_selector:
|
file_selector:
|
||||||
dependency: "direct main"
|
dependency: "direct main"
|
||||||
description:
|
description:
|
||||||
name: file_selector
|
name: file_selector
|
||||||
sha256: "84eaf3e034d647859167d1f01cfe7b6352488f34c1b4932635012b202014c25b"
|
sha256: "5019692b593455127794d5718304ff1ae15447dea286cdda9f0db2a796a1b828"
|
||||||
url: "https://pub.dev"
|
url: "https://pub.dev"
|
||||||
source: hosted
|
source: hosted
|
||||||
version: "1.0.1"
|
version: "1.0.3"
|
||||||
file_selector_android:
|
file_selector_android:
|
||||||
dependency: transitive
|
dependency: transitive
|
||||||
description:
|
description:
|
||||||
name: file_selector_android
|
name: file_selector_android
|
||||||
sha256: b7556052dbcc25ef88f6eba45ab98aa5600382af8dfdabc9d644a93d97b7be7f
|
sha256: "1cd66575f063b689e041aec836905ba7be18d76c9f0634d0d75daec825f67095"
|
||||||
url: "https://pub.dev"
|
url: "https://pub.dev"
|
||||||
source: hosted
|
source: hosted
|
||||||
version: "0.5.0+4"
|
version: "0.5.0+7"
|
||||||
file_selector_ios:
|
file_selector_ios:
|
||||||
dependency: transitive
|
dependency: transitive
|
||||||
description:
|
description:
|
||||||
name: file_selector_ios
|
name: file_selector_ios
|
||||||
sha256: "2f48db7e338b2255101c35c604b7ca5ab588dce032db7fc418a2fe5f28da63f8"
|
sha256: b015154e6d9fddbc4d08916794df170b44531798c8dd709a026df162d07ad81d
|
||||||
url: "https://pub.dev"
|
url: "https://pub.dev"
|
||||||
source: hosted
|
source: hosted
|
||||||
version: "0.5.1+7"
|
version: "0.5.1+8"
|
||||||
file_selector_linux:
|
file_selector_linux:
|
||||||
dependency: transitive
|
dependency: transitive
|
||||||
description:
|
description:
|
||||||
|
@ -229,10 +229,10 @@ packages:
|
||||||
dependency: transitive
|
dependency: transitive
|
||||||
description:
|
description:
|
||||||
name: file_selector_platform_interface
|
name: file_selector_platform_interface
|
||||||
sha256: "0aa47a725c346825a2bd396343ce63ac00bda6eff2fbc43eabe99737dede8262"
|
sha256: a3994c26f10378a039faa11de174d7b78eb8f79e4dd0af2a451410c1a5c3f66b
|
||||||
url: "https://pub.dev"
|
url: "https://pub.dev"
|
||||||
source: hosted
|
source: hosted
|
||||||
version: "2.6.1"
|
version: "2.6.2"
|
||||||
file_selector_web:
|
file_selector_web:
|
||||||
dependency: transitive
|
dependency: transitive
|
||||||
description:
|
description:
|
||||||
|
@ -253,10 +253,10 @@ packages:
|
||||||
dependency: "direct main"
|
dependency: "direct main"
|
||||||
description:
|
description:
|
||||||
name: fl_chart
|
name: fl_chart
|
||||||
sha256: fe6fec7d85975a99c73b9515a69a6e291364accfa0e4a5b3ce6de814d74b9a1c
|
sha256: "00b74ae680df6b1135bdbea00a7d1fc072a9180b7c3f3702e4b19a9943f5ed7d"
|
||||||
url: "https://pub.dev"
|
url: "https://pub.dev"
|
||||||
source: hosted
|
source: hosted
|
||||||
version: "0.66.0"
|
version: "0.66.2"
|
||||||
flutter:
|
flutter:
|
||||||
dependency: "direct main"
|
dependency: "direct main"
|
||||||
description: flutter
|
description: flutter
|
||||||
|
@ -295,10 +295,10 @@ packages:
|
||||||
dependency: "direct main"
|
dependency: "direct main"
|
||||||
description:
|
description:
|
||||||
name: flutter_markdown
|
name: flutter_markdown
|
||||||
sha256: "35108526a233cc0755664d445f8a6b4b61e6f8fe993b3658b80b4a26827fc196"
|
sha256: "87e11b9df25a42e2db315b8b7a51fae8e66f57a4b2f50ec4b822d0fa155e6b52"
|
||||||
url: "https://pub.dev"
|
url: "https://pub.dev"
|
||||||
source: hosted
|
source: hosted
|
||||||
version: "0.6.18+2"
|
version: "0.6.22"
|
||||||
flutter_plugin_android_lifecycle:
|
flutter_plugin_android_lifecycle:
|
||||||
dependency: transitive
|
dependency: transitive
|
||||||
description:
|
description:
|
||||||
|
@ -311,10 +311,10 @@ packages:
|
||||||
dependency: "direct main"
|
dependency: "direct main"
|
||||||
description:
|
description:
|
||||||
name: flutter_svg
|
name: flutter_svg
|
||||||
sha256: d39e7f95621fc84376bc0f7d504f05c3a41488c562f4a8ad410569127507402c
|
sha256: "7b4ca6cf3304575fe9c8ec64813c8d02ee41d2afe60bcfe0678bcb5375d596a2"
|
||||||
url: "https://pub.dev"
|
url: "https://pub.dev"
|
||||||
source: hosted
|
source: hosted
|
||||||
version: "2.0.9"
|
version: "2.0.10+1"
|
||||||
flutter_test:
|
flutter_test:
|
||||||
dependency: "direct dev"
|
dependency: "direct dev"
|
||||||
description: flutter
|
description: flutter
|
||||||
|
@ -345,18 +345,18 @@ packages:
|
||||||
dependency: "direct main"
|
dependency: "direct main"
|
||||||
description:
|
description:
|
||||||
name: go_router
|
name: go_router
|
||||||
sha256: ca7e4a2249f96773152f1853fa25933ac752495cdd7fdf5dafb9691bd05830fd
|
sha256: "7ecb2f391edbca5473db591b48555a8912dde60edd0fb3013bd6743033b2d3f8"
|
||||||
url: "https://pub.dev"
|
url: "https://pub.dev"
|
||||||
source: hosted
|
source: hosted
|
||||||
version: "13.0.0"
|
version: "13.2.1"
|
||||||
http:
|
http:
|
||||||
dependency: "direct main"
|
dependency: "direct main"
|
||||||
description:
|
description:
|
||||||
name: http
|
name: http
|
||||||
sha256: d4872660c46d929f6b8a9ef4e7a7eff7e49bbf0c4ec3f385ee32df5119175139
|
sha256: a2bbf9d017fcced29139daa8ed2bba4ece450ab222871df93ca9eec6f80c34ba
|
||||||
url: "https://pub.dev"
|
url: "https://pub.dev"
|
||||||
source: hosted
|
source: hosted
|
||||||
version: "1.1.2"
|
version: "1.2.0"
|
||||||
http_multi_server:
|
http_multi_server:
|
||||||
dependency: transitive
|
dependency: transitive
|
||||||
description:
|
description:
|
||||||
|
@ -377,10 +377,10 @@ packages:
|
||||||
dependency: transitive
|
dependency: transitive
|
||||||
description:
|
description:
|
||||||
name: image
|
name: image
|
||||||
sha256: "028f61960d56f26414eb616b48b04eb37d700cbe477b7fb09bf1d7ce57fd9271"
|
sha256: "4c68bfd5ae83e700b5204c1e74451e7bf3cf750e6843c6e158289cf56bda018e"
|
||||||
url: "https://pub.dev"
|
url: "https://pub.dev"
|
||||||
source: hosted
|
source: hosted
|
||||||
version: "4.1.3"
|
version: "4.1.7"
|
||||||
intl:
|
intl:
|
||||||
dependency: "direct main"
|
dependency: "direct main"
|
||||||
description:
|
description:
|
||||||
|
@ -421,6 +421,30 @@ packages:
|
||||||
url: "https://pub.dev"
|
url: "https://pub.dev"
|
||||||
source: hosted
|
source: hosted
|
||||||
version: "4.8.1"
|
version: "4.8.1"
|
||||||
|
leak_tracker:
|
||||||
|
dependency: transitive
|
||||||
|
description:
|
||||||
|
name: leak_tracker
|
||||||
|
sha256: "78eb209deea09858f5269f5a5b02be4049535f568c07b275096836f01ea323fa"
|
||||||
|
url: "https://pub.dev"
|
||||||
|
source: hosted
|
||||||
|
version: "10.0.0"
|
||||||
|
leak_tracker_flutter_testing:
|
||||||
|
dependency: transitive
|
||||||
|
description:
|
||||||
|
name: leak_tracker_flutter_testing
|
||||||
|
sha256: b46c5e37c19120a8a01918cfaf293547f47269f7cb4b0058f21531c2465d6ef0
|
||||||
|
url: "https://pub.dev"
|
||||||
|
source: hosted
|
||||||
|
version: "2.0.1"
|
||||||
|
leak_tracker_testing:
|
||||||
|
dependency: transitive
|
||||||
|
description:
|
||||||
|
name: leak_tracker_testing
|
||||||
|
sha256: a597f72a664dbd293f3bfc51f9ba69816f84dcd403cdac7066cb3f6003f3ab47
|
||||||
|
url: "https://pub.dev"
|
||||||
|
source: hosted
|
||||||
|
version: "2.0.1"
|
||||||
lints:
|
lints:
|
||||||
dependency: transitive
|
dependency: transitive
|
||||||
description:
|
description:
|
||||||
|
@ -441,34 +465,34 @@ packages:
|
||||||
dependency: transitive
|
dependency: transitive
|
||||||
description:
|
description:
|
||||||
name: markdown
|
name: markdown
|
||||||
sha256: acf35edccc0463a9d7384e437c015a3535772e09714cf60e07eeef3a15870dcd
|
sha256: ef2a1298144e3f985cc736b22e0ccdaf188b5b3970648f2d9dc13efd1d9df051
|
||||||
url: "https://pub.dev"
|
url: "https://pub.dev"
|
||||||
source: hosted
|
source: hosted
|
||||||
version: "7.1.1"
|
version: "7.2.2"
|
||||||
matcher:
|
matcher:
|
||||||
dependency: transitive
|
dependency: transitive
|
||||||
description:
|
description:
|
||||||
name: matcher
|
name: matcher
|
||||||
sha256: "1803e76e6653768d64ed8ff2e1e67bea3ad4b923eb5c56a295c3e634bad5960e"
|
sha256: d2323aa2060500f906aa31a895b4030b6da3ebdcc5619d14ce1aada65cd161cb
|
||||||
url: "https://pub.dev"
|
url: "https://pub.dev"
|
||||||
source: hosted
|
source: hosted
|
||||||
version: "0.12.16"
|
version: "0.12.16+1"
|
||||||
material_color_utilities:
|
material_color_utilities:
|
||||||
dependency: transitive
|
dependency: transitive
|
||||||
description:
|
description:
|
||||||
name: material_color_utilities
|
name: material_color_utilities
|
||||||
sha256: "9528f2f296073ff54cb9fee677df673ace1218163c3bc7628093e7eed5203d41"
|
sha256: "0e0a020085b65b6083975e499759762399b4475f766c21668c4ecca34ea74e5a"
|
||||||
url: "https://pub.dev"
|
url: "https://pub.dev"
|
||||||
source: hosted
|
source: hosted
|
||||||
version: "0.5.0"
|
version: "0.8.0"
|
||||||
meta:
|
meta:
|
||||||
dependency: transitive
|
dependency: transitive
|
||||||
description:
|
description:
|
||||||
name: meta
|
name: meta
|
||||||
sha256: a6e590c838b18133bb482a2745ad77c5bb7715fb0451209e1a7567d416678b8e
|
sha256: d584fa6707a52763a52446f02cc621b077888fb63b93bbcb1143a7be5a0c0c04
|
||||||
url: "https://pub.dev"
|
url: "https://pub.dev"
|
||||||
source: hosted
|
source: hosted
|
||||||
version: "1.10.0"
|
version: "1.11.0"
|
||||||
mime:
|
mime:
|
||||||
dependency: transitive
|
dependency: transitive
|
||||||
description:
|
description:
|
||||||
|
@ -513,10 +537,10 @@ packages:
|
||||||
dependency: "direct main"
|
dependency: "direct main"
|
||||||
description:
|
description:
|
||||||
name: path
|
name: path
|
||||||
sha256: "8829d8a55c13fc0e37127c29fedf290c102f4e40ae94ada574091fe0ff96c917"
|
sha256: "087ce49c3f0dc39180befefc60fdb4acd8f8620e5682fe2476afd0b3688bb4af"
|
||||||
url: "https://pub.dev"
|
url: "https://pub.dev"
|
||||||
source: hosted
|
source: hosted
|
||||||
version: "1.8.3"
|
version: "1.9.0"
|
||||||
path_parsing:
|
path_parsing:
|
||||||
dependency: transitive
|
dependency: transitive
|
||||||
description:
|
description:
|
||||||
|
@ -529,26 +553,26 @@ packages:
|
||||||
dependency: "direct main"
|
dependency: "direct main"
|
||||||
description:
|
description:
|
||||||
name: path_provider
|
name: path_provider
|
||||||
sha256: a1aa8aaa2542a6bc57e381f132af822420216c80d4781f7aa085ca3229208aaa
|
sha256: b27217933eeeba8ff24845c34003b003b2b22151de3c908d0e679e8fe1aa078b
|
||||||
url: "https://pub.dev"
|
url: "https://pub.dev"
|
||||||
source: hosted
|
source: hosted
|
||||||
version: "2.1.1"
|
version: "2.1.2"
|
||||||
path_provider_android:
|
path_provider_android:
|
||||||
dependency: transitive
|
dependency: transitive
|
||||||
description:
|
description:
|
||||||
name: path_provider_android
|
name: path_provider_android
|
||||||
sha256: e595b98692943b4881b219f0a9e3945118d3c16bd7e2813f98ec6e532d905f72
|
sha256: "477184d672607c0a3bf68fbbf601805f92ef79c82b64b4d6eb318cbca4c48668"
|
||||||
url: "https://pub.dev"
|
url: "https://pub.dev"
|
||||||
source: hosted
|
source: hosted
|
||||||
version: "2.2.1"
|
version: "2.2.2"
|
||||||
path_provider_foundation:
|
path_provider_foundation:
|
||||||
dependency: transitive
|
dependency: transitive
|
||||||
description:
|
description:
|
||||||
name: path_provider_foundation
|
name: path_provider_foundation
|
||||||
sha256: "19314d595120f82aca0ba62787d58dde2cc6b5df7d2f0daf72489e38d1b57f2d"
|
sha256: "5a7999be66e000916500be4f15a3633ebceb8302719b47b9cc49ce924125350f"
|
||||||
url: "https://pub.dev"
|
url: "https://pub.dev"
|
||||||
source: hosted
|
source: hosted
|
||||||
version: "2.3.1"
|
version: "2.3.2"
|
||||||
path_provider_linux:
|
path_provider_linux:
|
||||||
dependency: transitive
|
dependency: transitive
|
||||||
description:
|
description:
|
||||||
|
@ -561,10 +585,10 @@ packages:
|
||||||
dependency: transitive
|
dependency: transitive
|
||||||
description:
|
description:
|
||||||
name: path_provider_platform_interface
|
name: path_provider_platform_interface
|
||||||
sha256: "94b1e0dd80970c1ce43d5d4e050a9918fce4f4a775e6142424c30a29a363265c"
|
sha256: "88f5779f72ba699763fa3a3b06aa4bf6de76c8e5de842cf6f29e2e06476c2334"
|
||||||
url: "https://pub.dev"
|
url: "https://pub.dev"
|
||||||
source: hosted
|
source: hosted
|
||||||
version: "2.1.1"
|
version: "2.1.2"
|
||||||
path_provider_windows:
|
path_provider_windows:
|
||||||
dependency: transitive
|
dependency: transitive
|
||||||
description:
|
description:
|
||||||
|
@ -585,26 +609,26 @@ packages:
|
||||||
dependency: transitive
|
dependency: transitive
|
||||||
description:
|
description:
|
||||||
name: platform
|
name: platform
|
||||||
sha256: "0a279f0707af40c890e80b1e9df8bb761694c074ba7e1d4ab1bc4b728e200b59"
|
sha256: "12220bb4b65720483f8fa9450b4332347737cf8213dd2840d8b2c823e47243ec"
|
||||||
url: "https://pub.dev"
|
url: "https://pub.dev"
|
||||||
source: hosted
|
source: hosted
|
||||||
version: "3.1.3"
|
version: "3.1.4"
|
||||||
plugin_platform_interface:
|
plugin_platform_interface:
|
||||||
dependency: transitive
|
dependency: transitive
|
||||||
description:
|
description:
|
||||||
name: plugin_platform_interface
|
name: plugin_platform_interface
|
||||||
sha256: f4f88d4a900933e7267e2b353594774fc0d07fb072b47eedcd5b54e1ea3269f8
|
sha256: "4820fbfdb9478b1ebae27888254d445073732dae3d6ea81f0b7e06d5dedc3f02"
|
||||||
url: "https://pub.dev"
|
url: "https://pub.dev"
|
||||||
source: hosted
|
source: hosted
|
||||||
version: "2.1.7"
|
version: "2.1.8"
|
||||||
pointycastle:
|
pointycastle:
|
||||||
dependency: transitive
|
dependency: transitive
|
||||||
description:
|
description:
|
||||||
name: pointycastle
|
name: pointycastle
|
||||||
sha256: "7c1e5f0d23c9016c5bbd8b1473d0d3fb3fc851b876046039509e18e0c7485f2c"
|
sha256: "43ac87de6e10afabc85c445745a7b799e04de84cebaa4fd7bf55a5e1e9604d29"
|
||||||
url: "https://pub.dev"
|
url: "https://pub.dev"
|
||||||
source: hosted
|
source: hosted
|
||||||
version: "3.7.3"
|
version: "3.7.4"
|
||||||
pool:
|
pool:
|
||||||
dependency: transitive
|
dependency: transitive
|
||||||
description:
|
description:
|
||||||
|
@ -617,10 +641,10 @@ packages:
|
||||||
dependency: transitive
|
dependency: transitive
|
||||||
description:
|
description:
|
||||||
name: process_run
|
name: process_run
|
||||||
sha256: "3d5335d17003a7c2fd5148be2d313f5b84244ab2e625162fdd44b4aaa48bea66"
|
sha256: "8d9c6198b98fbbfb511edd42e7364e24d85c163e47398919871b952dc86a423e"
|
||||||
url: "https://pub.dev"
|
url: "https://pub.dev"
|
||||||
source: hosted
|
source: hosted
|
||||||
version: "0.13.3+1"
|
version: "0.14.2"
|
||||||
pub_semver:
|
pub_semver:
|
||||||
dependency: transitive
|
dependency: transitive
|
||||||
description:
|
description:
|
||||||
|
@ -657,10 +681,10 @@ packages:
|
||||||
dependency: transitive
|
dependency: transitive
|
||||||
description:
|
description:
|
||||||
name: shared_preferences_foundation
|
name: shared_preferences_foundation
|
||||||
sha256: "7bf53a9f2d007329ee6f3df7268fd498f8373602f943c975598bbb34649b62a7"
|
sha256: "7708d83064f38060c7b39db12aefe449cb8cdc031d6062280087bc4cdb988f5c"
|
||||||
url: "https://pub.dev"
|
url: "https://pub.dev"
|
||||||
source: hosted
|
source: hosted
|
||||||
version: "2.3.4"
|
version: "2.3.5"
|
||||||
shared_preferences_linux:
|
shared_preferences_linux:
|
||||||
dependency: transitive
|
dependency: transitive
|
||||||
description:
|
description:
|
||||||
|
@ -673,10 +697,10 @@ packages:
|
||||||
dependency: transitive
|
dependency: transitive
|
||||||
description:
|
description:
|
||||||
name: shared_preferences_platform_interface
|
name: shared_preferences_platform_interface
|
||||||
sha256: d4ec5fc9ebb2f2e056c617112aa75dcf92fc2e4faaf2ae999caa297473f75d8a
|
sha256: "22e2ecac9419b4246d7c22bfbbda589e3acf5c0351137d87dd2939d984d37c3b"
|
||||||
url: "https://pub.dev"
|
url: "https://pub.dev"
|
||||||
source: hosted
|
source: hosted
|
||||||
version: "2.3.1"
|
version: "2.3.2"
|
||||||
shared_preferences_web:
|
shared_preferences_web:
|
||||||
dependency: transitive
|
dependency: transitive
|
||||||
description:
|
description:
|
||||||
|
@ -734,18 +758,18 @@ packages:
|
||||||
dependency: "direct main"
|
dependency: "direct main"
|
||||||
description:
|
description:
|
||||||
name: slang
|
name: slang
|
||||||
sha256: "77fd99f7b0da15e671ef0289b24a0a63e74f693c58a0ca54111388e4c0ddb1dd"
|
sha256: "5e08ac915ac27a3508863f37734280d30c3713d56746cd2e4a5da77413da4b95"
|
||||||
url: "https://pub.dev"
|
url: "https://pub.dev"
|
||||||
source: hosted
|
source: hosted
|
||||||
version: "3.28.0"
|
version: "3.30.1"
|
||||||
slang_flutter:
|
slang_flutter:
|
||||||
dependency: "direct main"
|
dependency: "direct main"
|
||||||
description:
|
description:
|
||||||
name: slang_flutter
|
name: slang_flutter
|
||||||
sha256: "57817bb15553bb5df37aed3bac497286bdd8c2eab6763f4de6815efe2c0becee"
|
sha256: "9ee040b0d364d3a4d692e4af536acff6ef513870689403494ebc6d59b0dccea6"
|
||||||
url: "https://pub.dev"
|
url: "https://pub.dev"
|
||||||
source: hosted
|
source: hosted
|
||||||
version: "3.28.0"
|
version: "3.30.0"
|
||||||
source_map_stack_trace:
|
source_map_stack_trace:
|
||||||
dependency: transitive
|
dependency: transitive
|
||||||
description:
|
description:
|
||||||
|
@ -774,50 +798,50 @@ packages:
|
||||||
dependency: "direct main"
|
dependency: "direct main"
|
||||||
description:
|
description:
|
||||||
name: sqflite
|
name: sqflite
|
||||||
sha256: "591f1602816e9c31377d5f008c2d9ef7b8aca8941c3f89cc5fd9d84da0c38a9a"
|
sha256: a9016f495c927cb90557c909ff26a6d92d9bd54fc42ba92e19d4e79d61e798c6
|
||||||
url: "https://pub.dev"
|
url: "https://pub.dev"
|
||||||
source: hosted
|
source: hosted
|
||||||
version: "2.3.0"
|
version: "2.3.2"
|
||||||
sqflite_common:
|
sqflite_common:
|
||||||
dependency: transitive
|
dependency: transitive
|
||||||
description:
|
description:
|
||||||
name: sqflite_common
|
name: sqflite_common
|
||||||
sha256: bb4738f15b23352822f4c42a531677e5c6f522e079461fd240ead29d8d8a54a6
|
sha256: "3da423ce7baf868be70e2c0976c28a1bb2f73644268b7ffa7d2e08eab71f16a4"
|
||||||
url: "https://pub.dev"
|
url: "https://pub.dev"
|
||||||
source: hosted
|
source: hosted
|
||||||
version: "2.5.0+2"
|
version: "2.5.4"
|
||||||
sqflite_common_ffi:
|
sqflite_common_ffi:
|
||||||
dependency: "direct main"
|
dependency: "direct main"
|
||||||
description:
|
description:
|
||||||
name: sqflite_common_ffi
|
name: sqflite_common_ffi
|
||||||
sha256: "873677ee78738a723d1ded4ccb23980581998d873d30ee9c331f6a81748663ff"
|
sha256: "4d6137c29e930d6e4a8ff373989dd9de7bac12e3bc87bce950f6e844e8ad3bb5"
|
||||||
url: "https://pub.dev"
|
url: "https://pub.dev"
|
||||||
source: hosted
|
source: hosted
|
||||||
version: "2.3.1"
|
version: "2.3.3"
|
||||||
sqflite_common_ffi_web:
|
sqflite_common_ffi_web:
|
||||||
dependency: "direct main"
|
dependency: "direct main"
|
||||||
description:
|
description:
|
||||||
name: sqflite_common_ffi_web
|
name: sqflite_common_ffi_web
|
||||||
sha256: "3d4b550a09fda9eb0a9ce3bd98c8080f57b2cc1f4b19e844290e82843e73b63d"
|
sha256: "0c2921454d2e4a227675fb952be9fef916cf65fb9e9b606b54cfdf080d3e9450"
|
||||||
url: "https://pub.dev"
|
url: "https://pub.dev"
|
||||||
source: hosted
|
source: hosted
|
||||||
version: "0.4.2+2"
|
version: "0.4.2+3"
|
||||||
sqlite3:
|
sqlite3:
|
||||||
dependency: transitive
|
dependency: transitive
|
||||||
description:
|
description:
|
||||||
name: sqlite3
|
name: sqlite3
|
||||||
sha256: c4a4c5a4b2a32e2d0f6837b33d7c91a67903891a5b7dbe706cf4b1f6b0c798c5
|
sha256: "072128763f1547e3e9b4735ce846bfd226d68019ccda54db4cd427b12dfdedc9"
|
||||||
url: "https://pub.dev"
|
url: "https://pub.dev"
|
||||||
source: hosted
|
source: hosted
|
||||||
version: "2.3.0"
|
version: "2.4.0"
|
||||||
sqlite3_flutter_libs:
|
sqlite3_flutter_libs:
|
||||||
dependency: "direct main"
|
dependency: "direct main"
|
||||||
description:
|
description:
|
||||||
name: sqlite3_flutter_libs
|
name: sqlite3_flutter_libs
|
||||||
sha256: "3e3583b77cf888a68eae2e49ee4f025f66b86623ef0d83c297c8d903daa14871"
|
sha256: d6c31c8511c441d1f12f20b607343df1afe4eddf24a1cf85021677c8eea26060
|
||||||
url: "https://pub.dev"
|
url: "https://pub.dev"
|
||||||
source: hosted
|
source: hosted
|
||||||
version: "0.5.18"
|
version: "0.5.20"
|
||||||
stack_trace:
|
stack_trace:
|
||||||
dependency: transitive
|
dependency: transitive
|
||||||
description:
|
description:
|
||||||
|
@ -846,18 +870,18 @@ packages:
|
||||||
dependency: transitive
|
dependency: transitive
|
||||||
description:
|
description:
|
||||||
name: syncfusion_flutter_core
|
name: syncfusion_flutter_core
|
||||||
sha256: "69c827931957d5b121ee9f0b9b0b8d7d0d1ac537b61bcdd5c3fbffc044bbe86e"
|
sha256: "7666506885ebc8f62bb928ad4588a73e20caaff2b2cf2b2b56f67d98f4113525"
|
||||||
url: "https://pub.dev"
|
url: "https://pub.dev"
|
||||||
source: hosted
|
source: hosted
|
||||||
version: "24.1.41"
|
version: "24.2.9"
|
||||||
syncfusion_flutter_gauges:
|
syncfusion_flutter_gauges:
|
||||||
dependency: "direct main"
|
dependency: "direct main"
|
||||||
description:
|
description:
|
||||||
name: syncfusion_flutter_gauges
|
name: syncfusion_flutter_gauges
|
||||||
sha256: "78515dcfbed952c36ab9ca4a1e6c99737beb7c6cf2312efe8beca2bd314a3955"
|
sha256: "87be13e520fc1676a725691446f411f549ea5b6ff2580234db0479799f213757"
|
||||||
url: "https://pub.dev"
|
url: "https://pub.dev"
|
||||||
source: hosted
|
source: hosted
|
||||||
version: "24.1.41"
|
version: "24.2.9"
|
||||||
synchronized:
|
synchronized:
|
||||||
dependency: transitive
|
dependency: transitive
|
||||||
description:
|
description:
|
||||||
|
@ -910,26 +934,26 @@ packages:
|
||||||
dependency: "direct main"
|
dependency: "direct main"
|
||||||
description:
|
description:
|
||||||
name: url_launcher
|
name: url_launcher
|
||||||
sha256: e9aa5ea75c84cf46b3db4eea212523591211c3cf2e13099ee4ec147f54201c86
|
sha256: "0ecc004c62fd3ed36a2ffcbe0dd9700aee63bd7532d0b642a488b1ec310f492e"
|
||||||
url: "https://pub.dev"
|
url: "https://pub.dev"
|
||||||
source: hosted
|
source: hosted
|
||||||
version: "6.2.2"
|
version: "6.2.5"
|
||||||
url_launcher_android:
|
url_launcher_android:
|
||||||
dependency: transitive
|
dependency: transitive
|
||||||
description:
|
description:
|
||||||
name: url_launcher_android
|
name: url_launcher_android
|
||||||
sha256: "31222ffb0063171b526d3e569079cf1f8b294075ba323443fdc690842bfd4def"
|
sha256: d4ed0711849dd8e33eb2dd69c25db0d0d3fdc37e0a62e629fe32f57a22db2745
|
||||||
url: "https://pub.dev"
|
url: "https://pub.dev"
|
||||||
source: hosted
|
source: hosted
|
||||||
version: "6.2.0"
|
version: "6.3.0"
|
||||||
url_launcher_ios:
|
url_launcher_ios:
|
||||||
dependency: transitive
|
dependency: transitive
|
||||||
description:
|
description:
|
||||||
name: url_launcher_ios
|
name: url_launcher_ios
|
||||||
sha256: bba3373219b7abb6b5e0d071b0fe66dfbe005d07517a68e38d4fc3638f35c6d3
|
sha256: "9149d493b075ed740901f3ee844a38a00b33116c7c5c10d7fb27df8987fb51d5"
|
||||||
url: "https://pub.dev"
|
url: "https://pub.dev"
|
||||||
source: hosted
|
source: hosted
|
||||||
version: "6.2.1"
|
version: "6.2.5"
|
||||||
url_launcher_linux:
|
url_launcher_linux:
|
||||||
dependency: transitive
|
dependency: transitive
|
||||||
description:
|
description:
|
||||||
|
@ -950,18 +974,18 @@ packages:
|
||||||
dependency: transitive
|
dependency: transitive
|
||||||
description:
|
description:
|
||||||
name: url_launcher_platform_interface
|
name: url_launcher_platform_interface
|
||||||
sha256: "980e8d9af422f477be6948bdfb68df8433be71f5743a188968b0c1b887807e50"
|
sha256: "552f8a1e663569be95a8190206a38187b531910283c3e982193e4f2733f01029"
|
||||||
url: "https://pub.dev"
|
url: "https://pub.dev"
|
||||||
source: hosted
|
source: hosted
|
||||||
version: "2.2.0"
|
version: "2.3.2"
|
||||||
url_launcher_web:
|
url_launcher_web:
|
||||||
dependency: transitive
|
dependency: transitive
|
||||||
description:
|
description:
|
||||||
name: url_launcher_web
|
name: url_launcher_web
|
||||||
sha256: "7286aec002c8feecc338cc33269e96b73955ab227456e9fb2a91f7fab8a358e9"
|
sha256: fff0932192afeedf63cdd50ecbb1bc825d31aed259f02bb8dba0f3b729a5e88b
|
||||||
url: "https://pub.dev"
|
url: "https://pub.dev"
|
||||||
source: hosted
|
source: hosted
|
||||||
version: "2.2.2"
|
version: "2.2.3"
|
||||||
url_launcher_windows:
|
url_launcher_windows:
|
||||||
dependency: transitive
|
dependency: transitive
|
||||||
description:
|
description:
|
||||||
|
@ -974,26 +998,26 @@ packages:
|
||||||
dependency: transitive
|
dependency: transitive
|
||||||
description:
|
description:
|
||||||
name: vector_graphics
|
name: vector_graphics
|
||||||
sha256: "0f0c746dd2d6254a0057218ff980fc7f5670fd0fcf5e4db38a490d31eed4ad43"
|
sha256: "32c3c684e02f9bc0afb0ae0aa653337a2fe022e8ab064bcd7ffda27a74e288e3"
|
||||||
url: "https://pub.dev"
|
url: "https://pub.dev"
|
||||||
source: hosted
|
source: hosted
|
||||||
version: "1.1.9+1"
|
version: "1.1.11+1"
|
||||||
vector_graphics_codec:
|
vector_graphics_codec:
|
||||||
dependency: transitive
|
dependency: transitive
|
||||||
description:
|
description:
|
||||||
name: vector_graphics_codec
|
name: vector_graphics_codec
|
||||||
sha256: "0edf6d630d1bfd5589114138ed8fada3234deacc37966bec033d3047c29248b7"
|
sha256: c86987475f162fadff579e7320c7ddda04cd2fdeffbe1129227a85d9ac9e03da
|
||||||
url: "https://pub.dev"
|
url: "https://pub.dev"
|
||||||
source: hosted
|
source: hosted
|
||||||
version: "1.1.9+1"
|
version: "1.1.11+1"
|
||||||
vector_graphics_compiler:
|
vector_graphics_compiler:
|
||||||
dependency: transitive
|
dependency: transitive
|
||||||
description:
|
description:
|
||||||
name: vector_graphics_compiler
|
name: vector_graphics_compiler
|
||||||
sha256: d24333727332d9bd20990f1483af4e09abdb9b1fc7c3db940b56ab5c42790c26
|
sha256: "12faff3f73b1741a36ca7e31b292ddeb629af819ca9efe9953b70bd63fc8cd81"
|
||||||
url: "https://pub.dev"
|
url: "https://pub.dev"
|
||||||
source: hosted
|
source: hosted
|
||||||
version: "1.1.9+1"
|
version: "1.1.11+1"
|
||||||
vector_math:
|
vector_math:
|
||||||
dependency: "direct main"
|
dependency: "direct main"
|
||||||
description:
|
description:
|
||||||
|
@ -1022,18 +1046,18 @@ packages:
|
||||||
dependency: transitive
|
dependency: transitive
|
||||||
description:
|
description:
|
||||||
name: web
|
name: web
|
||||||
sha256: afe077240a270dcfd2aafe77602b4113645af95d0ad31128cc02bce5ac5d5152
|
sha256: "4188706108906f002b3a293509234588823c8c979dc83304e229ff400c996b05"
|
||||||
url: "https://pub.dev"
|
url: "https://pub.dev"
|
||||||
source: hosted
|
source: hosted
|
||||||
version: "0.3.0"
|
version: "0.4.2"
|
||||||
web_socket_channel:
|
web_socket_channel:
|
||||||
dependency: transitive
|
dependency: transitive
|
||||||
description:
|
description:
|
||||||
name: web_socket_channel
|
name: web_socket_channel
|
||||||
sha256: d88238e5eac9a42bb43ca4e721edba3c08c6354d4a53063afaa568516217621b
|
sha256: "939ab60734a4f8fa95feacb55804fa278de28bdeef38e616dc08e44a84adea23"
|
||||||
url: "https://pub.dev"
|
url: "https://pub.dev"
|
||||||
source: hosted
|
source: hosted
|
||||||
version: "2.4.0"
|
version: "2.4.3"
|
||||||
webkit_inspection_protocol:
|
webkit_inspection_protocol:
|
||||||
dependency: transitive
|
dependency: transitive
|
||||||
description:
|
description:
|
||||||
|
@ -1046,26 +1070,26 @@ packages:
|
||||||
dependency: transitive
|
dependency: transitive
|
||||||
description:
|
description:
|
||||||
name: win32
|
name: win32
|
||||||
sha256: b0f37db61ba2f2e9b7a78a1caece0052564d1bc70668156cf3a29d676fe4e574
|
sha256: "8cb58b45c47dcb42ab3651533626161d6b67a2921917d8d429791f76972b3480"
|
||||||
url: "https://pub.dev"
|
url: "https://pub.dev"
|
||||||
source: hosted
|
source: hosted
|
||||||
version: "5.1.1"
|
version: "5.3.0"
|
||||||
window_manager:
|
window_manager:
|
||||||
dependency: "direct main"
|
dependency: "direct main"
|
||||||
description:
|
description:
|
||||||
name: window_manager
|
name: window_manager
|
||||||
sha256: dcc865277f26a7dad263a47d0e405d77e21f12cb71f30333a52710a408690bd7
|
sha256: b3c895bdf936c77b83c5254bec2e6b3f066710c1f89c38b20b8acc382b525494
|
||||||
url: "https://pub.dev"
|
url: "https://pub.dev"
|
||||||
source: hosted
|
source: hosted
|
||||||
version: "0.3.7"
|
version: "0.3.8"
|
||||||
xdg_directories:
|
xdg_directories:
|
||||||
dependency: transitive
|
dependency: transitive
|
||||||
description:
|
description:
|
||||||
name: xdg_directories
|
name: xdg_directories
|
||||||
sha256: "589ada45ba9e39405c198fe34eb0f607cddb2108527e658136120892beac46d2"
|
sha256: faea9dee56b520b55a566385b84f2e8de55e7496104adada9962e0bd11bcff1d
|
||||||
url: "https://pub.dev"
|
url: "https://pub.dev"
|
||||||
source: hosted
|
source: hosted
|
||||||
version: "1.0.3"
|
version: "1.0.4"
|
||||||
xml:
|
xml:
|
||||||
dependency: transitive
|
dependency: transitive
|
||||||
description:
|
description:
|
||||||
|
@ -1083,5 +1107,5 @@ packages:
|
||||||
source: hosted
|
source: hosted
|
||||||
version: "3.1.2"
|
version: "3.1.2"
|
||||||
sdks:
|
sdks:
|
||||||
dart: ">=3.2.0 <4.0.0"
|
dart: ">=3.3.0 <4.0.0"
|
||||||
flutter: ">=3.16.0"
|
flutter: ">=3.19.0"
|
||||||
|
|
|
@ -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.4.1+15
|
version: 1.5.0+16
|
||||||
|
|
||||||
environment:
|
environment:
|
||||||
sdk: '>=3.0.0'
|
sdk: '>=3.0.0'
|
||||||
|
|
|
@ -46,6 +46,14 @@
|
||||||
"stoppedBeingTracked": "Removed from tracking list!",
|
"stoppedBeingTracked": "Removed from tracking list!",
|
||||||
"tlLeaderboard": "Tetra League leaderboard",
|
"tlLeaderboard": "Tetra League leaderboard",
|
||||||
"noRecords": "No records",
|
"noRecords": "No records",
|
||||||
|
"noOldRecords": {
|
||||||
|
"zero": "No records",
|
||||||
|
"one": "Only $n record",
|
||||||
|
"two": "Only $n records",
|
||||||
|
"few": "Only $n records",
|
||||||
|
"many": "Only $n records",
|
||||||
|
"other": "Only $n records"
|
||||||
|
},
|
||||||
"noRecord": "No record",
|
"noRecord": "No record",
|
||||||
"botRecord": "Bots are not allowed to set records",
|
"botRecord": "Bots are not allowed to set records",
|
||||||
"anonRecord": "Guests are not allowed to set records",
|
"anonRecord": "Guests are not allowed to set records",
|
||||||
|
@ -69,7 +77,10 @@
|
||||||
"supporter": "Supporter tier ${tier}",
|
"supporter": "Supporter tier ${tier}",
|
||||||
"comparingWith": "Data from ${newDate} comparing with ${oldDate}",
|
"comparingWith": "Data from ${newDate} comparing with ${oldDate}",
|
||||||
"top": "Top",
|
"top": "Top",
|
||||||
"topRank": "Top Rank",
|
"topRank": "Top rank",
|
||||||
|
"verdictGeneral": "$n $verdict than $rank rank average",
|
||||||
|
"verdictBetter": "better",
|
||||||
|
"verdictWorse": "worse",
|
||||||
"gamesUntilRanked": "${left} games until being ranked",
|
"gamesUntilRanked": "${left} games until being ranked",
|
||||||
"nerdStats": "Nerd Stats",
|
"nerdStats": "Nerd Stats",
|
||||||
"playersYouTrack": "Players you track",
|
"playersYouTrack": "Players you track",
|
||||||
|
@ -93,8 +104,14 @@
|
||||||
"yourIDAlertTitle": "Your nickname in TETR.IO",
|
"yourIDAlertTitle": "Your nickname in TETR.IO",
|
||||||
"yourIDText": "When app loads, it will retrieve data for this account",
|
"yourIDText": "When app loads, it will retrieve data for this account",
|
||||||
"language": "Language",
|
"language": "Language",
|
||||||
|
"customization": "Customization",
|
||||||
|
"customizationDescription": "There is only one toggle, planned to add more settings",
|
||||||
|
"lbStats": "Show leaderboard based stats",
|
||||||
|
"lbStatsDescription": "That will impact on loading times, but will allow you to see position on LB by stats and comparison with average values",
|
||||||
"aboutApp": "About app",
|
"aboutApp": "About app",
|
||||||
"aboutAppText": "${appName} (${packageName}) Version ${version} Build ${buildNumber}\n\nDeveloped by dan63047\nFormulas provided by kerrmunism\nHistory provided by p1nkl0bst3r\nTETR.IO replay grabber API by szy",
|
"aboutAppText": "${appName} (${packageName}) Version ${version} Build ${buildNumber}\n\nDeveloped by dan63047\nFormulas provided by kerrmunism\nHistory provided by p1nkl0bst3r\nTETR.IO replay grabber API by szy",
|
||||||
|
"oskKagari": "Osk Kagari gimmick",
|
||||||
|
"oskKagariDescription": "If on, osk's rank on main view will be rendered as :kagari:",
|
||||||
"stateViewTitle": "${nickname} account on ${date}",
|
"stateViewTitle": "${nickname} account on ${date}",
|
||||||
"statesViewTitle": "${number} states of ${nickname} account",
|
"statesViewTitle": "${number} states of ${nickname} account",
|
||||||
"matchesViewTitle": "${nickname} TL matches",
|
"matchesViewTitle": "${nickname} TL matches",
|
||||||
|
@ -119,10 +136,14 @@
|
||||||
"openReplay": "Open replay in TETR.IO",
|
"openReplay": "Open replay in TETR.IO",
|
||||||
"replaySaved": "Replay saved to ${path}",
|
"replaySaved": "Replay saved to ${path}",
|
||||||
"match": "Match",
|
"match": "Match",
|
||||||
|
"timeWeightedmatch": "Match (time-weighted)",
|
||||||
"roundNumber": "Round $n",
|
"roundNumber": "Round $n",
|
||||||
"statsFor": "Stats for",
|
"statsFor": "Stats for",
|
||||||
|
"numberOfRounds": "Number of rounds",
|
||||||
"matchLength": "Match Length",
|
"matchLength": "Match Length",
|
||||||
"roundLength": "Round Length",
|
"roundLength": "Round Length",
|
||||||
|
"matchStats": "Match stats",
|
||||||
|
"timeWeightedmatchStats": "Time-weighted match stats",
|
||||||
"replayIssue": "Can't process replay",
|
"replayIssue": "Can't process replay",
|
||||||
"matchIsTooOld": "Replay is not available",
|
"matchIsTooOld": "Replay is not available",
|
||||||
"winner": "Winner",
|
"winner": "Winner",
|
||||||
|
@ -159,6 +180,15 @@
|
||||||
"many": "$n players",
|
"many": "$n players",
|
||||||
"other": "$n players"
|
"other": "$n players"
|
||||||
},
|
},
|
||||||
|
"games": {
|
||||||
|
"zero": "$n games",
|
||||||
|
"one": "$n game",
|
||||||
|
"two": "$n games",
|
||||||
|
"few": "$n games",
|
||||||
|
"many": "$n games",
|
||||||
|
"other": "$n games"
|
||||||
|
},
|
||||||
|
"gamesPlayed": "$games played",
|
||||||
"chart": "Chart",
|
"chart": "Chart",
|
||||||
"entries": "Entries",
|
"entries": "Entries",
|
||||||
"minimums": "Minimums",
|
"minimums": "Minimums",
|
||||||
|
@ -238,8 +268,30 @@
|
||||||
"numOfGameActions":{
|
"numOfGameActions":{
|
||||||
"pc": "All Clears",
|
"pc": "All Clears",
|
||||||
"hold": "Holds",
|
"hold": "Holds",
|
||||||
"tspinsTotal": "T-spins total",
|
"inputs": {
|
||||||
"lineClears": "Line clears"
|
"zero": "$n key presses",
|
||||||
|
"one": "$n key press",
|
||||||
|
"two": "$n key presses",
|
||||||
|
"few": "$n key presses",
|
||||||
|
"many": "$n key presses",
|
||||||
|
"other": "$n key presses"
|
||||||
|
},
|
||||||
|
"tspinsTotal": {
|
||||||
|
"zero": "$n T-spins total",
|
||||||
|
"one": "$n T-spin total",
|
||||||
|
"two": "$n T-spins total",
|
||||||
|
"few": "$n T-spins total",
|
||||||
|
"many": "$n T-spins total",
|
||||||
|
"other": "$n T-spins total"
|
||||||
|
},
|
||||||
|
"lineClears": {
|
||||||
|
"zero": "$n lines cleared",
|
||||||
|
"one": "$n line cleared",
|
||||||
|
"two": "$n lines cleared",
|
||||||
|
"few": "$n lines cleared",
|
||||||
|
"many": "$n lines cleared",
|
||||||
|
"other": "$n lines cleared"
|
||||||
|
}
|
||||||
},
|
},
|
||||||
"popupActions":{
|
"popupActions":{
|
||||||
"cancel": "Cancel",
|
"cancel": "Cancel",
|
||||||
|
@ -249,21 +301,30 @@
|
||||||
"errors":{
|
"errors":{
|
||||||
"connection": "Some issue with connection: ${code} ${message}",
|
"connection": "Some issue with connection: ${code} ${message}",
|
||||||
"noSuchUser": "No such user",
|
"noSuchUser": "No such user",
|
||||||
|
"noSuchUserSub": "Either you mistyped something, or the account no longer exists",
|
||||||
|
"discordNotAssigned": "No user assigned to given Discord ID",
|
||||||
|
"discordNotAssignedSub": "Make sure you provided valid ID",
|
||||||
"history": "History for that player is missing",
|
"history": "History for that player is missing",
|
||||||
|
"actionSuggestion": "Perhaps, you want to",
|
||||||
"p1nkl0bst3rTLmatches": "No Tetra League matches was found",
|
"p1nkl0bst3rTLmatches": "No Tetra League matches was found",
|
||||||
"clientException": "No internet connection",
|
"clientException": "No internet connection",
|
||||||
"forbidden": "Your IP address is blocked.\nChange IP address or reach out to osk",
|
"forbidden": "Your IP address is blocked",
|
||||||
"tooManyRequests": "You have been rate limited. Try again later",
|
"forbiddenSub": "If you are using VPN or Proxy, turn it off. If this does not help, reach out to $nickname",
|
||||||
|
"tooManyRequests": "You have been rate limited.",
|
||||||
|
"tooManyRequestsSub": "Wait a few moments and try again",
|
||||||
"internal": "Something happend on the tetr.io side",
|
"internal": "Something happend on the tetr.io side",
|
||||||
|
"internalSub": "osk, probably, already aware about it",
|
||||||
"internalWebVersion": "Something happend on the tetr.io side (or on oskware_bridge, idk honestly)",
|
"internalWebVersion": "Something happend on the tetr.io side (or on oskware_bridge, idk honestly)",
|
||||||
"oskwareBridge": "Something happend with oskware_bridge. Let dan63047 know",
|
"internalWebVersionSub": "If osk status page says that everything is ok, let dan63047 know about this issue",
|
||||||
"p1nkl0bst3rForbidden": "Third party API blocked your IP address.\nChange IP address or reach out to p1nkl0bst3r",
|
"oskwareBridge": "Something happend with oskware_bridge",
|
||||||
|
"oskwareBridgeSub": "Let dan63047 know",
|
||||||
|
"p1nkl0bst3rForbidden": "Third party API blocked your IP address",
|
||||||
"p1nkl0bst3rTooManyRequests": "Too many requests to third party API. Try again later",
|
"p1nkl0bst3rTooManyRequests": "Too many requests to third party API. Try again later",
|
||||||
"p1nkl0bst3rinternal": "Something happend on the p1nkl0bst3r side",
|
"p1nkl0bst3rinternal": "Something happend on the p1nkl0bst3r side",
|
||||||
"p1nkl0bst3rinternalWebVersion": "Something happend on the p1nkl0bst3r side (or on oskware_bridge, idk honestly)",
|
"p1nkl0bst3rinternalWebVersion": "Something happend on the p1nkl0bst3r side (or on oskware_bridge, idk honestly)",
|
||||||
"replayAlreadySaved": "Replay already saved",
|
"replayAlreadySaved": "Replay already saved",
|
||||||
"replayExpired": "Replay expired and not available anymore",
|
"replayExpired": "Replay expired and not available anymore",
|
||||||
"replayRejected": "Third party API blocked your IP address.\nChange IP address or reach out to szy"
|
"replayRejected": "Third party API blocked your IP address"
|
||||||
},
|
},
|
||||||
"countries(map)": {
|
"countries(map)": {
|
||||||
"": "Not selected",
|
"": "Not selected",
|
||||||
|
|
|
@ -46,6 +46,14 @@
|
||||||
"compare": "Сравнить",
|
"compare": "Сравнить",
|
||||||
"tlLeaderboard": "Рейтинговая таблица",
|
"tlLeaderboard": "Рейтинговая таблица",
|
||||||
"noRecords": "Нет записей",
|
"noRecords": "Нет записей",
|
||||||
|
"noOldRecords": {
|
||||||
|
"zero": "Нет записей",
|
||||||
|
"one": "Всего один матч",
|
||||||
|
"two": "Всего $n матча",
|
||||||
|
"few": "Всего $n матча",
|
||||||
|
"many": "Всего $n матчей",
|
||||||
|
"other": "$n матчей"
|
||||||
|
},
|
||||||
"noRecord": "Нет рекорда",
|
"noRecord": "Нет рекорда",
|
||||||
"botRecord": "Ботам нельзя ставить рекорды",
|
"botRecord": "Ботам нельзя ставить рекорды",
|
||||||
"anonRecord": "Гостям нельзя ставить рекорды",
|
"anonRecord": "Гостям нельзя ставить рекорды",
|
||||||
|
@ -69,7 +77,10 @@
|
||||||
"assignedManualy": "Этот значок был присвоен вручную администрацией TETR.IO",
|
"assignedManualy": "Этот значок был присвоен вручную администрацией TETR.IO",
|
||||||
"comparingWith": "Данные от ${newDate} в сравнении с данными от ${oldDate}",
|
"comparingWith": "Данные от ${newDate} в сравнении с данными от ${oldDate}",
|
||||||
"top": "Топ",
|
"top": "Топ",
|
||||||
"topRank": "Топ Ранг",
|
"topRank": "Топ ранг",
|
||||||
|
"verdictGeneral": "$verdict среднего $rank ранга на $n",
|
||||||
|
"verdictBetter": "Лучше",
|
||||||
|
"verdictWorse": "Хуже",
|
||||||
"gamesUntilRanked": "${left} матчей до получения рейтинга",
|
"gamesUntilRanked": "${left} матчей до получения рейтинга",
|
||||||
"nerdStats": "Для задротов",
|
"nerdStats": "Для задротов",
|
||||||
"playersYouTrack": "Отслеживаемые игроки",
|
"playersYouTrack": "Отслеживаемые игроки",
|
||||||
|
@ -93,8 +104,14 @@
|
||||||
"yourIDAlertTitle": "Ваш ник в TETR.IO",
|
"yourIDAlertTitle": "Ваш ник в TETR.IO",
|
||||||
"yourIDText": "При запуске приложения оно будет получать статистику этого игрока.",
|
"yourIDText": "При запуске приложения оно будет получать статистику этого игрока.",
|
||||||
"language": "Язык (Language)",
|
"language": "Язык (Language)",
|
||||||
|
"customization": "Кастомизация",
|
||||||
|
"customizationDescription": "Здесь только один переключатель, в планах добавить больше",
|
||||||
|
"lbStats": "Показывать статистику, основанную на рейтинговой таблице",
|
||||||
|
"lbStatsDescription": "Это повлияет на время загрузки, но позволит видеть положение в рейтинге и сравнение со средними значениями по рангу по каждой стате",
|
||||||
"aboutApp": "О приложении",
|
"aboutApp": "О приложении",
|
||||||
"aboutAppText": "${appName} (${packageName}) Версия ${version} Сборка ${buildNumber}\n\nРазработал dan63047\nФормулы предоставил kerrmunism\nИсторию предоставляет p1nkl0bst3r\nВозможность скачивать повторы из TETR.IO предоставляет szy",
|
"aboutAppText": "${appName} (${packageName}) Версия ${version} Сборка ${buildNumber}\n\nРазработал dan63047\nФормулы предоставил kerrmunism\nИсторию предоставляет p1nkl0bst3r\nВозможность скачивать повторы из TETR.IO предоставляет szy",
|
||||||
|
"oskKagari": "\"Оск Кагари\" прикол",
|
||||||
|
"oskKagariDescription": "Если включено, вместо настоящего ранга оска будет рендерится :kagari:",
|
||||||
"stateViewTitle": "Аккаунт ${nickname} ${date}",
|
"stateViewTitle": "Аккаунт ${nickname} ${date}",
|
||||||
"statesViewTitle": "${number} состояний аккаунта ${nickname}",
|
"statesViewTitle": "${number} состояний аккаунта ${nickname}",
|
||||||
"matchesViewTitle": "Матчи аккаунта ${nickname}",
|
"matchesViewTitle": "Матчи аккаунта ${nickname}",
|
||||||
|
@ -119,10 +136,14 @@
|
||||||
"openReplay": "Открыть повтор в TETR.IO",
|
"openReplay": "Открыть повтор в TETR.IO",
|
||||||
"replaySaved": "Повтор сохранён по пути ${path}",
|
"replaySaved": "Повтор сохранён по пути ${path}",
|
||||||
"match": "Матч",
|
"match": "Матч",
|
||||||
|
"timeWeightedmatch": "Матч (взвешенная по времени)",
|
||||||
"roundNumber": "Раунд $n",
|
"roundNumber": "Раунд $n",
|
||||||
"statsFor": "Статистика за",
|
"statsFor": "Статистика за",
|
||||||
|
"numberOfRounds": "Количество раундов",
|
||||||
"matchLength": "Продолжительность матча",
|
"matchLength": "Продолжительность матча",
|
||||||
"roundLength": "Продолжительность раунда",
|
"roundLength": "Продолжительность раунда",
|
||||||
|
"matchStats": "Статистика матча",
|
||||||
|
"timeWeightedmatchStats": "Взвешенная по времени cтатистика матча",
|
||||||
"replayIssue": "Ошибка обработки повтора",
|
"replayIssue": "Ошибка обработки повтора",
|
||||||
"matchIsTooOld": "Информация о повторе недоступна",
|
"matchIsTooOld": "Информация о повторе недоступна",
|
||||||
"winner": "Победитель",
|
"winner": "Победитель",
|
||||||
|
@ -159,6 +180,15 @@
|
||||||
"many": "$n игроков",
|
"many": "$n игроков",
|
||||||
"other": "$n игроков"
|
"other": "$n игроков"
|
||||||
},
|
},
|
||||||
|
"games": {
|
||||||
|
"zero": "$n игр",
|
||||||
|
"one": "$n игра",
|
||||||
|
"two": "$n игры",
|
||||||
|
"few": "$n игры",
|
||||||
|
"many": "$n игр",
|
||||||
|
"other": "$n игр"
|
||||||
|
},
|
||||||
|
"gamesPlayed": "$games сыграно",
|
||||||
"chart": "График",
|
"chart": "График",
|
||||||
"entries": "Список",
|
"entries": "Список",
|
||||||
"minimums": "Минимумы",
|
"minimums": "Минимумы",
|
||||||
|
@ -238,8 +268,30 @@
|
||||||
"numOfGameActions":{
|
"numOfGameActions":{
|
||||||
"pc": "Все чисто",
|
"pc": "Все чисто",
|
||||||
"hold": "В запас",
|
"hold": "В запас",
|
||||||
"tspinsTotal": "T-spins всего",
|
"inputs": {
|
||||||
"lineClears": "Линий очищено"
|
"zero": "$n нажатий клавиш",
|
||||||
|
"one": "$n нажатие на клавишу",
|
||||||
|
"two": "$n нажатия на клавишы",
|
||||||
|
"few": "$n нажатия на клавишы",
|
||||||
|
"many": "$n нажатий на клавиш",
|
||||||
|
"other": "$n нажатий на клавиш"
|
||||||
|
},
|
||||||
|
"tspinsTotal": {
|
||||||
|
"zero": "$n T-спинов всего",
|
||||||
|
"one": "Всего $n T-спин",
|
||||||
|
"two": "$n T-спина всего",
|
||||||
|
"few": "$n T-спина всего",
|
||||||
|
"many": "$n T-спинов всего",
|
||||||
|
"other": "$n T-спинов всего"
|
||||||
|
},
|
||||||
|
"lineClears": {
|
||||||
|
"zero": "$n линий очищено",
|
||||||
|
"one": "$n линия очищена",
|
||||||
|
"two": "$n линии очищено",
|
||||||
|
"few": "$n линии очищено",
|
||||||
|
"many": "$n линий очищено",
|
||||||
|
"other": "$n линий очищено"
|
||||||
|
}
|
||||||
},
|
},
|
||||||
"popupActions":{
|
"popupActions":{
|
||||||
"cancel": "Отменить",
|
"cancel": "Отменить",
|
||||||
|
@ -249,21 +301,30 @@
|
||||||
"errors":{
|
"errors":{
|
||||||
"connection": "Проблема с подключением: ${code} ${message}",
|
"connection": "Проблема с подключением: ${code} ${message}",
|
||||||
"noSuchUser": "Нет такого пользователя",
|
"noSuchUser": "Нет такого пользователя",
|
||||||
|
"noSuchUserSub": "Либо вы ошиблись при вводе, либо аккаунта больше не существует",
|
||||||
|
"discordNotAssigned": "К данному Discord ID не привязан аккаунт",
|
||||||
|
"discordNotAssignedSub": "Убедитесь в том, что вы вставили правильный ID",
|
||||||
"history": "История данного игрока отсутствует",
|
"history": "История данного игрока отсутствует",
|
||||||
|
"actionSuggestion": "Возможно, вы хотите",
|
||||||
"p1nkl0bst3rTLmatches": "Старых матчей Тетра Лиги не было найдено",
|
"p1nkl0bst3rTLmatches": "Старых матчей Тетра Лиги не было найдено",
|
||||||
"clientException": "Нет соединения с интернетом",
|
"clientException": "Нет соединения с интернетом",
|
||||||
"forbidden": "Ваш IP адрес заблокирован.\nСмените IP адрес или свяжитесь с osk-ом",
|
"forbidden": "Ваш IP адрес заблокирован",
|
||||||
"tooManyRequests": "Слишком много запросов. Попробуйте позже",
|
"forbiddenSub": "Если у вас работает VPN или прокси, выключите его. Если это не помогло, свяжитесь с $nickname",
|
||||||
|
"tooManyRequests": "Слишком много запросов",
|
||||||
|
"tooManyRequestsSub": "Подождите немного и попробуйте снова",
|
||||||
"internal": "Что-то случилось на стороне tetr.io",
|
"internal": "Что-то случилось на стороне tetr.io",
|
||||||
|
"internalSub": "Скорее всего, osk уже в курсе об этом",
|
||||||
"internalWebVersion": "Что-то случилось на стороне tetr.io (или на стороне oskware_bridge, я хз если честно)",
|
"internalWebVersion": "Что-то случилось на стороне tetr.io (или на стороне oskware_bridge, я хз если честно)",
|
||||||
"oskwareBridge": "Что-то случилось с oskware_bridge. Дайте dan63047 знать",
|
"internalWebVersionSub": "Если статус страница osk-а говорит, что всё ок - свяжитесь с dan63047",
|
||||||
"p1nkl0bst3rForbidden": "Стороннее API заблокировало ваш IP адрес.\nСмените IP адрес или свяжитесь с p1nkl0bst3r-ом",
|
"oskwareBridge": "Что-то случилось с oskware_bridge",
|
||||||
|
"oskwareBridgeSub": "Дайте dan63047 знать",
|
||||||
|
"p1nkl0bst3rForbidden": "Стороннее API заблокировало ваш IP адрес",
|
||||||
"p1nkl0bst3rTooManyRequests": "Слишком много запросов к стороннему API. Попробуйте позже",
|
"p1nkl0bst3rTooManyRequests": "Слишком много запросов к стороннему API. Попробуйте позже",
|
||||||
"p1nkl0bst3rinternal": "Что-то случилось на стороне p1nkl0bst3r-а",
|
"p1nkl0bst3rinternal": "Что-то случилось на стороне p1nkl0bst3r-а",
|
||||||
"p1nkl0bst3rinternalWebVersion": "Что-то случилось на стороне p1nkl0bst3r-а (или на стороне oskware_bridge, я хз если честно)",
|
"p1nkl0bst3rinternalWebVersion": "Что-то случилось на стороне p1nkl0bst3r-а (или на стороне oskware_bridge, я хз если честно)",
|
||||||
"replayAlreadySaved": "Повтор уже сохранён",
|
"replayAlreadySaved": "Повтор уже сохранён",
|
||||||
"replayExpired": "Повтор истёк и больше недоступен",
|
"replayExpired": "Повтор истёк и больше недоступен",
|
||||||
"replayRejected": "Стороннее API заблокировало ваш IP адрес.\nСмените IP адрес или свяжитесь с szy"
|
"replayRejected": "Стороннее API заблокировало ваш IP адрес"
|
||||||
},
|
},
|
||||||
"countries(map)": {
|
"countries(map)": {
|
||||||
"": "Не выбрана",
|
"": "Не выбрана",
|
||||||
|
|
After Width: | Height: | Size: 45 KiB |
After Width: | Height: | Size: 45 KiB |
After Width: | Height: | Size: 41 KiB |
After Width: | Height: | Size: 48 KiB |
After Width: | Height: | Size: 29 KiB |
After Width: | Height: | Size: 30 KiB |
After Width: | Height: | Size: 28 KiB |
After Width: | Height: | Size: 15 KiB |
After Width: | Height: | Size: 42 KiB |
After Width: | Height: | Size: 25 KiB |
After Width: | Height: | Size: 28 KiB |
|
@ -1,5 +1,4 @@
|
||||||
import 'dart:io';
|
import 'dart:io';
|
||||||
import 'dart:math';
|
|
||||||
import 'dart:ui';
|
import 'dart:ui';
|
||||||
import 'package:flutter/foundation.dart';
|
import 'package:flutter/foundation.dart';
|
||||||
import 'package:flutter/material.dart';
|
import 'package:flutter/material.dart';
|
||||||
|
|
|
@ -18,7 +18,7 @@
|
||||||
|
|
||||||
<meta charset="UTF-8">
|
<meta charset="UTF-8">
|
||||||
<meta content="IE=Edge" http-equiv="X-UA-Compatible">
|
<meta content="IE=Edge" http-equiv="X-UA-Compatible">
|
||||||
<meta name="description" content="Track your and other player stats in TETR.IO">
|
<meta name="description" content="Track your and other player stats in TETR.IO. Made by dan63047">
|
||||||
|
|
||||||
<!-- iOS meta tags & icons -->
|
<!-- iOS meta tags & icons -->
|
||||||
<meta name="apple-mobile-web-app-capable" content="yes">
|
<meta name="apple-mobile-web-app-capable" content="yes">
|
||||||
|
|