|
@ -16,6 +16,7 @@ You can [download an app](https://github.com/dan63047/TetraStats/releases), or [
|
|||
- Stats Calculator
|
||||
- Player history in charts
|
||||
- Tetra League matches history
|
||||
- Time-weighted stats in Tetra League matches
|
||||
|
||||
# Special thanks
|
||||
- **kerrmunism** — formulas
|
||||
|
|
|
@ -25,6 +25,12 @@ apply plugin: 'com.android.application'
|
|||
apply plugin: 'kotlin-android'
|
||||
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 {
|
||||
compileSdkVersion flutter.compileSdkVersion
|
||||
ndkVersion flutter.ndkVersion
|
||||
|
@ -53,11 +59,17 @@ android {
|
|||
versionName flutterVersionName
|
||||
}
|
||||
|
||||
signingConfigs {
|
||||
release {
|
||||
keyAlias keystoreProperties['keyAlias']
|
||||
keyPassword keystoreProperties['keyPassword']
|
||||
storeFile keystoreProperties['storeFile'] ? file(keystoreProperties['storeFile']) : null
|
||||
storePassword keystoreProperties['storePassword']
|
||||
}
|
||||
}
|
||||
buildTypes {
|
||||
release {
|
||||
// TODO: Add your own signing config for the release build.
|
||||
// Signing with the debug keys for now, so `flutter run --release` works.
|
||||
signingConfig signingConfigs.debug
|
||||
signingConfig signingConfigs.release
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -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,
|
||||
"": 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 {
|
||||
tr,
|
||||
glicko,
|
||||
|
@ -59,6 +78,7 @@ enum Stats {
|
|||
area,
|
||||
eTR,
|
||||
acceTR,
|
||||
acceTRabs,
|
||||
opener,
|
||||
plonk,
|
||||
infDS,
|
||||
|
@ -88,6 +108,7 @@ const Map<Stats, String> chartsShortTitles = {
|
|||
Stats.area: "Area",
|
||||
Stats.eTR: "eTR",
|
||||
Stats.acceTR: "±eTR",
|
||||
Stats.acceTRabs: "+eTR absolute",
|
||||
Stats.opener: "Opener",
|
||||
Stats.plonk: "Plonk",
|
||||
Stats.infDS: "Inf. DS",
|
||||
|
@ -117,6 +138,48 @@ const Map<String, Color> rankColors = { // thanks osk for const rankColors at ht
|
|||
'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){
|
||||
return t[stat.name];
|
||||
}
|
||||
|
@ -271,6 +334,10 @@ class TetrioPlayer {
|
|||
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
|
||||
String toString() {
|
||||
return "$username ($state)";
|
||||
|
@ -318,6 +385,8 @@ class TetrioPlayer {
|
|||
return tlSeason1.estTr?.esttr;
|
||||
case Stats.acceTR:
|
||||
return tlSeason1.esttracc;
|
||||
case Stats.acceTRabs:
|
||||
return tlSeason1.esttracc?.abs();
|
||||
case Stats.opener:
|
||||
return tlSeason1.playstyle?.opener;
|
||||
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 {
|
||||
late String type;
|
||||
late DateTime timestamp;
|
||||
|
@ -1121,6 +1257,20 @@ class TetrioPlayersLeaderboard {
|
|||
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
|
||||
if (rank.isNotEmpty && !rankCutoffs.keys.contains(rank)) throw Exception("Invalid rank");
|
||||
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 => {
|
||||
'x': getAverageOfRank("x"),
|
||||
'u': getAverageOfRank("u"),
|
||||
|
@ -1732,6 +1906,26 @@ class TetrioPlayersLeaderboard {
|
|||
'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) {
|
||||
type = t;
|
||||
timestamp = ts;
|
||||
|
@ -1785,7 +1979,11 @@ class TetrioPlayerFromLeaderboard {
|
|||
this.apm,
|
||||
this.pps,
|
||||
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 esttracc => estTr.esttr - rating;
|
||||
|
@ -1857,6 +2055,8 @@ class TetrioPlayerFromLeaderboard {
|
|||
return estTr.esttr;
|
||||
case Stats.acceTR:
|
||||
return esttracc;
|
||||
case Stats.acceTRabs:
|
||||
return esttracc.abs();
|
||||
case Stats.opener:
|
||||
return playstyle.opener;
|
||||
case Stats.plonk:
|
||||
|
|
|
@ -1,4 +1,6 @@
|
|||
import 'dart:math';
|
||||
import 'package:vector_math/vector_math_64.dart';
|
||||
|
||||
import 'tetrio.dart';
|
||||
|
||||
// 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{
|
||||
late String id;
|
||||
late Map<dynamic, dynamic> rawJson;
|
||||
late List<EndContextMulti> endcontext;
|
||||
late List<AggregateStats> timeWeightedStats;
|
||||
late List<List<ReplayStats>> stats;
|
||||
late List<ReplayStats> totalStats;
|
||||
late List<List<String>> roundWinners;
|
||||
|
@ -178,20 +199,45 @@ class ReplayData{
|
|||
totalLength = 0;
|
||||
stats = [];
|
||||
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()];
|
||||
for(var round in json['data']) {
|
||||
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;
|
||||
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']);
|
||||
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);
|
||||
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 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]);
|
||||
totalStats[0] = totalStats[0] + playerOne;
|
||||
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(){
|
||||
|
@ -212,3 +258,402 @@ class ReplayData{
|
|||
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`
|
||||
///
|
||||
/// 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
|
||||
// ignore_for_file: type=lint
|
||||
|
@ -181,6 +181,14 @@ class Translations implements BaseTranslations<AppLocale, Translations> {
|
|||
String get stoppedBeingTracked => 'Removed from tracking list!';
|
||||
String get tlLeaderboard => 'Tetra League leaderboard';
|
||||
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 botRecord => 'Bots 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 comparingWith({required Object newDate, required Object oldDate}) => 'Data from ${newDate} comparing with ${oldDate}';
|
||||
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 get nerdStats => 'Nerd Stats';
|
||||
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 yourIDText => 'When app loads, it will retrieve data for this account';
|
||||
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 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 statesViewTitle({required Object number, required Object nickname}) => '${number} states of ${nickname} account';
|
||||
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 replaySaved({required Object path}) => 'Replay saved to ${path}';
|
||||
String get match => 'Match';
|
||||
String get timeWeightedmatch => 'Match (time-weighted)';
|
||||
String roundNumber({required Object n}) => 'Round ${n}';
|
||||
String get statsFor => 'Stats for';
|
||||
String get numberOfRounds => 'Number of rounds';
|
||||
String get matchLength => 'Match 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 matchIsTooOld => 'Replay is not available';
|
||||
String get winner => 'Winner';
|
||||
|
@ -294,6 +315,15 @@ class Translations implements BaseTranslations<AppLocale, Translations> {
|
|||
many: '${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 entries => 'Entries';
|
||||
String get minimums => 'Minimums';
|
||||
|
@ -675,8 +705,30 @@ class _StringsNumOfGameActionsEn {
|
|||
// Translations
|
||||
String get pc => 'All Clears';
|
||||
String get hold => 'Holds';
|
||||
String get tspinsTotal => 'T-spins total';
|
||||
String get lineClears => 'Line clears';
|
||||
String inputs({required num n}) => (_root.$meta.cardinalResolver ?? PluralResolvers.cardinal('en'))(n,
|
||||
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
|
||||
|
@ -700,21 +752,30 @@ class _StringsErrorsEn {
|
|||
// Translations
|
||||
String connection({required Object code, required Object message}) => 'Some issue with connection: ${code} ${message}';
|
||||
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 actionSuggestion => 'Perhaps, you want to';
|
||||
String get p1nkl0bst3rTLmatches => 'No Tetra League matches was found';
|
||||
String get clientException => 'No internet connection';
|
||||
String get forbidden => 'Your IP address is blocked.\nChange IP address or reach out to osk';
|
||||
String get tooManyRequests => 'You have been rate limited. Try again later';
|
||||
String get forbidden => 'Your IP address is blocked';
|
||||
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 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 oskwareBridge => 'Something happend with oskware_bridge. Let dan63047 know';
|
||||
String get p1nkl0bst3rForbidden => 'Third party API blocked your IP address.\nChange IP address or reach out to p1nkl0bst3r';
|
||||
String get internalWebVersionSub => 'If osk status page says that everything is ok, let dan63047 know about this issue';
|
||||
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 p1nkl0bst3rinternal => 'Something happend on the p1nkl0bst3r side';
|
||||
String get p1nkl0bst3rinternalWebVersion => 'Something happend on the p1nkl0bst3r side (or on oskware_bridge, idk honestly)';
|
||||
String get replayAlreadySaved => 'Replay already saved';
|
||||
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>
|
||||
|
@ -774,6 +835,14 @@ class _StringsRu implements Translations {
|
|||
@override String get compare => 'Сравнить';
|
||||
@override String get tlLeaderboard => 'Рейтинговая таблица';
|
||||
@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 botRecord => 'Ботам нельзя ставить рекорды';
|
||||
@override String get anonRecord => 'Гостям нельзя ставить рекорды';
|
||||
|
@ -797,7 +866,10 @@ class _StringsRu implements Translations {
|
|||
@override String get assignedManualy => 'Этот значок был присвоен вручную администрацией TETR.IO';
|
||||
@override String comparingWith({required Object newDate, required Object oldDate}) => 'Данные от ${newDate} в сравнении с данными от ${oldDate}';
|
||||
@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 get nerdStats => 'Для задротов';
|
||||
@override String get playersYouTrack => 'Отслеживаемые игроки';
|
||||
|
@ -821,8 +893,14 @@ class _StringsRu implements Translations {
|
|||
@override String get yourIDAlertTitle => 'Ваш ник в TETR.IO';
|
||||
@override String get yourIDText => 'При запуске приложения оно будет получать статистику этого игрока.';
|
||||
@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 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 statesViewTitle({required Object number, required Object nickname}) => '${number} состояний аккаунта ${nickname}';
|
||||
@override String matchesViewTitle({required Object nickname}) => 'Матчи аккаунта ${nickname}';
|
||||
|
@ -847,10 +925,14 @@ class _StringsRu implements Translations {
|
|||
@override String get openReplay => 'Открыть повтор в TETR.IO';
|
||||
@override String replaySaved({required Object path}) => 'Повтор сохранён по пути ${path}';
|
||||
@override String get match => 'Матч';
|
||||
@override String get timeWeightedmatch => 'Матч (взвешенная по времени)';
|
||||
@override String roundNumber({required Object n}) => 'Раунд ${n}';
|
||||
@override String get statsFor => 'Статистика за';
|
||||
@override String get numberOfRounds => 'Количество раундов';
|
||||
@override String get matchLength => 'Продолжительность матча';
|
||||
@override String get roundLength => 'Продолжительность раунда';
|
||||
@override String get matchStats => 'Статистика матча';
|
||||
@override String get timeWeightedmatchStats => 'Взвешенная по времени cтатистика матча';
|
||||
@override String get replayIssue => 'Ошибка обработки повтора';
|
||||
@override String get matchIsTooOld => 'Информация о повторе недоступна';
|
||||
@override String get winner => 'Победитель';
|
||||
|
@ -887,6 +969,15 @@ class _StringsRu implements Translations {
|
|||
many: '${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 entries => 'Список';
|
||||
@override String get minimums => 'Минимумы';
|
||||
|
@ -1268,8 +1359,30 @@ class _StringsNumOfGameActionsRu implements _StringsNumOfGameActionsEn {
|
|||
// Translations
|
||||
@override String get pc => 'Все чисто';
|
||||
@override String get hold => 'В запас';
|
||||
@override String get tspinsTotal => 'T-spins всего';
|
||||
@override String get lineClears => 'Линий очищено';
|
||||
@override String inputs({required num n}) => (_root.$meta.cardinalResolver ?? PluralResolvers.cardinal('ru'))(n,
|
||||
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
|
||||
|
@ -1293,21 +1406,30 @@ class _StringsErrorsRu implements _StringsErrorsEn {
|
|||
// Translations
|
||||
@override String connection({required Object code, required Object message}) => 'Проблема с подключением: ${code} ${message}';
|
||||
@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 actionSuggestion => 'Возможно, вы хотите';
|
||||
@override String get p1nkl0bst3rTLmatches => 'Старых матчей Тетра Лиги не было найдено';
|
||||
@override String get clientException => 'Нет соединения с интернетом';
|
||||
@override String get forbidden => 'Ваш IP адрес заблокирован.\nСмените IP адрес или свяжитесь с osk-ом';
|
||||
@override String get tooManyRequests => 'Слишком много запросов. Попробуйте позже';
|
||||
@override String get forbidden => 'Ваш IP адрес заблокирован';
|
||||
@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 internalSub => 'Скорее всего, osk уже в курсе об этом';
|
||||
@override String get internalWebVersion => 'Что-то случилось на стороне tetr.io (или на стороне oskware_bridge, я хз если честно)';
|
||||
@override String get oskwareBridge => 'Что-то случилось с oskware_bridge. Дайте dan63047 знать';
|
||||
@override String get p1nkl0bst3rForbidden => 'Стороннее API заблокировало ваш IP адрес.\nСмените IP адрес или свяжитесь с p1nkl0bst3r-ом';
|
||||
@override String get internalWebVersionSub => 'Если статус страница osk-а говорит, что всё ок - свяжитесь с dan63047';
|
||||
@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 p1nkl0bst3rinternal => 'Что-то случилось на стороне p1nkl0bst3r-а';
|
||||
@override String get p1nkl0bst3rinternalWebVersion => 'Что-то случилось на стороне p1nkl0bst3r-а (или на стороне oskware_bridge, я хз если честно)';
|
||||
@override String get replayAlreadySaved => 'Повтор уже сохранён';
|
||||
@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.
|
||||
|
@ -1359,6 +1481,14 @@ extension on Translations {
|
|||
case 'stoppedBeingTracked': return 'Removed from tracking list!';
|
||||
case 'tlLeaderboard': return 'Tetra League leaderboard';
|
||||
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 'botRecord': return 'Bots 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 'comparingWith': return ({required Object newDate, required Object oldDate}) => 'Data from ${newDate} comparing with ${oldDate}';
|
||||
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 'nerdStats': return 'Nerd Stats';
|
||||
case 'playersYouTrack': return 'Players you track';
|
||||
|
@ -1406,8 +1539,14 @@ extension on Translations {
|
|||
case 'yourIDAlertTitle': return 'Your nickname in TETR.IO';
|
||||
case 'yourIDText': return 'When app loads, it will retrieve data for this account';
|
||||
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 '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 'statesViewTitle': return ({required Object number, required Object nickname}) => '${number} states of ${nickname} account';
|
||||
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 'replaySaved': return ({required Object path}) => 'Replay saved to ${path}';
|
||||
case 'match': return 'Match';
|
||||
case 'timeWeightedmatch': return 'Match (time-weighted)';
|
||||
case 'roundNumber': return ({required Object n}) => 'Round ${n}';
|
||||
case 'statsFor': return 'Stats for';
|
||||
case 'numberOfRounds': return 'Number of rounds';
|
||||
case 'matchLength': return 'Match 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 'matchIsTooOld': return 'Replay is not available';
|
||||
case 'winner': return 'Winner';
|
||||
|
@ -1472,6 +1615,15 @@ extension on Translations {
|
|||
many: '${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 'entries': return 'Entries';
|
||||
case 'minimums': return 'Minimums';
|
||||
|
@ -1546,28 +1698,59 @@ extension on Translations {
|
|||
case 'playerRole.anon': return 'Anonymous';
|
||||
case 'numOfGameActions.pc': return 'All Clears';
|
||||
case 'numOfGameActions.hold': return 'Holds';
|
||||
case 'numOfGameActions.tspinsTotal': return 'T-spins total';
|
||||
case 'numOfGameActions.lineClears': return 'Line clears';
|
||||
case 'numOfGameActions.inputs': return ({required num n}) => (_root.$meta.cardinalResolver ?? PluralResolvers.cardinal('en'))(n,
|
||||
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.submit': return 'Submit';
|
||||
case 'popupActions.ok': return 'OK';
|
||||
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.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.actionSuggestion': return 'Perhaps, you want to';
|
||||
case 'errors.p1nkl0bst3rTLmatches': return 'No Tetra League matches was found';
|
||||
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.tooManyRequests': return 'You have been rate limited. Try again later';
|
||||
case 'errors.forbidden': return 'Your IP address is blocked';
|
||||
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.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.oskwareBridge': return 'Something happend with oskware_bridge. Let dan63047 know';
|
||||
case 'errors.p1nkl0bst3rForbidden': return 'Third party API blocked your IP address.\nChange IP address or reach out to p1nkl0bst3r';
|
||||
case 'errors.internalWebVersionSub': return 'If osk status page says that everything is ok, let dan63047 know about this issue';
|
||||
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.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.replayAlreadySaved': return 'Replay already saved';
|
||||
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.AF': return 'Afghanistan';
|
||||
case 'countries.AX': return 'Åland Islands';
|
||||
|
@ -1878,6 +2061,14 @@ extension on _StringsRu {
|
|||
case 'compare': return 'Сравнить';
|
||||
case 'tlLeaderboard': 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 'botRecord': return 'Ботам нельзя ставить рекорды';
|
||||
case 'anonRecord': return 'Гостям нельзя ставить рекорды';
|
||||
|
@ -1901,7 +2092,10 @@ extension on _StringsRu {
|
|||
case 'assignedManualy': return 'Этот значок был присвоен вручную администрацией TETR.IO';
|
||||
case 'comparingWith': return ({required Object newDate, required Object oldDate}) => 'Данные от ${newDate} в сравнении с данными от ${oldDate}';
|
||||
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 'nerdStats': return 'Для задротов';
|
||||
case 'playersYouTrack': return 'Отслеживаемые игроки';
|
||||
|
@ -1925,8 +2119,14 @@ extension on _StringsRu {
|
|||
case 'yourIDAlertTitle': return 'Ваш ник в TETR.IO';
|
||||
case 'yourIDText': return 'При запуске приложения оно будет получать статистику этого игрока.';
|
||||
case 'language': return 'Язык (Language)';
|
||||
case 'customization': return 'Кастомизация';
|
||||
case 'customizationDescription': return 'Здесь только один переключатель, в планах добавить больше';
|
||||
case 'lbStats': return 'Показывать статистику, основанную на рейтинговой таблице';
|
||||
case 'lbStatsDescription': 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 'oskKagari': return '"Оск Кагари" прикол';
|
||||
case 'oskKagariDescription': return 'Если включено, вместо настоящего ранга оска будет рендерится :kagari:';
|
||||
case 'stateViewTitle': return ({required Object nickname, required Object date}) => 'Аккаунт ${nickname} ${date}';
|
||||
case 'statesViewTitle': return ({required Object number, required Object nickname}) => '${number} состояний аккаунта ${nickname}';
|
||||
case 'matchesViewTitle': return ({required Object nickname}) => 'Матчи аккаунта ${nickname}';
|
||||
|
@ -1951,10 +2151,14 @@ extension on _StringsRu {
|
|||
case 'openReplay': return 'Открыть повтор в TETR.IO';
|
||||
case 'replaySaved': return ({required Object path}) => 'Повтор сохранён по пути ${path}';
|
||||
case 'match': return 'Матч';
|
||||
case 'timeWeightedmatch': return 'Матч (взвешенная по времени)';
|
||||
case 'roundNumber': return ({required Object n}) => 'Раунд ${n}';
|
||||
case 'statsFor': return 'Статистика за';
|
||||
case 'numberOfRounds': return 'Количество раундов';
|
||||
case 'matchLength': return 'Продолжительность матча';
|
||||
case 'roundLength': return 'Продолжительность раунда';
|
||||
case 'matchStats': return 'Статистика матча';
|
||||
case 'timeWeightedmatchStats': return 'Взвешенная по времени cтатистика матча';
|
||||
case 'replayIssue': return 'Ошибка обработки повтора';
|
||||
case 'matchIsTooOld': return 'Информация о повторе недоступна';
|
||||
case 'winner': return 'Победитель';
|
||||
|
@ -1991,6 +2195,15 @@ extension on _StringsRu {
|
|||
many: '${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 'entries': return 'Список';
|
||||
case 'minimums': return 'Минимумы';
|
||||
|
@ -2065,28 +2278,59 @@ extension on _StringsRu {
|
|||
case 'playerRole.anon': return 'Аноним';
|
||||
case 'numOfGameActions.pc': return 'Все чисто';
|
||||
case 'numOfGameActions.hold': return 'В запас';
|
||||
case 'numOfGameActions.tspinsTotal': return 'T-spins всего';
|
||||
case 'numOfGameActions.lineClears': return 'Линий очищено';
|
||||
case 'numOfGameActions.inputs': return ({required num n}) => (_root.$meta.cardinalResolver ?? PluralResolvers.cardinal('ru'))(n,
|
||||
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.submit': return 'Подтвердить';
|
||||
case 'popupActions.ok': return 'OK';
|
||||
case 'errors.connection': return ({required Object code, required Object message}) => 'Проблема с подключением: ${code} ${message}';
|
||||
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.actionSuggestion': return 'Возможно, вы хотите';
|
||||
case 'errors.p1nkl0bst3rTLmatches': return 'Старых матчей Тетра Лиги не было найдено';
|
||||
case 'errors.clientException': return 'Нет соединения с интернетом';
|
||||
case 'errors.forbidden': return 'Ваш IP адрес заблокирован.\nСмените IP адрес или свяжитесь с osk-ом';
|
||||
case 'errors.tooManyRequests': return 'Слишком много запросов. Попробуйте позже';
|
||||
case 'errors.forbidden': return 'Ваш IP адрес заблокирован';
|
||||
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.internalSub': return 'Скорее всего, osk уже в курсе об этом';
|
||||
case 'errors.internalWebVersion': return 'Что-то случилось на стороне tetr.io (или на стороне oskware_bridge, я хз если честно)';
|
||||
case 'errors.oskwareBridge': return 'Что-то случилось с oskware_bridge. Дайте dan63047 знать';
|
||||
case 'errors.p1nkl0bst3rForbidden': return 'Стороннее API заблокировало ваш IP адрес.\nСмените IP адрес или свяжитесь с p1nkl0bst3r-ом';
|
||||
case 'errors.internalWebVersionSub': return 'Если статус страница osk-а говорит, что всё ок - свяжитесь с dan63047';
|
||||
case 'errors.oskwareBridge': return 'Что-то случилось с oskware_bridge';
|
||||
case 'errors.oskwareBridgeSub': return 'Дайте dan63047 знать';
|
||||
case 'errors.p1nkl0bst3rForbidden': return 'Стороннее API заблокировало ваш IP адрес';
|
||||
case 'errors.p1nkl0bst3rTooManyRequests': return 'Слишком много запросов к стороннему API. Попробуйте позже';
|
||||
case 'errors.p1nkl0bst3rinternal': return 'Что-то случилось на стороне p1nkl0bst3r-а';
|
||||
case 'errors.p1nkl0bst3rinternalWebVersion': return 'Что-то случилось на стороне p1nkl0bst3r-а (или на стороне oskware_bridge, я хз если честно)';
|
||||
case 'errors.replayAlreadySaved': 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.AF': return 'Афганистан';
|
||||
case 'countries.AX': return 'Аландские острова';
|
||||
|
|
|
@ -14,6 +14,8 @@ class TetrioPlayerAlreadyExist implements Exception {}
|
|||
|
||||
class TetrioPlayerNotExist implements Exception {}
|
||||
|
||||
class TetrioDiscordNotExist implements Exception {}
|
||||
|
||||
class TetrioHistoryNotExist implements Exception {}
|
||||
|
||||
class TetrioTooManyRequests implements Exception {}
|
||||
|
|
|
@ -74,6 +74,7 @@ class TetrioService extends DB {
|
|||
final Map<String, Map<String, dynamic>> _recordsCache = {};
|
||||
final Map<String, dynamic> _replaysCache = {}; // the only one is different: {"replayID": [replayString, replayBytes]}
|
||||
final Map<String, TetrioPlayersLeaderboard> _leaderboardsCache = {};
|
||||
final Map<String, PlayerLeaderboardPosition> _lbPositions = {};
|
||||
final Map<String, List<News>> _newsCache = {};
|
||||
final Map<String, Map<String, double?>> _topTRcache = {};
|
||||
final Map<String, TetraLeagueAlphaStream> _tlStreamsCache = {};
|
||||
|
@ -142,6 +143,14 @@ class TetrioService extends DB {
|
|||
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
|
||||
/// different from 200 statusCode, it will throw an excepction. Returns list, that contains same replay
|
||||
/// as string and as binary.
|
||||
|
@ -406,12 +415,12 @@ class TetrioService extends DB {
|
|||
// parsing data into TetraLeagueAlphaRecord objects
|
||||
for (var entry in csv){
|
||||
TetraLeagueAlphaRecord match = TetraLeagueAlphaRecord(
|
||||
replayId: entry[0],
|
||||
ownId: entry[0], // i gonna disting p1nkl0bst3r entries with it
|
||||
replayId: entry[0].toString(),
|
||||
ownId: entry[0].toString(), // i gonna disting p1nkl0bst3r entries with it
|
||||
timestamp: DateTime.parse(entry[1]),
|
||||
endContext: [
|
||||
EndContextMulti(
|
||||
userId: entry[2],
|
||||
userId: entry[2].toString(),
|
||||
username: entry[3].toString(),
|
||||
naturalOrder: 0,
|
||||
inputs: -1,
|
||||
|
@ -428,7 +437,7 @@ class TetrioService extends DB {
|
|||
success: true
|
||||
),
|
||||
EndContextMulti(
|
||||
userId: entry[8],
|
||||
userId: entry[8].toString(),
|
||||
username: entry[9].toString(),
|
||||
naturalOrder: 1,
|
||||
inputs: -1,
|
||||
|
@ -504,6 +513,7 @@ class TetrioService extends DB {
|
|||
|
||||
switch (response.statusCode) {
|
||||
case 200:
|
||||
_lbPositions.clear();
|
||||
var rawJson = jsonDecode(response.body);
|
||||
if (rawJson['success']) { // if api confirmed that everything ok
|
||||
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.
|
||||
Future<List<News>> fetchNews(String userID) async{
|
||||
try{
|
||||
|
@ -712,6 +728,14 @@ class TetrioService extends DB {
|
|||
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.
|
||||
Future<void> deleteTLMatch(String matchID) async {
|
||||
await ensureDbIsOpen();
|
||||
|
@ -950,7 +974,7 @@ class TetrioService extends DB {
|
|||
user = json['data']['user']['_id'];
|
||||
} else { // fail - throw an exception
|
||||
developer.log("fetchPlayer User dosen't exist", name: "services/tetrio_crud", error: response.body);
|
||||
throw TetrioPlayerNotExist();
|
||||
throw TetrioDiscordNotExist();
|
||||
}
|
||||
break;
|
||||
// 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;
|
||||
EstTr? estTr;
|
||||
Playstyle? playstyle;
|
||||
final NumberFormat f2 = NumberFormat.decimalPatternDigits(locale: LocaleSettings.currentLocale.languageCode, decimalDigits: 2);
|
||||
late String oldWindowTitle;
|
||||
|
||||
class CalcView extends StatefulWidget {
|
||||
|
@ -67,73 +66,67 @@ class CalcState extends State<CalcView> {
|
|||
title: Text(t.statsCalc),
|
||||
),
|
||||
backgroundColor: Colors.black,
|
||||
body: SafeArea(
|
||||
child: NestedScrollView(
|
||||
controller: _scrollController,
|
||||
headerSliverBuilder: (context, value) {
|
||||
return [
|
||||
SliverToBoxAdapter(
|
||||
child: Padding(
|
||||
padding: const EdgeInsets.fromLTRB(14, 16, 16, 32),
|
||||
child: Row(
|
||||
children: [
|
||||
Expanded(
|
||||
child: Padding(
|
||||
padding: const EdgeInsets.only(right: 12),
|
||||
child: TextField(
|
||||
onSubmitted: (value) => calc(),
|
||||
controller: apmController,
|
||||
keyboardType: TextInputType.number,
|
||||
decoration: const InputDecoration(label: Text("APM"), alignLabelWithHint: true),
|
||||
),
|
||||
)),
|
||||
Expanded(
|
||||
child: TextField(
|
||||
onSubmitted: (value) => calc(),
|
||||
controller: ppsController,
|
||||
keyboardType: TextInputType.number,
|
||||
decoration: const InputDecoration(label: Text("PPS"), alignLabelWithHint: true),
|
||||
)),
|
||||
Expanded(
|
||||
child: Padding(
|
||||
padding: const EdgeInsets.only(left: 12),
|
||||
child: TextField(
|
||||
onSubmitted: (value) => calc(),
|
||||
controller: vsController,
|
||||
keyboardType: TextInputType.number,
|
||||
decoration: const InputDecoration(label: Text("VS"), alignLabelWithHint: true),
|
||||
),
|
||||
)),
|
||||
TextButton(
|
||||
onPressed: () => calc(),
|
||||
child: Text(t.calc),
|
||||
),
|
||||
],
|
||||
body: SingleChildScrollView(
|
||||
child: Center(
|
||||
child: Container(
|
||||
constraints: const BoxConstraints(maxWidth: 768),
|
||||
child: Column(children: [
|
||||
Padding(
|
||||
padding: const EdgeInsets.fromLTRB(14, 16, 16, 32),
|
||||
child: Row(
|
||||
children: [
|
||||
Expanded(
|
||||
child: Padding(
|
||||
padding: const EdgeInsets.only(right: 12),
|
||||
child: TextField(
|
||||
onSubmitted: (value) => calc(),
|
||||
controller: apmController,
|
||||
keyboardType: TextInputType.number,
|
||||
decoration: const InputDecoration(label: Text("APM"), alignLabelWithHint: true),
|
||||
),
|
||||
)),
|
||||
Expanded(
|
||||
child: TextField(
|
||||
onSubmitted: (value) => calc(),
|
||||
controller: ppsController,
|
||||
keyboardType: TextInputType.number,
|
||||
decoration: const InputDecoration(label: Text("PPS"), alignLabelWithHint: true),
|
||||
)),
|
||||
Expanded(
|
||||
child: Padding(
|
||||
padding: const EdgeInsets.only(left: 12),
|
||||
child: TextField(
|
||||
onSubmitted: (value) => calc(),
|
||||
controller: vsController,
|
||||
keyboardType: TextInputType.number,
|
||||
decoration: const InputDecoration(label: Text("VS"), alignLabelWithHint: true),
|
||||
),
|
||||
)),
|
||||
TextButton(
|
||||
onPressed: () => calc(),
|
||||
child: Text(t.calc),
|
||||
),
|
||||
),
|
||||
],
|
||||
),
|
||||
const SliverToBoxAdapter(
|
||||
child: Divider(),
|
||||
)
|
||||
];
|
||||
},
|
||||
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!.vsapm, label: "VS/APM", fractionDigits: 3),
|
||||
_ListEntry(value: nerdStats!.dss, label: t.statCellNum.dss.replaceAll(RegExp(r'\n'), " "), fractionDigits: 3),
|
||||
_ListEntry(value: nerdStats!.dsp, label: t.statCellNum.dsp.replaceAll(RegExp(r'\n'), " "), fractionDigits: 3),
|
||||
_ListEntry(value: nerdStats!.appdsp, label: "APP + DS/P", fractionDigits: 3),
|
||||
_ListEntry(value: nerdStats!.cheese, label: t.statCellNum.cheese.replaceAll(RegExp(r'\n'), " "), fractionDigits: 3),
|
||||
_ListEntry(value: nerdStats!.gbe, label: t.statCellNum.gbe.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: estTr!.esttr, label: t.statCellNum.estOfTR, fractionDigits: 3),
|
||||
Graphs(apm!, pps!, vs!, nerdStats!, playstyle!),
|
||||
],
|
||||
)),
|
||||
),
|
||||
Divider(),
|
||||
if (nerdStats == null) Text(t.calcViewNoValues)
|
||||
else Column(children: [
|
||||
_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!.dss, label: t.statCellNum.dss.replaceAll(RegExp(r'\n'), " "), fractionDigits: 3),
|
||||
_ListEntry(value: nerdStats!.dsp, label: t.statCellNum.dsp.replaceAll(RegExp(r'\n'), " "), fractionDigits: 3),
|
||||
_ListEntry(value: nerdStats!.appdsp, label: "APP + DS/P", fractionDigits: 3),
|
||||
_ListEntry(value: nerdStats!.cheese, label: t.statCellNum.cheese.replaceAll(RegExp(r'\n'), " "), fractionDigits: 3),
|
||||
_ListEntry(value: nerdStats!.gbe, label: t.statCellNum.gbe.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: estTr!.esttr, label: t.statCellNum.estOfTR, fractionDigits: 3),
|
||||
Graphs(apm!, pps!, vs!, nerdStats!, playstyle!)
|
||||
],)
|
||||
],),
|
||||
),
|
||||
),
|
||||
),
|
||||
);
|
||||
}
|
||||
|
|
|
@ -255,444 +255,435 @@ class CompareState extends State<CompareView> {
|
|||
return Scaffold(
|
||||
appBar: AppBar(title: Text("$titleGreenSide ${t.vs} $titleRedSide")),
|
||||
backgroundColor: Colors.black,
|
||||
body: SafeArea(
|
||||
child: NestedScrollView(
|
||||
controller: _scrollController,
|
||||
headerSliverBuilder: (context, value) {
|
||||
return [
|
||||
SliverToBoxAdapter(
|
||||
child: Padding(
|
||||
padding: const EdgeInsets.fromLTRB(16, 16, 16, 32),
|
||||
child: Row(
|
||||
mainAxisAlignment: MainAxisAlignment.spaceBetween,
|
||||
crossAxisAlignment: CrossAxisAlignment.start,
|
||||
children: [
|
||||
Expanded(
|
||||
child: Container(
|
||||
decoration: const BoxDecoration(
|
||||
gradient: LinearGradient(
|
||||
colors: [Colors.green, Colors.transparent],
|
||||
begin: Alignment.bottomCenter,
|
||||
end: Alignment.topCenter,
|
||||
stops: [0.0, 0.4],
|
||||
)),
|
||||
child: Padding(
|
||||
padding: const EdgeInsets.fromLTRB(8, 0, 8, 0),
|
||||
child: PlayerSelector(
|
||||
data: theGreenSide,
|
||||
mode: greenSideMode,
|
||||
fetch: fetchGreenSide,
|
||||
change: changeGreenSide,
|
||||
updateState: _justUpdate,
|
||||
),
|
||||
body: SingleChildScrollView(
|
||||
controller: _scrollController,
|
||||
physics: AlwaysScrollableScrollPhysics(),
|
||||
child: Center(
|
||||
child: Container(
|
||||
constraints: const BoxConstraints(maxWidth: 768),
|
||||
child: Column(children: [
|
||||
Padding(
|
||||
padding: const EdgeInsets.fromLTRB(16, 16, 16, 32),
|
||||
child: Row(
|
||||
mainAxisAlignment: MainAxisAlignment.spaceBetween,
|
||||
crossAxisAlignment: CrossAxisAlignment.start,
|
||||
children: [
|
||||
Expanded(
|
||||
child: Container(
|
||||
decoration: const BoxDecoration(
|
||||
gradient: LinearGradient(
|
||||
colors: [Colors.green, Colors.transparent],
|
||||
begin: Alignment.bottomCenter,
|
||||
end: Alignment.topCenter,
|
||||
stops: [0.0, 0.4],
|
||||
)),
|
||||
child: Padding(
|
||||
padding: const EdgeInsets.fromLTRB(8, 0, 8, 0),
|
||||
child: PlayerSelector(
|
||||
data: theGreenSide,
|
||||
mode: greenSideMode,
|
||||
fetch: fetchGreenSide,
|
||||
change: changeGreenSide,
|
||||
updateState: _justUpdate,
|
||||
),
|
||||
),
|
||||
),
|
||||
const Padding(
|
||||
padding: EdgeInsets.only(top: 16),
|
||||
child: Text("VS"),
|
||||
),
|
||||
Expanded(
|
||||
child: Container(
|
||||
decoration: const BoxDecoration(
|
||||
gradient: LinearGradient(
|
||||
colors: [Colors.red, Colors.transparent],
|
||||
begin: Alignment.bottomCenter,
|
||||
end: Alignment.topCenter,
|
||||
stops: [0.0, 0.4],
|
||||
)),
|
||||
child: Padding(
|
||||
padding: const EdgeInsets.fromLTRB(8, 0, 8, 0),
|
||||
child: PlayerSelector(
|
||||
data: theRedSide,
|
||||
mode: redSideMode,
|
||||
fetch: fetchRedSide,
|
||||
change: changeRedSide,
|
||||
updateState: _justUpdate,
|
||||
),
|
||||
),
|
||||
const Padding(
|
||||
padding: EdgeInsets.only(top: 16),
|
||||
child: Text("VS"),
|
||||
),
|
||||
Expanded(
|
||||
child: Container(
|
||||
decoration: const BoxDecoration(
|
||||
gradient: LinearGradient(
|
||||
colors: [Colors.red, Colors.transparent],
|
||||
begin: Alignment.bottomCenter,
|
||||
end: Alignment.topCenter,
|
||||
stops: [0.0, 0.4],
|
||||
)),
|
||||
child: Padding(
|
||||
padding: const EdgeInsets.fromLTRB(8, 0, 8, 0),
|
||||
child: PlayerSelector(
|
||||
data: theRedSide,
|
||||
mode: redSideMode,
|
||||
fetch: fetchRedSide,
|
||||
change: changeRedSide,
|
||||
updateState: _justUpdate,
|
||||
),
|
||||
),
|
||||
),
|
||||
],
|
||||
),
|
||||
),
|
||||
],
|
||||
),
|
||||
),
|
||||
const SliverToBoxAdapter(
|
||||
child: Divider(),
|
||||
)
|
||||
];
|
||||
},
|
||||
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(
|
||||
children: [
|
||||
CompareRegTimeThingy(
|
||||
greenSide: theGreenSide[0].registrationTime,
|
||||
redSide: theRedSide[0].registrationTime,
|
||||
label: t.registred),
|
||||
CompareThingy(
|
||||
label: t.statCellNum.level,
|
||||
greenSide: theGreenSide[0].level,
|
||||
redSide: theRedSide[0].level,
|
||||
higherIsBetter: true,
|
||||
fractionDigits: 2,
|
||||
),
|
||||
if (!theGreenSide[0].gameTime.isNegative &&
|
||||
!theRedSide[0].gameTime.isNegative)
|
||||
CompareThingy(
|
||||
greenSide: theGreenSide[0].gameTime.inMicroseconds /
|
||||
1000000 /
|
||||
60 /
|
||||
60,
|
||||
redSide: theRedSide[0].gameTime.inMicroseconds /
|
||||
1000000 /
|
||||
60 /
|
||||
60,
|
||||
label: t.statCellNum.hoursPlayed.replaceAll(RegExp(r'\n'), " "),
|
||||
higherIsBetter: true,
|
||||
fractionDigits: 2,
|
||||
),
|
||||
if (theGreenSide[0].gamesPlayed >= 0 &&
|
||||
theRedSide[0].gamesPlayed >= 0)
|
||||
CompareThingy(
|
||||
label: t.statCellNum.onlineGames.replaceAll(RegExp(r'\n'), " "),
|
||||
greenSide: theGreenSide[0].gamesPlayed,
|
||||
redSide: theRedSide[0].gamesPlayed,
|
||||
higherIsBetter: true,
|
||||
),
|
||||
if (theGreenSide[0].gamesWon >= 0 &&
|
||||
theRedSide[0].gamesWon >= 0)
|
||||
CompareThingy(
|
||||
label: t.statCellNum.gamesWon.replaceAll(RegExp(r'\n'), " "),
|
||||
greenSide: theGreenSide[0].gamesWon,
|
||||
redSide: theRedSide[0].gamesWon,
|
||||
higherIsBetter: true,
|
||||
),
|
||||
CompareThingy(
|
||||
label: t.statCellNum.friends,
|
||||
greenSide: theGreenSide[0].friendCount,
|
||||
redSide: theRedSide[0].friendCount,
|
||||
higherIsBetter: true,
|
||||
),
|
||||
const Divider(),
|
||||
],
|
||||
Divider(),
|
||||
if (!listEquals(theGreenSide, [null, null, null]) && !listEquals(theRedSide, [null, null, null])) Column(
|
||||
children: [
|
||||
if (theGreenSide[0] != null && theRedSide[0] != null && theGreenSide[0]!.role != "banned" && theRedSide[0]!.role != "banned")
|
||||
Column(
|
||||
children: [
|
||||
CompareRegTimeThingy(
|
||||
greenSide: theGreenSide[0].registrationTime,
|
||||
redSide: theRedSide[0].registrationTime,
|
||||
label: t.registred),
|
||||
CompareThingy(
|
||||
label: t.statCellNum.level,
|
||||
greenSide: theGreenSide[0].level,
|
||||
redSide: theRedSide[0].level,
|
||||
higherIsBetter: true,
|
||||
fractionDigits: 2,
|
||||
),
|
||||
if (theGreenSide[0] != null &&
|
||||
theRedSide[0] != null &&
|
||||
(theGreenSide[0]!.role == "banned" ||
|
||||
theRedSide[0]!.role == "banned"))
|
||||
CompareBoolThingy(
|
||||
greenSide: theGreenSide[0].role == "banned",
|
||||
redSide: theRedSide[0].role == "banned",
|
||||
label: t.normalBanned,
|
||||
trueIsBetter: false),
|
||||
(theGreenSide[2].gamesPlayed > 0 || greenSideMode == Mode.stats) &&
|
||||
(theRedSide[2].gamesPlayed > 0 || redSideMode == Mode.stats)
|
||||
? Column(
|
||||
children: [
|
||||
Padding(
|
||||
padding: const EdgeInsets.only(bottom: 16),
|
||||
child: Text(t.tetraLeague,
|
||||
style: TextStyle(
|
||||
fontFamily: "Eurostile Round Extended",
|
||||
fontSize: bigScreen ? 42 : 28)),
|
||||
),
|
||||
if (theGreenSide[2].gamesPlayed > 9 &&
|
||||
theRedSide[2].gamesPlayed > 9 &&
|
||||
greenSideMode != Mode.stats &&
|
||||
redSideMode != Mode.stats)
|
||||
CompareThingy(
|
||||
label: "TR",
|
||||
greenSide: theGreenSide[2].rating,
|
||||
redSide: theRedSide[2].rating,
|
||||
fractionDigits: 2,
|
||||
higherIsBetter: true,
|
||||
),
|
||||
if (greenSideMode != Mode.stats &&
|
||||
redSideMode != Mode.stats)
|
||||
CompareThingy(
|
||||
label: t.statCellNum.gamesPlayed.replaceAll(RegExp(r'\n'), " "),
|
||||
greenSide: theGreenSide[2].gamesPlayed,
|
||||
redSide: theRedSide[2].gamesPlayed,
|
||||
higherIsBetter: true,
|
||||
),
|
||||
if (greenSideMode != Mode.stats &&
|
||||
redSideMode != Mode.stats)
|
||||
CompareThingy(
|
||||
label: t.statCellNum.gamesWonTL.replaceAll(RegExp(r'\n'), " "),
|
||||
greenSide: theGreenSide[2].gamesWon,
|
||||
redSide: theRedSide[2].gamesWon,
|
||||
higherIsBetter: true,
|
||||
),
|
||||
if (greenSideMode != Mode.stats &&
|
||||
redSideMode != Mode.stats)
|
||||
CompareThingy(
|
||||
label: "WR %",
|
||||
greenSide:
|
||||
theGreenSide[2].winrate * 100,
|
||||
redSide: theRedSide[2].winrate * 100,
|
||||
fractionDigits: 2,
|
||||
higherIsBetter: true,
|
||||
),
|
||||
if (theGreenSide[2].gamesPlayed > 9 &&
|
||||
theRedSide[2].gamesPlayed > 9 &&
|
||||
greenSideMode != Mode.stats &&
|
||||
redSideMode != Mode.stats)
|
||||
CompareThingy(
|
||||
label: "Glicko",
|
||||
greenSide: theGreenSide[2].glicko!,
|
||||
redSide: theRedSide[2].glicko!,
|
||||
fractionDigits: 2,
|
||||
higherIsBetter: true,
|
||||
),
|
||||
if (theGreenSide[2].gamesPlayed > 9 &&
|
||||
theRedSide[2].gamesPlayed > 9 &&
|
||||
greenSideMode != Mode.stats &&
|
||||
redSideMode != Mode.stats)
|
||||
CompareThingy(
|
||||
label: "RD",
|
||||
greenSide: theGreenSide[2].rd!,
|
||||
redSide: theRedSide[2].rd!,
|
||||
fractionDigits: 3,
|
||||
higherIsBetter: false,
|
||||
),
|
||||
if (theGreenSide[2].standing > 0 &&
|
||||
theRedSide[2].standing > 0 &&
|
||||
greenSideMode == Mode.player &&
|
||||
redSideMode == Mode.player)
|
||||
CompareThingy(
|
||||
label: t.statCellNum.lbpShort,
|
||||
greenSide: theGreenSide[2].standing,
|
||||
redSide: theRedSide[2].standing,
|
||||
higherIsBetter: false,
|
||||
),
|
||||
if (theGreenSide[2].standingLocal > 0 &&
|
||||
theRedSide[2].standingLocal > 0 &&
|
||||
greenSideMode == Mode.player &&
|
||||
redSideMode == Mode.player)
|
||||
CompareThingy(
|
||||
label: t.statCellNum.lbpcShort,
|
||||
greenSide:
|
||||
theGreenSide[2].standingLocal,
|
||||
redSide: theRedSide[2].standingLocal,
|
||||
higherIsBetter: false,
|
||||
),
|
||||
if (theGreenSide[2].apm != null &&
|
||||
theRedSide[2].apm != null)
|
||||
CompareThingy(
|
||||
label: "APM",
|
||||
greenSide: theGreenSide[2].apm!,
|
||||
redSide: theRedSide[2].apm!,
|
||||
fractionDigits: 2,
|
||||
higherIsBetter: true,
|
||||
),
|
||||
if (theGreenSide[2].pps != null &&
|
||||
theRedSide[2].pps != null)
|
||||
CompareThingy(
|
||||
label: "PPS",
|
||||
greenSide: theGreenSide[2].pps!,
|
||||
redSide: theRedSide[2].pps!,
|
||||
fractionDigits: 2,
|
||||
higherIsBetter: true,
|
||||
),
|
||||
if (theGreenSide[2].vs != null &&
|
||||
theRedSide[2].vs != null)
|
||||
CompareThingy(
|
||||
label: "VS",
|
||||
greenSide: theGreenSide[2].vs!,
|
||||
redSide: theRedSide[2].vs!,
|
||||
fractionDigits: 2,
|
||||
higherIsBetter: true,
|
||||
),
|
||||
],
|
||||
)
|
||||
: CompareBoolThingy(
|
||||
greenSide: theGreenSide[2].gamesPlayed > 0,
|
||||
redSide: theRedSide[2].gamesPlayed > 0,
|
||||
label: t.playedTL,
|
||||
trueIsBetter: false),
|
||||
if (!theGreenSide[0].gameTime.isNegative && !theRedSide[0].gameTime.isNegative)
|
||||
CompareThingy(
|
||||
greenSide: theGreenSide[0].gameTime.inMicroseconds /
|
||||
1000000 /
|
||||
60 /
|
||||
60,
|
||||
redSide: theRedSide[0].gameTime.inMicroseconds /
|
||||
1000000 /
|
||||
60 /
|
||||
60,
|
||||
label: t.statCellNum.hoursPlayed.replaceAll(RegExp(r'\n'), " "),
|
||||
higherIsBetter: true,
|
||||
fractionDigits: 2,
|
||||
),
|
||||
if (theGreenSide[0].gamesPlayed >= 0 && theRedSide[0].gamesPlayed >= 0)
|
||||
CompareThingy(
|
||||
label: t.statCellNum.onlineGames.replaceAll(RegExp(r'\n'), " "),
|
||||
greenSide: theGreenSide[0].gamesPlayed,
|
||||
redSide: theRedSide[0].gamesPlayed,
|
||||
higherIsBetter: true,
|
||||
),
|
||||
if (theGreenSide[0].gamesWon >= 0 && theRedSide[0].gamesWon >= 0)
|
||||
CompareThingy(
|
||||
label: t.statCellNum.gamesWon.replaceAll(RegExp(r'\n'), " "),
|
||||
greenSide: theGreenSide[0].gamesWon,
|
||||
redSide: theRedSide[0].gamesWon,
|
||||
higherIsBetter: true,
|
||||
),
|
||||
CompareThingy(
|
||||
label: t.statCellNum.friends,
|
||||
greenSide: theGreenSide[0].friendCount,
|
||||
redSide: theRedSide[0].friendCount,
|
||||
higherIsBetter: true,
|
||||
),
|
||||
const Divider(),
|
||||
],
|
||||
),
|
||||
if (theGreenSide[0] != null && theRedSide[0] != null && (theGreenSide[0]!.role == "banned" || theRedSide[0]!.role == "banned"))
|
||||
CompareBoolThingy(
|
||||
greenSide: theGreenSide[0].role == "banned",
|
||||
redSide: theRedSide[0].role == "banned",
|
||||
label: t.normalBanned,
|
||||
trueIsBetter: false
|
||||
),
|
||||
(theGreenSide[2].gamesPlayed > 0 || greenSideMode == Mode.stats) && (theRedSide[2].gamesPlayed > 0 || redSideMode == Mode.stats)
|
||||
? Column(
|
||||
children: [
|
||||
Padding(
|
||||
padding: const EdgeInsets.only(bottom: 16),
|
||||
child: Text(t.tetraLeague,
|
||||
style: TextStyle(
|
||||
fontFamily: "Eurostile Round Extended",
|
||||
fontSize: bigScreen ? 42 : 28)),
|
||||
),
|
||||
if (theGreenSide[2].gamesPlayed > 9 &&
|
||||
theRedSide[2].gamesPlayed > 9 &&
|
||||
greenSideMode != Mode.stats &&
|
||||
redSideMode != Mode.stats)
|
||||
CompareThingy(
|
||||
label: "TR",
|
||||
greenSide: theGreenSide[2].rating,
|
||||
redSide: theRedSide[2].rating,
|
||||
fractionDigits: 2,
|
||||
higherIsBetter: true,
|
||||
),
|
||||
if (greenSideMode != Mode.stats &&
|
||||
redSideMode != Mode.stats)
|
||||
CompareThingy(
|
||||
label: t.statCellNum.gamesPlayed.replaceAll(RegExp(r'\n'), " "),
|
||||
greenSide: theGreenSide[2].gamesPlayed,
|
||||
redSide: theRedSide[2].gamesPlayed,
|
||||
higherIsBetter: true,
|
||||
),
|
||||
if (greenSideMode != Mode.stats &&
|
||||
redSideMode != Mode.stats)
|
||||
CompareThingy(
|
||||
label: t.statCellNum.gamesWonTL.replaceAll(RegExp(r'\n'), " "),
|
||||
greenSide: theGreenSide[2].gamesWon,
|
||||
redSide: theRedSide[2].gamesWon,
|
||||
higherIsBetter: true,
|
||||
),
|
||||
if (greenSideMode != Mode.stats &&
|
||||
redSideMode != Mode.stats)
|
||||
CompareThingy(
|
||||
label: "WR %",
|
||||
greenSide:
|
||||
theGreenSide[2].winrate * 100,
|
||||
redSide: theRedSide[2].winrate * 100,
|
||||
fractionDigits: 2,
|
||||
higherIsBetter: true,
|
||||
),
|
||||
if (theGreenSide[2].gamesPlayed > 9 &&
|
||||
theRedSide[2].gamesPlayed > 9 &&
|
||||
greenSideMode != Mode.stats &&
|
||||
redSideMode != Mode.stats)
|
||||
CompareThingy(
|
||||
label: "Glicko",
|
||||
greenSide: theGreenSide[2].glicko!,
|
||||
redSide: theRedSide[2].glicko!,
|
||||
fractionDigits: 2,
|
||||
higherIsBetter: true,
|
||||
),
|
||||
if (theGreenSide[2].gamesPlayed > 9 &&
|
||||
theRedSide[2].gamesPlayed > 9 &&
|
||||
greenSideMode != Mode.stats &&
|
||||
redSideMode != Mode.stats)
|
||||
CompareThingy(
|
||||
label: "RD",
|
||||
greenSide: theGreenSide[2].rd!,
|
||||
redSide: theRedSide[2].rd!,
|
||||
fractionDigits: 3,
|
||||
higherIsBetter: false,
|
||||
),
|
||||
if (theGreenSide[2].standing > 0 &&
|
||||
theRedSide[2].standing > 0 &&
|
||||
greenSideMode == Mode.player &&
|
||||
redSideMode == Mode.player)
|
||||
CompareThingy(
|
||||
label: t.statCellNum.lbpShort,
|
||||
greenSide: theGreenSide[2].standing,
|
||||
redSide: theRedSide[2].standing,
|
||||
higherIsBetter: false,
|
||||
),
|
||||
if (theGreenSide[2].standingLocal > 0 &&
|
||||
theRedSide[2].standingLocal > 0 &&
|
||||
greenSideMode == Mode.player &&
|
||||
redSideMode == Mode.player)
|
||||
CompareThingy(
|
||||
label: t.statCellNum.lbpcShort,
|
||||
greenSide:
|
||||
theGreenSide[2].standingLocal,
|
||||
redSide: theRedSide[2].standingLocal,
|
||||
higherIsBetter: false,
|
||||
),
|
||||
if (theGreenSide[2].apm != null &&
|
||||
theRedSide[2].apm != null)
|
||||
CompareThingy(
|
||||
label: "APM",
|
||||
greenSide: theGreenSide[2].apm!,
|
||||
redSide: theRedSide[2].apm!,
|
||||
fractionDigits: 2,
|
||||
higherIsBetter: true,
|
||||
),
|
||||
if (theGreenSide[2].pps != null &&
|
||||
theRedSide[2].pps != null)
|
||||
CompareThingy(
|
||||
label: "PPS",
|
||||
greenSide: theGreenSide[2].pps!,
|
||||
redSide: theRedSide[2].pps!,
|
||||
fractionDigits: 2,
|
||||
higherIsBetter: true,
|
||||
),
|
||||
if (theGreenSide[2].vs != null &&
|
||||
theRedSide[2].vs != null)
|
||||
CompareThingy(
|
||||
label: "VS",
|
||||
greenSide: theGreenSide[2].vs!,
|
||||
redSide: theRedSide[2].vs!,
|
||||
fractionDigits: 2,
|
||||
higherIsBetter: true,
|
||||
),
|
||||
],
|
||||
)
|
||||
: CompareBoolThingy(
|
||||
greenSide: theGreenSide[2].gamesPlayed > 0,
|
||||
redSide: theRedSide[2].gamesPlayed > 0,
|
||||
label: t.playedTL,
|
||||
trueIsBetter: false),
|
||||
const Divider(),
|
||||
if (theGreenSide[2].nerdStats != null &&
|
||||
theRedSide[2].nerdStats != null)
|
||||
Column(
|
||||
children: [
|
||||
Padding(
|
||||
padding: const EdgeInsets.only(bottom: 16),
|
||||
child: Text(t.nerdStats,
|
||||
style: TextStyle(
|
||||
fontFamily: "Eurostile Round Extended",
|
||||
fontSize: bigScreen ? 42 : 28)),
|
||||
),
|
||||
CompareThingy(
|
||||
label: "APP",
|
||||
greenSide: theGreenSide[2].nerdStats!.app,
|
||||
redSide: theRedSide[2].nerdStats!.app,
|
||||
fractionDigits: 3,
|
||||
higherIsBetter: true,
|
||||
),
|
||||
CompareThingy(
|
||||
label: "VS/APM",
|
||||
greenSide: theGreenSide[2].nerdStats!.vsapm,
|
||||
redSide: theRedSide[2].nerdStats!.vsapm,
|
||||
fractionDigits: 3,
|
||||
higherIsBetter: true,
|
||||
),
|
||||
CompareThingy(
|
||||
label: "DS/S",
|
||||
greenSide: theGreenSide[2].nerdStats!.dss,
|
||||
redSide: theRedSide[2].nerdStats!.dss,
|
||||
fractionDigits: 3,
|
||||
higherIsBetter: true,
|
||||
),
|
||||
CompareThingy(
|
||||
label: "DS/P",
|
||||
greenSide: theGreenSide[2].nerdStats!.dsp,
|
||||
redSide: theRedSide[2].nerdStats!.dsp,
|
||||
fractionDigits: 3,
|
||||
higherIsBetter: true,
|
||||
),
|
||||
CompareThingy(
|
||||
label: "APP + DS/P",
|
||||
greenSide:
|
||||
theGreenSide[2].nerdStats!.appdsp,
|
||||
redSide: theRedSide[2].nerdStats!.appdsp,
|
||||
fractionDigits: 3,
|
||||
higherIsBetter: true,
|
||||
),
|
||||
CompareThingy(
|
||||
label: t.statCellNum.cheese.replaceAll(RegExp(r'\n'), " "),
|
||||
greenSide:
|
||||
theGreenSide[2].nerdStats!.cheese,
|
||||
redSide: theRedSide[2].nerdStats!.cheese,
|
||||
fractionDigits: 2,
|
||||
higherIsBetter: true,
|
||||
),
|
||||
CompareThingy(
|
||||
label: "Gb Eff.",
|
||||
greenSide: theGreenSide[2].nerdStats!.gbe,
|
||||
redSide: theRedSide[2].nerdStats!.gbe,
|
||||
fractionDigits: 3,
|
||||
higherIsBetter: true,
|
||||
),
|
||||
CompareThingy(
|
||||
label: "wAPP",
|
||||
greenSide:
|
||||
theGreenSide[2].nerdStats!.nyaapp,
|
||||
redSide: theRedSide[2].nerdStats!.nyaapp,
|
||||
fractionDigits: 3,
|
||||
higherIsBetter: true,
|
||||
),
|
||||
CompareThingy(
|
||||
label: "Area",
|
||||
greenSide: theGreenSide[2].nerdStats!.area,
|
||||
redSide: theRedSide[2].nerdStats!.area,
|
||||
fractionDigits: 2,
|
||||
higherIsBetter: true,
|
||||
),
|
||||
CompareThingy(
|
||||
label: t.statCellNum.estOfTRShort,
|
||||
greenSide: theGreenSide[2].estTr!.esttr,
|
||||
redSide: theRedSide[2].estTr!.esttr,
|
||||
fractionDigits: 2,
|
||||
higherIsBetter: true,
|
||||
),
|
||||
if (theGreenSide[2].gamesPlayed > 9 &&
|
||||
theGreenSide[2].gamesPlayed > 9 &&
|
||||
greenSideMode != Mode.stats &&
|
||||
redSideMode != Mode.stats)
|
||||
CompareThingy(
|
||||
label: t.statCellNum.accOfEstShort,
|
||||
greenSide: theGreenSide[2].esttracc!,
|
||||
redSide: theRedSide[2].esttracc!,
|
||||
fractionDigits: 2,
|
||||
higherIsBetter: true,
|
||||
),
|
||||
CompareThingy(
|
||||
label: "Opener",
|
||||
greenSide: theGreenSide[2].playstyle!.opener,
|
||||
redSide: theRedSide[2].playstyle!.opener,
|
||||
fractionDigits: 3,
|
||||
higherIsBetter: true,
|
||||
),
|
||||
CompareThingy(
|
||||
label: "Plonk",
|
||||
greenSide: theGreenSide[2].playstyle!.plonk,
|
||||
redSide: theRedSide[2].playstyle!.plonk,
|
||||
fractionDigits: 3,
|
||||
higherIsBetter: true,
|
||||
),
|
||||
CompareThingy(
|
||||
label: "Stride",
|
||||
greenSide: theGreenSide[2].playstyle!.stride,
|
||||
redSide: theRedSide[2].playstyle!.stride,
|
||||
fractionDigits: 3,
|
||||
higherIsBetter: true,
|
||||
),
|
||||
CompareThingy(
|
||||
label: "Inf. DS",
|
||||
greenSide: theGreenSide[2].playstyle!.infds,
|
||||
redSide: theRedSide[2].playstyle!.infds,
|
||||
fractionDigits: 3,
|
||||
higherIsBetter: true,
|
||||
),
|
||||
VsGraphs(theGreenSide[2].apm!, theGreenSide[2].pps!, theGreenSide[2].vs!, theGreenSide[2].nerdStats!, theGreenSide[2].playstyle!, theRedSide[2].apm!, theRedSide[2].pps!, theRedSide[2].vs!, theRedSide[2].nerdStats!, theRedSide[2].playstyle!),
|
||||
const Divider(),
|
||||
if (theGreenSide[2].nerdStats != null &&
|
||||
theRedSide[2].nerdStats != null)
|
||||
Column(
|
||||
children: [
|
||||
Padding(
|
||||
padding: const EdgeInsets.only(bottom: 16),
|
||||
child: Text(t.nerdStats,
|
||||
style: TextStyle(
|
||||
fontFamily: "Eurostile Round Extended",
|
||||
fontSize: bigScreen ? 42 : 28)),
|
||||
),
|
||||
CompareThingy(
|
||||
label: "APP",
|
||||
greenSide: theGreenSide[2].nerdStats!.app,
|
||||
redSide: theRedSide[2].nerdStats!.app,
|
||||
fractionDigits: 3,
|
||||
higherIsBetter: true,
|
||||
),
|
||||
CompareThingy(
|
||||
label: "VS/APM",
|
||||
greenSide: theGreenSide[2].nerdStats!.vsapm,
|
||||
redSide: theRedSide[2].nerdStats!.vsapm,
|
||||
fractionDigits: 3,
|
||||
higherIsBetter: true,
|
||||
),
|
||||
CompareThingy(
|
||||
label: "DS/S",
|
||||
greenSide: theGreenSide[2].nerdStats!.dss,
|
||||
redSide: theRedSide[2].nerdStats!.dss,
|
||||
fractionDigits: 3,
|
||||
higherIsBetter: true,
|
||||
),
|
||||
CompareThingy(
|
||||
label: "DS/P",
|
||||
greenSide: theGreenSide[2].nerdStats!.dsp,
|
||||
redSide: theRedSide[2].nerdStats!.dsp,
|
||||
fractionDigits: 3,
|
||||
higherIsBetter: true,
|
||||
),
|
||||
CompareThingy(
|
||||
label: "APP + DS/P",
|
||||
greenSide:
|
||||
theGreenSide[2].nerdStats!.appdsp,
|
||||
redSide: theRedSide[2].nerdStats!.appdsp,
|
||||
fractionDigits: 3,
|
||||
higherIsBetter: true,
|
||||
),
|
||||
CompareThingy(
|
||||
label: t.statCellNum.cheese.replaceAll(RegExp(r'\n'), " "),
|
||||
greenSide:
|
||||
theGreenSide[2].nerdStats!.cheese,
|
||||
redSide: theRedSide[2].nerdStats!.cheese,
|
||||
fractionDigits: 2,
|
||||
higherIsBetter: true,
|
||||
),
|
||||
CompareThingy(
|
||||
label: "Gb Eff.",
|
||||
greenSide: theGreenSide[2].nerdStats!.gbe,
|
||||
redSide: theRedSide[2].nerdStats!.gbe,
|
||||
fractionDigits: 3,
|
||||
higherIsBetter: true,
|
||||
),
|
||||
CompareThingy(
|
||||
label: "wAPP",
|
||||
greenSide:
|
||||
theGreenSide[2].nerdStats!.nyaapp,
|
||||
redSide: theRedSide[2].nerdStats!.nyaapp,
|
||||
fractionDigits: 3,
|
||||
higherIsBetter: true,
|
||||
),
|
||||
CompareThingy(
|
||||
label: "Area",
|
||||
greenSide: theGreenSide[2].nerdStats!.area,
|
||||
redSide: theRedSide[2].nerdStats!.area,
|
||||
fractionDigits: 2,
|
||||
higherIsBetter: true,
|
||||
),
|
||||
CompareThingy(
|
||||
label: t.statCellNum.estOfTRShort,
|
||||
greenSide: theGreenSide[2].estTr!.esttr,
|
||||
redSide: theRedSide[2].estTr!.esttr,
|
||||
fractionDigits: 2,
|
||||
higherIsBetter: true,
|
||||
),
|
||||
if (theGreenSide[2].gamesPlayed > 9 &&
|
||||
theGreenSide[2].gamesPlayed > 9 &&
|
||||
greenSideMode != Mode.stats &&
|
||||
redSideMode != Mode.stats)
|
||||
CompareThingy(
|
||||
label: t.statCellNum.accOfEstShort,
|
||||
greenSide: theGreenSide[2].esttracc!,
|
||||
redSide: theRedSide[2].esttracc!,
|
||||
fractionDigits: 2,
|
||||
higherIsBetter: true,
|
||||
),
|
||||
CompareThingy(
|
||||
label: "Opener",
|
||||
greenSide: theGreenSide[2].playstyle!.opener,
|
||||
redSide: theRedSide[2].playstyle!.opener,
|
||||
fractionDigits: 3,
|
||||
higherIsBetter: true,
|
||||
),
|
||||
CompareThingy(
|
||||
label: "Plonk",
|
||||
greenSide: theGreenSide[2].playstyle!.plonk,
|
||||
redSide: theRedSide[2].playstyle!.plonk,
|
||||
fractionDigits: 3,
|
||||
higherIsBetter: true,
|
||||
),
|
||||
CompareThingy(
|
||||
label: "Stride",
|
||||
greenSide: theGreenSide[2].playstyle!.stride,
|
||||
redSide: theRedSide[2].playstyle!.stride,
|
||||
fractionDigits: 3,
|
||||
higherIsBetter: true,
|
||||
),
|
||||
CompareThingy(
|
||||
label: "Inf. DS",
|
||||
greenSide: theGreenSide[2].playstyle!.infds,
|
||||
redSide: theRedSide[2].playstyle!.infds,
|
||||
fractionDigits: 3,
|
||||
higherIsBetter: true,
|
||||
),
|
||||
VsGraphs(theGreenSide[2].apm!, theGreenSide[2].pps!, theGreenSide[2].vs!, theGreenSide[2].nerdStats!, theGreenSide[2].playstyle!, theRedSide[2].apm!, theRedSide[2].pps!, theRedSide[2].vs!, theRedSide[2].nerdStats!, theRedSide[2].playstyle!),
|
||||
const Divider(),
|
||||
Padding(
|
||||
padding: const EdgeInsets.only(bottom: 16),
|
||||
child: Text(t.winChance,
|
||||
style: TextStyle(
|
||||
fontFamily: "Eurostile Round Extended",
|
||||
fontSize: bigScreen ? 42 : 28)),
|
||||
),
|
||||
if (greenSideMode != Mode.stats && redSideMode != Mode.stats &&
|
||||
theGreenSide[2].gamesPlayed > 9 && theRedSide[2].gamesPlayed > 9)
|
||||
CompareThingy(
|
||||
label: t.byGlicko,
|
||||
greenSide: getWinrateByTR(
|
||||
theGreenSide[2].glicko!,
|
||||
theGreenSide[2].rd!,
|
||||
theRedSide[2].glicko!,
|
||||
theRedSide[2].rd!) *
|
||||
100,
|
||||
redSide: getWinrateByTR(
|
||||
theRedSide[2].glicko!,
|
||||
theRedSide[2].rd!,
|
||||
theGreenSide[2].glicko!,
|
||||
theGreenSide[2].rd!) *
|
||||
100,
|
||||
fractionDigits: 2,
|
||||
higherIsBetter: true,
|
||||
postfix: "%",
|
||||
),
|
||||
CompareThingy(
|
||||
label: t.byEstTR,
|
||||
greenSide: getWinrateByTR(
|
||||
theGreenSide[2].estTr!.estglicko,
|
||||
theGreenSide[2].rd ?? noTrRd,
|
||||
theRedSide[2].estTr!.estglicko,
|
||||
theRedSide[2].rd ?? noTrRd) *
|
||||
100,
|
||||
redSide: getWinrateByTR(
|
||||
theRedSide[2].estTr!.estglicko,
|
||||
theRedSide[2].rd ?? noTrRd,
|
||||
theGreenSide[2].estTr!.estglicko,
|
||||
theGreenSide[2].rd ?? noTrRd) *
|
||||
100,
|
||||
fractionDigits: 2,
|
||||
higherIsBetter: true,
|
||||
postfix: "%",
|
||||
),
|
||||
],
|
||||
)
|
||||
] : [Padding(
|
||||
padding: const EdgeInsets.all(8.0),
|
||||
child: Text(t.compareViewNoValues(avgR: "\$avgR"), textAlign: TextAlign.center),
|
||||
)], // This is so fucked up holy shit
|
||||
Padding(
|
||||
padding: const EdgeInsets.only(bottom: 16),
|
||||
child: Text(t.winChance,
|
||||
style: TextStyle(
|
||||
fontFamily: "Eurostile Round Extended",
|
||||
fontSize: bigScreen ? 42 : 28)),
|
||||
),
|
||||
if (greenSideMode != Mode.stats && redSideMode != Mode.stats &&
|
||||
theGreenSide[2].gamesPlayed > 9 && theRedSide[2].gamesPlayed > 9)
|
||||
CompareThingy(
|
||||
label: t.byGlicko,
|
||||
greenSide: getWinrateByTR(
|
||||
theGreenSide[2].glicko!,
|
||||
theGreenSide[2].rd!,
|
||||
theRedSide[2].glicko!,
|
||||
theRedSide[2].rd!) *
|
||||
100,
|
||||
redSide: getWinrateByTR(
|
||||
theRedSide[2].glicko!,
|
||||
theRedSide[2].rd!,
|
||||
theGreenSide[2].glicko!,
|
||||
theGreenSide[2].rd!) *
|
||||
100,
|
||||
fractionDigits: 2,
|
||||
higherIsBetter: true,
|
||||
postfix: "%",
|
||||
),
|
||||
CompareThingy(
|
||||
label: t.byEstTR,
|
||||
greenSide: getWinrateByTR(
|
||||
theGreenSide[2].estTr!.estglicko,
|
||||
theGreenSide[2].rd ?? noTrRd,
|
||||
theRedSide[2].estTr!.estglicko,
|
||||
theRedSide[2].rd ?? noTrRd) *
|
||||
100,
|
||||
redSide: getWinrateByTR(
|
||||
theRedSide[2].estTr!.estglicko,
|
||||
theRedSide[2].rd ?? noTrRd,
|
||||
theGreenSide[2].estTr!.estglicko,
|
||||
theGreenSide[2].rd ?? noTrRd) *
|
||||
100,
|
||||
fractionDigits: 2,
|
||||
higherIsBetter: true,
|
||||
postfix: "%",
|
||||
),
|
||||
],
|
||||
)
|
||||
],
|
||||
)
|
||||
else Padding(
|
||||
padding: const EdgeInsets.all(8.0),
|
||||
child: Text(t.compareViewNoValues(avgR: "\$avgR"), textAlign: TextAlign.center),
|
||||
)
|
||||
],
|
||||
),
|
||||
),
|
||||
),
|
||||
),
|
||||
);
|
||||
|
@ -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 {
|
||||
final num greenSide;
|
||||
final num redSide;
|
||||
|
@ -868,7 +861,7 @@ class CompareThingy extends StatelessWidget {
|
|||
Text(
|
||||
verdict(greenSide, redSide,
|
||||
fractionDigits != null ? fractionDigits! + 2 : 0),
|
||||
style: const TextStyle(fontSize: 16),
|
||||
style: verdictStyle,
|
||||
textAlign: TextAlign.center,
|
||||
)
|
||||
],
|
||||
|
@ -981,11 +974,7 @@ class CompareBoolThingy extends StatelessWidget {
|
|||
style: const TextStyle(fontSize: 22),
|
||||
textAlign: TextAlign.center,
|
||||
),
|
||||
const Text(
|
||||
"---",
|
||||
style: TextStyle(fontSize: 16),
|
||||
textAlign: TextAlign.center,
|
||||
)
|
||||
const Text("---", style: verdictStyle, textAlign: TextAlign.center)
|
||||
],
|
||||
),
|
||||
Expanded(
|
||||
|
@ -1085,10 +1074,7 @@ class CompareDurationThingy extends StatelessWidget {
|
|||
textAlign: TextAlign.center,
|
||||
),
|
||||
Text(
|
||||
verdict(greenSide, redSide).toString(),
|
||||
style: const TextStyle(fontSize: 16),
|
||||
textAlign: TextAlign.center,
|
||||
)
|
||||
verdict(greenSide, redSide).toString(), style: verdictStyle, textAlign: TextAlign.center)
|
||||
],
|
||||
),
|
||||
Expanded(
|
||||
|
@ -1176,11 +1162,7 @@ class CompareRegTimeThingy extends StatelessWidget {
|
|||
style: const TextStyle(fontSize: 22),
|
||||
textAlign: TextAlign.center,
|
||||
),
|
||||
Text(
|
||||
verdict(greenSide, redSide),
|
||||
style: const TextStyle(fontSize: 16),
|
||||
textAlign: TextAlign.center,
|
||||
)
|
||||
Text(verdict(greenSide, redSide), style: verdictStyle, textAlign: TextAlign.center)
|
||||
],
|
||||
),
|
||||
Expanded(
|
||||
|
|
|
@ -20,6 +20,7 @@ class CustomizationView extends StatefulWidget {
|
|||
|
||||
class CustomizationState extends State<CustomizationView> {
|
||||
late SharedPreferences prefs;
|
||||
late bool oskKagariGimmick;
|
||||
|
||||
void changeColor(Color color) {
|
||||
setState(() => pickerColor = color);
|
||||
|
@ -31,7 +32,7 @@ class CustomizationState extends State<CustomizationView> {
|
|||
windowManager.getTitle().then((value) => oldWindowTitle = value);
|
||||
windowManager.setTitle("Tetra Stats: ${t.settings}");
|
||||
}
|
||||
_getPreferences();
|
||||
_getPreferences().then((value) => setState((){}));
|
||||
super.initState();
|
||||
}
|
||||
|
||||
|
@ -43,6 +44,11 @@ class CustomizationState extends State<CustomizationView> {
|
|||
|
||||
Future<void> _getPreferences() async {
|
||||
prefs = await SharedPreferences.getInstance();
|
||||
if (prefs.getBool("oskKagariGimmick") != null) {
|
||||
oskKagariGimmick = prefs.getBool("oskKagariGimmick")!;
|
||||
} else {
|
||||
oskKagariGimmick = true;
|
||||
}
|
||||
}
|
||||
|
||||
ThemeData getTheme(BuildContext context, Color color){
|
||||
|
@ -66,59 +72,48 @@ class CustomizationState extends State<CustomizationView> {
|
|||
body: SafeArea(
|
||||
child: ListView(
|
||||
children: [
|
||||
ListTile(
|
||||
title: const Text("Accent Color"),
|
||||
trailing: ColorIndicator(HSVColor.fromColor(Theme.of(context).colorScheme.primary)),
|
||||
onTap: () {
|
||||
showDialog(
|
||||
context: context,
|
||||
builder: (BuildContext context) => AlertDialog(
|
||||
title: const Text('Pick a color!'),
|
||||
content: SingleChildScrollView(
|
||||
child: ColorPicker(
|
||||
pickerColor: pickerColor,
|
||||
onColorChanged: changeColor,
|
||||
),
|
||||
// Use Material color picker:
|
||||
//
|
||||
// child: MaterialPicker(
|
||||
// pickerColor: pickerColor,
|
||||
// onColorChanged: changeColor,
|
||||
// showLabel: true, // only on portrait mode
|
||||
// ),
|
||||
//
|
||||
// Use Block color picker:
|
||||
//
|
||||
// child: BlockPicker(
|
||||
// pickerColor: currentColor,
|
||||
// onColorChanged: changeColor,
|
||||
// ),
|
||||
//
|
||||
// child: MultipleChoiceBlockPicker(
|
||||
// pickerColors: currentColors,
|
||||
// onColorsChanged: changeColors,
|
||||
// ),
|
||||
),
|
||||
actions: <Widget>[
|
||||
ElevatedButton(
|
||||
child: const Text('Got it'),
|
||||
onPressed: () {
|
||||
setState(() {
|
||||
setAccentColor(pickerColor);
|
||||
});
|
||||
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"),
|
||||
),
|
||||
// ListTile(
|
||||
// title: const Text("Accent color"),
|
||||
// trailing: ColorIndicator(HSVColor.fromColor(Theme.of(context).colorScheme.primary)),
|
||||
// onTap: () {
|
||||
// showDialog(
|
||||
// context: context,
|
||||
// builder: (BuildContext context) => AlertDialog(
|
||||
// title: const Text('Pick an accent color'),
|
||||
// content: SingleChildScrollView(
|
||||
// child: ColorPicker(
|
||||
// pickerColor: pickerColor,
|
||||
// onColorChanged: changeColor,
|
||||
// ),
|
||||
// ),
|
||||
// actions: <Widget>[
|
||||
// ElevatedButton(
|
||||
// child: const Text('Set'),
|
||||
// onPressed: () {
|
||||
// setState(() {
|
||||
// setAccentColor(pickerColor);
|
||||
// });
|
||||
// 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"),
|
||||
// ),
|
||||
ListTile(title: Text(t.oskKagari),
|
||||
subtitle: Text(t.oskKagariDescription),
|
||||
trailing: Switch(value: oskKagariGimmick, onChanged: (bool value){
|
||||
prefs.setBool("oskKagariGimmick", value);
|
||||
setState(() {
|
||||
oskKagariGimmick = value;
|
||||
});
|
||||
}),)
|
||||
],
|
||||
)),
|
||||
);
|
||||
|
|
|
@ -8,7 +8,6 @@ import 'package:tetra_stats/views/tl_match_view.dart';
|
|||
import 'package:window_manager/window_manager.dart';
|
||||
|
||||
final TetrioService teto = TetrioService();
|
||||
final NumberFormat f2 = NumberFormat.decimalPatternDigits(locale: LocaleSettings.currentLocale.languageCode, decimalDigits: 2);
|
||||
late String oldWindowTitle;
|
||||
|
||||
class MatchesView extends StatefulWidget {
|
||||
|
|
|
@ -16,6 +16,7 @@ Stats _chartsX = Stats.tr;
|
|||
Stats _chartsY = Stats.apm;
|
||||
List<DropdownMenuItem> _itemStats = [for (MapEntry e in chartsShortTitles.entries) DropdownMenuItem(value: e.key, child: Text(e.value))];
|
||||
Stats _sortBy = Stats.tr;
|
||||
late List<TetrioPlayerFromLeaderboard> they;
|
||||
bool _reversed = false;
|
||||
List<DropdownMenuItem> _itemCountries = [for (MapEntry e in t.countries.entries) DropdownMenuItem(value: e.key, child: Text(e.value))];
|
||||
String _country = "";
|
||||
|
@ -61,6 +62,7 @@ class RankState extends State<RankView> with SingleTickerProviderStateMixin {
|
|||
}
|
||||
super.initState();
|
||||
previousAxisTitles = _chartsX.toString()+_chartsY.toString();
|
||||
they = TetrioPlayersLeaderboard("lol", []).getStatRanking(widget.rank[1]["entries"]!, _sortBy, reversed: _reversed, country: _country);
|
||||
recalculateBoundaries();
|
||||
resetScale();
|
||||
}
|
||||
|
@ -73,7 +75,7 @@ class RankState extends State<RankView> with SingleTickerProviderStateMixin {
|
|||
} else {
|
||||
return element;
|
||||
}
|
||||
}).getStatByEnum(_chartsX) as double;
|
||||
}).getStatByEnum(_chartsX).toDouble();
|
||||
actualMaxX = (widget.rank[1]["entries"] as List<TetrioPlayerFromLeaderboard>).reduce((value, element) {
|
||||
num n = max(value.getStatByEnum(_chartsX), element.getStatByEnum(_chartsX));
|
||||
if (value.getStatByEnum(_chartsX) == n) {
|
||||
|
@ -81,7 +83,7 @@ class RankState extends State<RankView> with SingleTickerProviderStateMixin {
|
|||
} else {
|
||||
return element;
|
||||
}
|
||||
}).getStatByEnum(_chartsX) as double;
|
||||
}).getStatByEnum(_chartsX).toDouble();
|
||||
actualMinY = (widget.rank[1]["entries"] as List<TetrioPlayerFromLeaderboard>).reduce((value, element) {
|
||||
num n = min(value.getStatByEnum(_chartsY), element.getStatByEnum(_chartsY));
|
||||
if (value.getStatByEnum(_chartsY) == n) {
|
||||
|
@ -89,7 +91,7 @@ class RankState extends State<RankView> with SingleTickerProviderStateMixin {
|
|||
} else {
|
||||
return element;
|
||||
}
|
||||
}).getStatByEnum(_chartsY) as double;
|
||||
}).getStatByEnum(_chartsY).toDouble();
|
||||
actualMaxY = (widget.rank[1]["entries"] as List<TetrioPlayerFromLeaderboard>).reduce((value, element) {
|
||||
num n = max(value.getStatByEnum(_chartsY), element.getStatByEnum(_chartsY));
|
||||
if (value.getStatByEnum(_chartsY) == n) {
|
||||
|
@ -97,7 +99,7 @@ class RankState extends State<RankView> with SingleTickerProviderStateMixin {
|
|||
} else {
|
||||
return element;
|
||||
}
|
||||
}).getStatByEnum(_chartsY) as double;
|
||||
}).getStatByEnum(_chartsY).toDouble();
|
||||
}
|
||||
|
||||
void resetScale(){
|
||||
|
@ -164,7 +166,7 @@ class RankState extends State<RankView> with SingleTickerProviderStateMixin {
|
|||
previousAxisTitles = _chartsX.toString()+_chartsY.toString();
|
||||
}
|
||||
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(
|
||||
appBar: AppBar(
|
||||
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"])
|
||||
if (entry.apm != 0.0 && entry.vs != 0.0) // prevents from ScatterChart "Offset argument contained a NaN value." exception
|
||||
_MyScatterSpot(
|
||||
entry.getStatByEnum(_chartsX) as double,
|
||||
entry.getStatByEnum(_chartsY) as double,
|
||||
entry.getStatByEnum(_chartsX).toDouble(),
|
||||
entry.getStatByEnum(_chartsY).toDouble(),
|
||||
entry.userId,
|
||||
entry.username,
|
||||
dotPainter: FlDotCirclePainter(color: rankColors[entry.rank]??Colors.white, radius: 3))
|
||||
|
@ -403,7 +405,9 @@ class RankState extends State<RankView> with SingleTickerProviderStateMixin {
|
|||
value: _sortBy,
|
||||
onChanged: ((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 'package:flutter/foundation.dart';
|
||||
import 'package:flutter/material.dart';
|
||||
import 'package:intl/intl.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:window_manager/window_manager.dart';
|
||||
import 'main_view.dart'; // lol
|
||||
|
@ -40,7 +40,6 @@ class RanksAverages extends State<RankAveragesView> {
|
|||
|
||||
@override
|
||||
Widget build(BuildContext context) {
|
||||
final NumberFormat f2 = NumberFormat.decimalPattern(LocaleSettings.currentLocale.languageCode)..maximumFractionDigits = 2;
|
||||
return Scaffold(
|
||||
appBar: AppBar(
|
||||
title: Text(t.rankAveragesViewTitle),
|
||||
|
@ -55,7 +54,8 @@ class RanksAverages extends State<RankAveragesView> {
|
|||
return ListTile(
|
||||
leading: Image.asset("res/tetrio_tl_alpha_ranks/${keys[index]}.png", height: 48),
|
||||
title: Text(t.players(n: averages[keys[index]]?[1]["players"]), style: const TextStyle(fontFamily: "Eurostile Round Extended")),
|
||||
subtitle: Text("${f2.format(averages[keys[index]]?[0].apm)} APM, ${f2.format(averages[keys[index]]?[0].pps)} PPS, ${f2.format(averages[keys[index]]?[0].vs)} VS, ${f2.format(averages[keys[index]]?[0].nerdStats.app)} APP, ${f2.format(averages[keys[index]]?[0].nerdStats.vsapm)} VS/APM"),
|
||||
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),
|
||||
onTap: (){
|
||||
if (averages[keys[index]]?[1]["players"] > 0) {
|
||||
|
|
|
@ -1,4 +1,5 @@
|
|||
import 'dart:io';
|
||||
import 'package:go_router/go_router.dart';
|
||||
import 'package:tetra_stats/data_objects/tetrio.dart';
|
||||
import 'package:tetra_stats/main.dart' show packageInfo;
|
||||
import 'package:file_selector/file_selector.dart';
|
||||
|
@ -26,6 +27,7 @@ class SettingsState extends State<SettingsView> {
|
|||
late SharedPreferences prefs;
|
||||
final TetrioService teto = TetrioService();
|
||||
String defaultNickname = "Checking...";
|
||||
late bool showPositions;
|
||||
final TextEditingController _playertext = TextEditingController();
|
||||
|
||||
@override
|
||||
|
@ -46,6 +48,11 @@ class SettingsState extends State<SettingsView> {
|
|||
|
||||
Future<void> _getPreferences() async {
|
||||
prefs = await SharedPreferences.getInstance();
|
||||
if (prefs.getBool("showPositions") != null) {
|
||||
showPositions = prefs.getBool("showPositions")!;
|
||||
} else {
|
||||
showPositions = false;
|
||||
}
|
||||
_setDefaultNickname(prefs.getString("player"));
|
||||
}
|
||||
|
||||
|
@ -254,12 +261,20 @@ class SettingsState extends State<SettingsView> {
|
|||
},
|
||||
),
|
||||
),
|
||||
ListTile(title: const Text("Customization"),
|
||||
subtitle: const Text("I don't want to implement this"),
|
||||
ListTile(title: Text(t.customization),
|
||||
subtitle: Text(t.customizationDescription),
|
||||
trailing: const Icon(Icons.arrow_right),
|
||||
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(),
|
||||
ListTile(
|
||||
onTap: (){
|
||||
|
@ -267,6 +282,7 @@ class SettingsState extends State<SettingsView> {
|
|||
},
|
||||
title: Text(t.aboutApp),
|
||||
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.waiting:
|
||||
case ConnectionState.active:
|
||||
return const Center(child: Text('Fetching...'));
|
||||
return const Center(child: CircularProgressIndicator());
|
||||
case ConnectionState.done:
|
||||
final allPlayers = snapshot.data?.getStatRanking(snapshot.data!.leaderboard, _sortBy, reversed: reversed, country: _country);
|
||||
if (!kIsWeb && !Platform.isAndroid && !Platform.isIOS) windowManager.setTitle("Tetra Stats: ${t.tlLeaderboard} - ${t.players(n: allPlayers!.length)}");
|
||||
|
@ -175,7 +175,8 @@ class TLLeaderboardState extends State<TLLeaderboardView> {
|
|||
return ListTile(
|
||||
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")),
|
||||
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(
|
||||
mainAxisSize: MainAxisSize.min,
|
||||
children: [
|
||||
|
|
|
@ -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:flutter/material.dart';
|
||||
import 'package:intl/intl.dart';
|
||||
import 'package:tetra_stats/data_objects/tetrio.dart';
|
||||
import 'package:tetra_stats/gen/strings.g.dart';
|
||||
|
||||
final NumberFormat _f2 = NumberFormat.decimalPatternDigits(locale: LocaleSettings.currentLocale.languageCode, decimalDigits: 2);
|
||||
import 'package:tetra_stats/utils/numers_formats.dart';
|
||||
|
||||
class Graphs extends StatelessWidget{
|
||||
const Graphs(
|
||||
|
@ -125,13 +122,13 @@ class Graphs extends StatelessWidget{
|
|||
getTitle: (index, angle) {
|
||||
switch (index) {
|
||||
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:
|
||||
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:
|
||||
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:
|
||||
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:
|
||||
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:intl/intl.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';
|
||||
|
||||
class StatCellNum extends StatelessWidget {
|
||||
const StatCellNum(
|
||||
|
@ -8,11 +11,12 @@ class StatCellNum extends StatelessWidget {
|
|||
required this.playerStat,
|
||||
required this.playerStatLabel,
|
||||
required this.isScreenBig,
|
||||
this.smallDecimal = true,
|
||||
this.alertWidgets,
|
||||
this.fractionDigits,
|
||||
this.oldPlayerStat,
|
||||
required this.higherIsBetter,
|
||||
this.okText, this.alertTitle});
|
||||
this.okText, this.alertTitle, this.pos, this.averageStat});
|
||||
|
||||
final num playerStat;
|
||||
final num? oldPlayerStat;
|
||||
|
@ -20,39 +24,57 @@ class StatCellNum extends StatelessWidget {
|
|||
final String playerStatLabel;
|
||||
final String? okText;
|
||||
final bool isScreenBig;
|
||||
final bool smallDecimal;
|
||||
final String? alertTitle;
|
||||
final List<Widget>? alertWidgets;
|
||||
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
|
||||
Widget build(BuildContext context) {
|
||||
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;
|
||||
num fraction = playerStat.isNegative ? 1 - (playerStat - playerStat.floor()) : playerStat - playerStat.floor();
|
||||
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(
|
||||
children: [
|
||||
RichText(
|
||||
text: TextSpan(text: intf.format(integer),
|
||||
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(
|
||||
fontFamily: "Eurostile Round Extended",
|
||||
//fontWeight: FontWeight.bold,
|
||||
fontSize: isScreenBig ? 32 : 24,
|
||||
color: Colors.white
|
||||
color: getStatColor()
|
||||
)
|
||||
)
|
||||
),
|
||||
if (oldPlayerStat != null) Text(comparef.format(playerStat - oldPlayerStat!), style: TextStyle(
|
||||
color: higherIsBetter ?
|
||||
oldPlayerStat! > playerStat ? Colors.red : Colors.green :
|
||||
oldPlayerStat! < playerStat ? Colors.red : Colors.green
|
||||
),),
|
||||
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 ?
|
||||
oldPlayerStat! > playerStat ? Colors.redAccent : Colors.greenAccent :
|
||||
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
|
||||
? Text(
|
||||
playerStatLabel,
|
||||
|
|
|
@ -3,13 +3,16 @@ import 'package:intl/intl.dart';
|
|||
import 'package:tetra_stats/data_objects/tetrio.dart';
|
||||
import 'package:syncfusion_flutter_gauges/gauges.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/stat_sell_num.dart';
|
||||
|
||||
var fDiff = NumberFormat("+#,###.###;-#,###.###");
|
||||
var intFDiff = NumberFormat("+#,###;-#,###");
|
||||
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;
|
||||
TetraLeagueAlpha? oldTl;
|
||||
late TetraLeagueAlpha currentTl;
|
||||
|
@ -23,18 +26,26 @@ class TLThingy extends StatefulWidget {
|
|||
final bool bot;
|
||||
final bool guest;
|
||||
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
|
||||
State<TLThingy> createState() => _TLThingyState();
|
||||
}
|
||||
|
||||
class _TLThingyState extends State<TLThingy> {
|
||||
late bool oskKagariGimmick;
|
||||
|
||||
@override
|
||||
void initState() {
|
||||
_currentRangeValues = const RangeValues(0, 1);
|
||||
sortedStates = widget.states.reversed.toList();
|
||||
oskKagariGimmick = prefs.getBool("oskKagariGimmick")??true;
|
||||
try{
|
||||
oldTl = sortedStates[1].tlSeason1;
|
||||
}on RangeError{
|
||||
|
@ -47,9 +58,11 @@ class _TLThingyState extends State<TLThingy> {
|
|||
@override
|
||||
Widget build(BuildContext 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,));
|
||||
return LayoutBuilder(builder: (context, constraints) {
|
||||
bool bigScreen = constraints.maxWidth > 768;
|
||||
bool bigScreen = constraints.maxWidth >= 768;
|
||||
return ListView.builder(
|
||||
physics: const ClampingScrollPhysics(),
|
||||
itemCount: 1,
|
||||
|
@ -87,7 +100,7 @@ class _TLThingyState extends State<TLThingy> {
|
|||
crossAxisAlignment: WrapCrossAlignment.center,
|
||||
clipBehavior: Clip.hardEdge,
|
||||
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/tetrio_tl_alpha_ranks/${currentTl.rank}.png", height: 128),
|
||||
Column(
|
||||
|
@ -146,12 +159,12 @@ class _TLThingyState extends State<TLThingy> {
|
|||
softWrap: true,
|
||||
textAlign: TextAlign.center,
|
||||
style: TextStyle(
|
||||
fontFamily: "Eurostile Round Extended",
|
||||
fontFamily: "Eurostile Round",
|
||||
fontSize: bigScreen ? 42 : 28,
|
||||
overflow: TextOverflow.visible,
|
||||
)),
|
||||
Padding(
|
||||
padding: const EdgeInsets.fromLTRB(0, 16, 0, 48),
|
||||
padding: const EdgeInsets.fromLTRB(8, 16, 8, 48),
|
||||
child: Wrap(
|
||||
direction: Axis.horizontal,
|
||||
alignment: WrapAlignment.center,
|
||||
|
@ -159,13 +172,13 @@ class _TLThingyState extends State<TLThingy> {
|
|||
crossAxisAlignment: WrapCrossAlignment.start,
|
||||
clipBehavior: Clip.hardEdge,
|
||||
children: [
|
||||
if (currentTl.apm != null) StatCellNum(playerStat: currentTl.apm!, isScreenBig: bigScreen, fractionDigits: 2, playerStatLabel: t.statCellNum.apm, higherIsBetter: true, oldPlayerStat: oldTl?.apm),
|
||||
if (currentTl.pps != null) StatCellNum(playerStat: currentTl.pps!, isScreenBig: bigScreen, fractionDigits: 2, playerStatLabel: t.statCellNum.pps, higherIsBetter: true, oldPlayerStat: oldTl?.pps),
|
||||
if (currentTl.vs != null) StatCellNum(playerStat: currentTl.vs!, isScreenBig: bigScreen, fractionDigits: 2, playerStatLabel: t.statCellNum.vs, higherIsBetter: true, oldPlayerStat: oldTl?.vs),
|
||||
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, 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, 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),
|
||||
StatCellNum(playerStat: currentTl.gamesPlayed, isScreenBig: bigScreen, playerStatLabel: t.statCellNum.gamesPlayed, higherIsBetter: true, oldPlayerStat: oldTl?.gamesPlayed),
|
||||
StatCellNum(playerStat: currentTl.gamesWon, isScreenBig: bigScreen, playerStatLabel: t.statCellNum.gamesWonTL, higherIsBetter: true, oldPlayerStat: oldTl?.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.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, 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, pos: widget.lbPositions?.winrate, averageStat: widget.averages != null ? widget.averages!.winrate * 100 : null),
|
||||
],
|
||||
),
|
||||
),
|
||||
|
@ -176,236 +189,181 @@ class _TLThingyState extends State<TLThingy> {
|
|||
Padding(
|
||||
padding: const EdgeInsets.fromLTRB(0, 40, 0, 0),
|
||||
child: Wrap(
|
||||
direction: Axis.horizontal,
|
||||
alignment: WrapAlignment.center,
|
||||
spacing: 35,
|
||||
crossAxisAlignment: WrapCrossAlignment.start,
|
||||
clipBehavior: Clip.hardEdge,
|
||||
children: [
|
||||
SizedBox(
|
||||
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.2, endValue: 0.4, color: Colors.yellow),
|
||||
GaugeRange(startValue: 0.4, endValue: 0.6, color: Colors.green),
|
||||
GaugeRange(startValue: 0.6, endValue: 0.8, color: Colors.blue),
|
||||
GaugeRange(startValue: 0.8, endValue: 1, color: Colors.purple),
|
||||
],
|
||||
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.exactValue}: ${currentTl.nerdStats!.app}")
|
||||
]),
|
||||
),
|
||||
actions: <Widget>[
|
||||
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: 2.0, endValue: 2.2, color: Colors.blue),
|
||||
GaugeRange(startValue: 2.2, endValue: 2.4, color: Colors.purple),
|
||||
],
|
||||
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.exactValue}: ${currentTl.nerdStats!.vsapm}")
|
||||
]),
|
||||
),
|
||||
actions: <Widget>[
|
||||
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!.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,
|
||||
alignment: WrapAlignment.center,
|
||||
spacing: 25,
|
||||
spacing: 35,
|
||||
crossAxisAlignment: WrapCrossAlignment.start,
|
||||
clipBehavior: Clip.hardEdge,
|
||||
children: [
|
||||
StatCellNum(playerStat: currentTl.nerdStats!.dss, isScreenBig: bigScreen, fractionDigits: 3, playerStatLabel: t.statCellNum.dss,
|
||||
alertWidgets: [Text(t.statCellNum.dssDescription),
|
||||
Text("${t.formula}: (VS / 100) - (APM / 60)"),
|
||||
Text("${t.exactValue}: ${currentTl.nerdStats!.dss}"),],
|
||||
okText: t.popupActions.ok,
|
||||
higherIsBetter: true,
|
||||
oldPlayerStat: oldTl?.nerdStats?.dss,),
|
||||
StatCellNum(playerStat: currentTl.nerdStats!.dsp, isScreenBig: bigScreen, fractionDigits: 3, playerStatLabel: t.statCellNum.dsp,
|
||||
alertWidgets: [Text(t.statCellNum.dspDescription),
|
||||
Text("${t.formula}: DS/S / PPS"),
|
||||
Text("${t.exactValue}: ${currentTl.nerdStats!.dsp}"),],
|
||||
okText: t.popupActions.ok,
|
||||
higherIsBetter: true,
|
||||
oldPlayerStat: oldTl?.nerdStats?.dsp,),
|
||||
StatCellNum(playerStat: currentTl.nerdStats!.appdsp, isScreenBig: bigScreen, fractionDigits: 3, playerStatLabel: t.statCellNum.appdsp,
|
||||
alertWidgets: [Text(t.statCellNum.appdspDescription),
|
||||
Text("${t.formula}: APP + DS/P"),
|
||||
Text("${t.exactValue}: ${currentTl.nerdStats!.appdsp}"),],
|
||||
okText: t.popupActions.ok,
|
||||
higherIsBetter: true,
|
||||
oldPlayerStat: oldTl?.nerdStats?.appdsp,),
|
||||
StatCellNum(playerStat: currentTl.nerdStats!.cheese, isScreenBig: bigScreen, fractionDigits: 2, playerStatLabel: t.statCellNum.cheese,
|
||||
alertWidgets: [Text(t.statCellNum.cheeseDescription),
|
||||
Text("${t.formula}: (DS/P * 150) + ((VS/APM - 2) * 50) + (0.6 - APP) * 125"),
|
||||
Text("${t.exactValue}: ${currentTl.nerdStats!.cheese}"),],
|
||||
okText: t.popupActions.ok,
|
||||
higherIsBetter: true,
|
||||
oldPlayerStat: oldTl?.nerdStats?.cheese,),
|
||||
StatCellNum(playerStat: currentTl.nerdStats!.gbe, isScreenBig: bigScreen, fractionDigits: 3, playerStatLabel: t.statCellNum.gbe,
|
||||
alertWidgets: [Text(t.statCellNum.gbeDescription),
|
||||
Text("${t.formula}: APP * DS/P * 2"),
|
||||
Text("${t.exactValue}: ${currentTl.nerdStats!.gbe}"),],
|
||||
okText: t.popupActions.ok,
|
||||
higherIsBetter: true,
|
||||
oldPlayerStat: oldTl?.nerdStats?.gbe,),
|
||||
StatCellNum(playerStat: currentTl.nerdStats!.nyaapp, isScreenBig: bigScreen, fractionDigits: 3, playerStatLabel: t.statCellNum.nyaapp,
|
||||
alertWidgets: [Text(t.statCellNum.nyaappDescription),
|
||||
Text("${t.formula}: APP - 5 * tan(radians((Cheese Index / -30) + 1))"),
|
||||
Text("${t.exactValue}: ${currentTl.nerdStats!.nyaapp}"),],
|
||||
okText: t.popupActions.ok,
|
||||
higherIsBetter: true,
|
||||
oldPlayerStat: oldTl?.nerdStats?.nyaapp,),
|
||||
StatCellNum(playerStat: currentTl.nerdStats!.area, isScreenBig: bigScreen, fractionDigits: 1, playerStatLabel: t.statCellNum.area,
|
||||
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.exactValue}: ${currentTl.nerdStats!.area}"),],
|
||||
okText: t.popupActions.ok,
|
||||
higherIsBetter: true,
|
||||
oldPlayerStat: oldTl?.nerdStats?.area,)
|
||||
])
|
||||
GaugetNum(playerStat: currentTl.nerdStats!.app, playerStatLabel: t.statCellNum.app, higherIsBetter: true, minimum: 0, maximum: 1, ranges: [
|
||||
GaugeRange(startValue: 0, endValue: 0.2, color: Colors.red),
|
||||
GaugeRange(startValue: 0.2, endValue: 0.4, color: Colors.yellow),
|
||||
GaugeRange(startValue: 0.4, endValue: 0.6, color: Colors.green),
|
||||
GaugeRange(startValue: 0.6, endValue: 0.8, color: Colors.blue),
|
||||
GaugeRange(startValue: 0.8, endValue: 1, color: Colors.purple),
|
||||
], alertWidgets: [
|
||||
Text(t.statCellNum.appDescription),
|
||||
Text("${t.exactValue}: ${currentTl.nerdStats!.app}")
|
||||
], oldPlayerStat: oldTl?.nerdStats?.app, pos: widget.lbPositions?.app,
|
||||
averageStat: widget.averages?.nerdStats?.app),
|
||||
GaugetNum(playerStat: currentTl.nerdStats!.vsapm, playerStatLabel: "VS / APM", higherIsBetter: true, minimum: 1.8, maximum: 2.4, ranges: [
|
||||
GaugeRange(startValue: 1.8, endValue: 2.0, color: Colors.green),
|
||||
GaugeRange(startValue: 2.0, endValue: 2.2, color: Colors.blue),
|
||||
GaugeRange(startValue: 2.2, endValue: 2.4, color: Colors.purple),
|
||||
], alertWidgets: [
|
||||
Text(t.statCellNum.vsapmDescription),
|
||||
Text("${t.exactValue}: ${currentTl.nerdStats!.vsapm}")
|
||||
], oldPlayerStat: oldTl?.nerdStats?.vsapm, pos: widget.lbPositions?.vsapm,
|
||||
averageStat: widget.averages?.nerdStats?.vsapm)
|
||||
]),
|
||||
),
|
||||
Padding(
|
||||
padding: const EdgeInsets.fromLTRB(8, 0, 8, 0),
|
||||
child: Wrap(
|
||||
direction: Axis.horizontal,
|
||||
alignment: WrapAlignment.center,
|
||||
spacing: 25,
|
||||
crossAxisAlignment: WrapCrossAlignment.start,
|
||||
clipBehavior: Clip.hardEdge,
|
||||
children: [
|
||||
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),
|
||||
Text("${t.formula}: (VS / 100) - (APM / 60)"),
|
||||
Text("${t.exactValue}: ${currentTl.nerdStats!.dss}"),],
|
||||
okText: t.popupActions.ok,
|
||||
higherIsBetter: true,
|
||||
oldPlayerStat: oldTl?.nerdStats?.dss,),
|
||||
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),
|
||||
Text("${t.formula}: DS/S / PPS"),
|
||||
Text("${t.exactValue}: ${currentTl.nerdStats!.dsp}"),],
|
||||
okText: t.popupActions.ok,
|
||||
higherIsBetter: true,
|
||||
oldPlayerStat: oldTl?.nerdStats?.dsp,),
|
||||
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),
|
||||
Text("${t.formula}: APP + DS/P"),
|
||||
Text("${t.exactValue}: ${currentTl.nerdStats!.appdsp}"),],
|
||||
okText: t.popupActions.ok,
|
||||
higherIsBetter: true,
|
||||
oldPlayerStat: oldTl?.nerdStats?.appdsp,),
|
||||
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),
|
||||
Text("${t.formula}: (DS/P * 150) + ((VS/APM - 2) * 50) + (0.6 - APP) * 125"),
|
||||
Text("${t.exactValue}: ${currentTl.nerdStats!.cheese}"),],
|
||||
okText: t.popupActions.ok,
|
||||
higherIsBetter: false,
|
||||
oldPlayerStat: oldTl?.nerdStats?.cheese,),
|
||||
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),
|
||||
Text("${t.formula}: APP * DS/P * 2"),
|
||||
Text("${t.exactValue}: ${currentTl.nerdStats!.gbe}"),],
|
||||
okText: t.popupActions.ok,
|
||||
higherIsBetter: true,
|
||||
oldPlayerStat: oldTl?.nerdStats?.gbe,),
|
||||
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),
|
||||
Text("${t.formula}: APP - 5 * tan(radians((Cheese Index / -30) + 1))"),
|
||||
Text("${t.exactValue}: ${currentTl.nerdStats!.nyaapp}"),],
|
||||
okText: t.popupActions.ok,
|
||||
higherIsBetter: true,
|
||||
oldPlayerStat: oldTl?.nerdStats?.nyaapp,),
|
||||
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),
|
||||
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}"),],
|
||||
okText: t.popupActions.ok,
|
||||
higherIsBetter: true,
|
||||
oldPlayerStat: oldTl?.nerdStats?.area,)
|
||||
]),
|
||||
)
|
||||
],
|
||||
),
|
||||
if (currentTl.estTr != null)
|
||||
Padding(
|
||||
padding: const EdgeInsets.fromLTRB(0, 16, 0, 48),
|
||||
child: SizedBox(
|
||||
padding: const EdgeInsets.fromLTRB(0, 20, 0, 20),
|
||||
child: Container(
|
||||
//alignment: Alignment.center,
|
||||
width: bigScreen ? MediaQuery.of(context).size.width * 0.4 : MediaQuery.of(context).size.width * 0.85,
|
||||
child: Column(
|
||||
crossAxisAlignment: CrossAxisAlignment.start,
|
||||
height: 70,
|
||||
constraints: const BoxConstraints(maxWidth: 768),
|
||||
child: Stack(
|
||||
children: [
|
||||
Row(
|
||||
mainAxisAlignment: MainAxisAlignment.spaceBetween,
|
||||
children: [
|
||||
Text(
|
||||
"${bigScreen ? t.statCellNum.estOfTR : t.statCellNum.estOfTRShort}:",
|
||||
style: const TextStyle(fontSize: 24),
|
||||
),
|
||||
Text(
|
||||
f2.format(currentTl.estTr!.esttr),
|
||||
style: const TextStyle(fontSize: 24),
|
||||
),
|
||||
],
|
||||
),
|
||||
if (currentTl.rating >= 0)
|
||||
Row(
|
||||
mainAxisAlignment: MainAxisAlignment.spaceBetween,
|
||||
Positioned(
|
||||
left: 0,
|
||||
child: Column(
|
||||
crossAxisAlignment: CrossAxisAlignment.start,
|
||||
children: [
|
||||
Text(
|
||||
"${bigScreen ? t.statCellNum.accOfEst : t.statCellNum.accOfEstShort}:",
|
||||
style: const TextStyle(fontSize: 24),
|
||||
Text(t.statCellNum.estOfTR, style: const TextStyle(height: 0.1),),
|
||||
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))]
|
||||
),
|
||||
),
|
||||
Text(
|
||||
fDiff.format(currentTl.esttracc!),
|
||||
style: const TextStyle(fontSize: 24),
|
||||
RichText(text: TextSpan(
|
||||
text: "",
|
||||
style: const TextStyle(fontFamily: "Eurostile Round", fontSize: 14, color: Colors.grey, height: 0.5),
|
||||
children: [
|
||||
if (oldTl?.estTr?.esttr != null) TextSpan(text: comparef.format(currentTl.estTr!.esttr - oldTl!.estTr!.esttr), style: TextStyle(
|
||||
color: oldTl!.estTr!.esttr > currentTl.estTr!.esttr ? Colors.redAccent : Colors.greenAccent
|
||||
),),
|
||||
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)}")
|
||||
]
|
||||
),
|
||||
],
|
||||
),
|
||||
),
|
||||
],),
|
||||
),
|
||||
Positioned(
|
||||
right: 0,
|
||||
child: Column(
|
||||
crossAxisAlignment: CrossAxisAlignment.end,
|
||||
children: [
|
||||
Text(t.statCellNum.accOfEst, style: const TextStyle(height: 0.1),),
|
||||
RichText(
|
||||
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))
|
||||
]
|
||||
),
|
||||
),
|
||||
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!)
|
||||
]
|
||||
|
|
|
@ -91,6 +91,7 @@ class UserThingy extends StatelessWidget {
|
|||
? Image.asset("res/avatars/tetrio_banned.png", fit: BoxFit.fitHeight, height: pfpHeight,)
|
||||
: player.avatarRevision != null
|
||||
? 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) {
|
||||
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);
|
||||
|
@ -271,7 +272,7 @@ class UserThingy extends StatelessWidget {
|
|||
playerStatLabel: t.statCellNum.hoursPlayed,
|
||||
isScreenBig: bigScreen,
|
||||
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,),
|
||||
if (player.gamesPlayed >= 0)
|
||||
StatCellNum(
|
||||
|
@ -328,13 +329,29 @@ class UserThingy extends StatelessWidget {
|
|||
mainAxisAlignment: MainAxisAlignment.center,
|
||||
children: [
|
||||
Expanded(
|
||||
child: 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,
|
||||
)),
|
||||
child: RichText(
|
||||
textAlign: TextAlign.center,
|
||||
text: TextSpan(text: "", style: const TextStyle(
|
||||
fontFamily: "Eurostile Round",
|
||||
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
|
||||
description:
|
||||
name: _fe_analyzer_shared
|
||||
sha256: eb376e9acf6938204f90eb3b1f00b578640d3188b4c8a8ec054f9f479af8d051
|
||||
sha256: "0b2f2bd91ba804e53a61d757b986f89f1f9eaed5b11e4b2f5a2468d86d6c9fc7"
|
||||
url: "https://pub.dev"
|
||||
source: hosted
|
||||
version: "64.0.0"
|
||||
version: "67.0.0"
|
||||
analyzer:
|
||||
dependency: transitive
|
||||
description:
|
||||
name: analyzer
|
||||
sha256: "69f54f967773f6c26c7dcb13e93d7ccee8b17a641689da39e878d5cf13b06893"
|
||||
sha256: "37577842a27e4338429a1cbc32679d508836510b056f1eedf0c8d20e39c1383d"
|
||||
url: "https://pub.dev"
|
||||
source: hosted
|
||||
version: "6.2.0"
|
||||
version: "6.4.1"
|
||||
archive:
|
||||
dependency: transitive
|
||||
description:
|
||||
name: archive
|
||||
sha256: "7b875fd4a20b165a3084bd2d210439b22ebc653f21cea4842729c0c30c82596b"
|
||||
sha256: "22600aa1e926be775fa5fe7e6894e7fb3df9efda8891c73f70fb3262399a432d"
|
||||
url: "https://pub.dev"
|
||||
source: hosted
|
||||
version: "3.4.9"
|
||||
version: "3.4.10"
|
||||
args:
|
||||
dependency: transitive
|
||||
description:
|
||||
|
@ -141,10 +141,10 @@ packages:
|
|||
dependency: transitive
|
||||
description:
|
||||
name: dev_build
|
||||
sha256: e476ac99174842cdb01e64c1d379d041d2150f9ad2cdd2713eb1ca1bdbf30507
|
||||
sha256: e5d575f3de4b0e5f004e065e1e2d98fa012d634b61b5855216b5698ed7f1e443
|
||||
url: "https://pub.dev"
|
||||
source: hosted
|
||||
version: "0.16.3+2"
|
||||
version: "0.16.4+3"
|
||||
equatable:
|
||||
dependency: transitive
|
||||
description:
|
||||
|
@ -165,10 +165,10 @@ packages:
|
|||
dependency: transitive
|
||||
description:
|
||||
name: ffi
|
||||
sha256: "7bf0adc28a23d395f19f3f1eb21dd7cfd1dd9f8e1c50051c069122e6853bc878"
|
||||
sha256: "493f37e7df1804778ff3a53bd691d8692ddf69702cf4c1c1096a2e41b4779e21"
|
||||
url: "https://pub.dev"
|
||||
source: hosted
|
||||
version: "2.1.0"
|
||||
version: "2.1.2"
|
||||
file:
|
||||
dependency: transitive
|
||||
description:
|
||||
|
@ -181,34 +181,34 @@ packages:
|
|||
dependency: "direct main"
|
||||
description:
|
||||
name: file_picker
|
||||
sha256: "4e42aacde3b993c5947467ab640882c56947d9d27342a5b6f2895b23956954a6"
|
||||
sha256: "1bbf65dd997458a08b531042ec3794112a6c39c07c37ff22113d2e7e4f81d4e4"
|
||||
url: "https://pub.dev"
|
||||
source: hosted
|
||||
version: "6.1.1"
|
||||
version: "6.2.1"
|
||||
file_selector:
|
||||
dependency: "direct main"
|
||||
description:
|
||||
name: file_selector
|
||||
sha256: "84eaf3e034d647859167d1f01cfe7b6352488f34c1b4932635012b202014c25b"
|
||||
sha256: "5019692b593455127794d5718304ff1ae15447dea286cdda9f0db2a796a1b828"
|
||||
url: "https://pub.dev"
|
||||
source: hosted
|
||||
version: "1.0.1"
|
||||
version: "1.0.3"
|
||||
file_selector_android:
|
||||
dependency: transitive
|
||||
description:
|
||||
name: file_selector_android
|
||||
sha256: b7556052dbcc25ef88f6eba45ab98aa5600382af8dfdabc9d644a93d97b7be7f
|
||||
sha256: "1cd66575f063b689e041aec836905ba7be18d76c9f0634d0d75daec825f67095"
|
||||
url: "https://pub.dev"
|
||||
source: hosted
|
||||
version: "0.5.0+4"
|
||||
version: "0.5.0+7"
|
||||
file_selector_ios:
|
||||
dependency: transitive
|
||||
description:
|
||||
name: file_selector_ios
|
||||
sha256: "2f48db7e338b2255101c35c604b7ca5ab588dce032db7fc418a2fe5f28da63f8"
|
||||
sha256: b015154e6d9fddbc4d08916794df170b44531798c8dd709a026df162d07ad81d
|
||||
url: "https://pub.dev"
|
||||
source: hosted
|
||||
version: "0.5.1+7"
|
||||
version: "0.5.1+8"
|
||||
file_selector_linux:
|
||||
dependency: transitive
|
||||
description:
|
||||
|
@ -229,10 +229,10 @@ packages:
|
|||
dependency: transitive
|
||||
description:
|
||||
name: file_selector_platform_interface
|
||||
sha256: "0aa47a725c346825a2bd396343ce63ac00bda6eff2fbc43eabe99737dede8262"
|
||||
sha256: a3994c26f10378a039faa11de174d7b78eb8f79e4dd0af2a451410c1a5c3f66b
|
||||
url: "https://pub.dev"
|
||||
source: hosted
|
||||
version: "2.6.1"
|
||||
version: "2.6.2"
|
||||
file_selector_web:
|
||||
dependency: transitive
|
||||
description:
|
||||
|
@ -253,10 +253,10 @@ packages:
|
|||
dependency: "direct main"
|
||||
description:
|
||||
name: fl_chart
|
||||
sha256: fe6fec7d85975a99c73b9515a69a6e291364accfa0e4a5b3ce6de814d74b9a1c
|
||||
sha256: "00b74ae680df6b1135bdbea00a7d1fc072a9180b7c3f3702e4b19a9943f5ed7d"
|
||||
url: "https://pub.dev"
|
||||
source: hosted
|
||||
version: "0.66.0"
|
||||
version: "0.66.2"
|
||||
flutter:
|
||||
dependency: "direct main"
|
||||
description: flutter
|
||||
|
@ -295,10 +295,10 @@ packages:
|
|||
dependency: "direct main"
|
||||
description:
|
||||
name: flutter_markdown
|
||||
sha256: "35108526a233cc0755664d445f8a6b4b61e6f8fe993b3658b80b4a26827fc196"
|
||||
sha256: "87e11b9df25a42e2db315b8b7a51fae8e66f57a4b2f50ec4b822d0fa155e6b52"
|
||||
url: "https://pub.dev"
|
||||
source: hosted
|
||||
version: "0.6.18+2"
|
||||
version: "0.6.22"
|
||||
flutter_plugin_android_lifecycle:
|
||||
dependency: transitive
|
||||
description:
|
||||
|
@ -311,10 +311,10 @@ packages:
|
|||
dependency: "direct main"
|
||||
description:
|
||||
name: flutter_svg
|
||||
sha256: d39e7f95621fc84376bc0f7d504f05c3a41488c562f4a8ad410569127507402c
|
||||
sha256: "7b4ca6cf3304575fe9c8ec64813c8d02ee41d2afe60bcfe0678bcb5375d596a2"
|
||||
url: "https://pub.dev"
|
||||
source: hosted
|
||||
version: "2.0.9"
|
||||
version: "2.0.10+1"
|
||||
flutter_test:
|
||||
dependency: "direct dev"
|
||||
description: flutter
|
||||
|
@ -345,18 +345,18 @@ packages:
|
|||
dependency: "direct main"
|
||||
description:
|
||||
name: go_router
|
||||
sha256: ca7e4a2249f96773152f1853fa25933ac752495cdd7fdf5dafb9691bd05830fd
|
||||
sha256: "7ecb2f391edbca5473db591b48555a8912dde60edd0fb3013bd6743033b2d3f8"
|
||||
url: "https://pub.dev"
|
||||
source: hosted
|
||||
version: "13.0.0"
|
||||
version: "13.2.1"
|
||||
http:
|
||||
dependency: "direct main"
|
||||
description:
|
||||
name: http
|
||||
sha256: d4872660c46d929f6b8a9ef4e7a7eff7e49bbf0c4ec3f385ee32df5119175139
|
||||
sha256: a2bbf9d017fcced29139daa8ed2bba4ece450ab222871df93ca9eec6f80c34ba
|
||||
url: "https://pub.dev"
|
||||
source: hosted
|
||||
version: "1.1.2"
|
||||
version: "1.2.0"
|
||||
http_multi_server:
|
||||
dependency: transitive
|
||||
description:
|
||||
|
@ -377,10 +377,10 @@ packages:
|
|||
dependency: transitive
|
||||
description:
|
||||
name: image
|
||||
sha256: "028f61960d56f26414eb616b48b04eb37d700cbe477b7fb09bf1d7ce57fd9271"
|
||||
sha256: "4c68bfd5ae83e700b5204c1e74451e7bf3cf750e6843c6e158289cf56bda018e"
|
||||
url: "https://pub.dev"
|
||||
source: hosted
|
||||
version: "4.1.3"
|
||||
version: "4.1.7"
|
||||
intl:
|
||||
dependency: "direct main"
|
||||
description:
|
||||
|
@ -421,6 +421,30 @@ packages:
|
|||
url: "https://pub.dev"
|
||||
source: hosted
|
||||
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:
|
||||
dependency: transitive
|
||||
description:
|
||||
|
@ -441,34 +465,34 @@ packages:
|
|||
dependency: transitive
|
||||
description:
|
||||
name: markdown
|
||||
sha256: acf35edccc0463a9d7384e437c015a3535772e09714cf60e07eeef3a15870dcd
|
||||
sha256: ef2a1298144e3f985cc736b22e0ccdaf188b5b3970648f2d9dc13efd1d9df051
|
||||
url: "https://pub.dev"
|
||||
source: hosted
|
||||
version: "7.1.1"
|
||||
version: "7.2.2"
|
||||
matcher:
|
||||
dependency: transitive
|
||||
description:
|
||||
name: matcher
|
||||
sha256: "1803e76e6653768d64ed8ff2e1e67bea3ad4b923eb5c56a295c3e634bad5960e"
|
||||
sha256: d2323aa2060500f906aa31a895b4030b6da3ebdcc5619d14ce1aada65cd161cb
|
||||
url: "https://pub.dev"
|
||||
source: hosted
|
||||
version: "0.12.16"
|
||||
version: "0.12.16+1"
|
||||
material_color_utilities:
|
||||
dependency: transitive
|
||||
description:
|
||||
name: material_color_utilities
|
||||
sha256: "9528f2f296073ff54cb9fee677df673ace1218163c3bc7628093e7eed5203d41"
|
||||
sha256: "0e0a020085b65b6083975e499759762399b4475f766c21668c4ecca34ea74e5a"
|
||||
url: "https://pub.dev"
|
||||
source: hosted
|
||||
version: "0.5.0"
|
||||
version: "0.8.0"
|
||||
meta:
|
||||
dependency: transitive
|
||||
description:
|
||||
name: meta
|
||||
sha256: a6e590c838b18133bb482a2745ad77c5bb7715fb0451209e1a7567d416678b8e
|
||||
sha256: d584fa6707a52763a52446f02cc621b077888fb63b93bbcb1143a7be5a0c0c04
|
||||
url: "https://pub.dev"
|
||||
source: hosted
|
||||
version: "1.10.0"
|
||||
version: "1.11.0"
|
||||
mime:
|
||||
dependency: transitive
|
||||
description:
|
||||
|
@ -513,10 +537,10 @@ packages:
|
|||
dependency: "direct main"
|
||||
description:
|
||||
name: path
|
||||
sha256: "8829d8a55c13fc0e37127c29fedf290c102f4e40ae94ada574091fe0ff96c917"
|
||||
sha256: "087ce49c3f0dc39180befefc60fdb4acd8f8620e5682fe2476afd0b3688bb4af"
|
||||
url: "https://pub.dev"
|
||||
source: hosted
|
||||
version: "1.8.3"
|
||||
version: "1.9.0"
|
||||
path_parsing:
|
||||
dependency: transitive
|
||||
description:
|
||||
|
@ -529,26 +553,26 @@ packages:
|
|||
dependency: "direct main"
|
||||
description:
|
||||
name: path_provider
|
||||
sha256: a1aa8aaa2542a6bc57e381f132af822420216c80d4781f7aa085ca3229208aaa
|
||||
sha256: b27217933eeeba8ff24845c34003b003b2b22151de3c908d0e679e8fe1aa078b
|
||||
url: "https://pub.dev"
|
||||
source: hosted
|
||||
version: "2.1.1"
|
||||
version: "2.1.2"
|
||||
path_provider_android:
|
||||
dependency: transitive
|
||||
description:
|
||||
name: path_provider_android
|
||||
sha256: e595b98692943b4881b219f0a9e3945118d3c16bd7e2813f98ec6e532d905f72
|
||||
sha256: "477184d672607c0a3bf68fbbf601805f92ef79c82b64b4d6eb318cbca4c48668"
|
||||
url: "https://pub.dev"
|
||||
source: hosted
|
||||
version: "2.2.1"
|
||||
version: "2.2.2"
|
||||
path_provider_foundation:
|
||||
dependency: transitive
|
||||
description:
|
||||
name: path_provider_foundation
|
||||
sha256: "19314d595120f82aca0ba62787d58dde2cc6b5df7d2f0daf72489e38d1b57f2d"
|
||||
sha256: "5a7999be66e000916500be4f15a3633ebceb8302719b47b9cc49ce924125350f"
|
||||
url: "https://pub.dev"
|
||||
source: hosted
|
||||
version: "2.3.1"
|
||||
version: "2.3.2"
|
||||
path_provider_linux:
|
||||
dependency: transitive
|
||||
description:
|
||||
|
@ -561,10 +585,10 @@ packages:
|
|||
dependency: transitive
|
||||
description:
|
||||
name: path_provider_platform_interface
|
||||
sha256: "94b1e0dd80970c1ce43d5d4e050a9918fce4f4a775e6142424c30a29a363265c"
|
||||
sha256: "88f5779f72ba699763fa3a3b06aa4bf6de76c8e5de842cf6f29e2e06476c2334"
|
||||
url: "https://pub.dev"
|
||||
source: hosted
|
||||
version: "2.1.1"
|
||||
version: "2.1.2"
|
||||
path_provider_windows:
|
||||
dependency: transitive
|
||||
description:
|
||||
|
@ -585,26 +609,26 @@ packages:
|
|||
dependency: transitive
|
||||
description:
|
||||
name: platform
|
||||
sha256: "0a279f0707af40c890e80b1e9df8bb761694c074ba7e1d4ab1bc4b728e200b59"
|
||||
sha256: "12220bb4b65720483f8fa9450b4332347737cf8213dd2840d8b2c823e47243ec"
|
||||
url: "https://pub.dev"
|
||||
source: hosted
|
||||
version: "3.1.3"
|
||||
version: "3.1.4"
|
||||
plugin_platform_interface:
|
||||
dependency: transitive
|
||||
description:
|
||||
name: plugin_platform_interface
|
||||
sha256: f4f88d4a900933e7267e2b353594774fc0d07fb072b47eedcd5b54e1ea3269f8
|
||||
sha256: "4820fbfdb9478b1ebae27888254d445073732dae3d6ea81f0b7e06d5dedc3f02"
|
||||
url: "https://pub.dev"
|
||||
source: hosted
|
||||
version: "2.1.7"
|
||||
version: "2.1.8"
|
||||
pointycastle:
|
||||
dependency: transitive
|
||||
description:
|
||||
name: pointycastle
|
||||
sha256: "7c1e5f0d23c9016c5bbd8b1473d0d3fb3fc851b876046039509e18e0c7485f2c"
|
||||
sha256: "43ac87de6e10afabc85c445745a7b799e04de84cebaa4fd7bf55a5e1e9604d29"
|
||||
url: "https://pub.dev"
|
||||
source: hosted
|
||||
version: "3.7.3"
|
||||
version: "3.7.4"
|
||||
pool:
|
||||
dependency: transitive
|
||||
description:
|
||||
|
@ -617,10 +641,10 @@ packages:
|
|||
dependency: transitive
|
||||
description:
|
||||
name: process_run
|
||||
sha256: "3d5335d17003a7c2fd5148be2d313f5b84244ab2e625162fdd44b4aaa48bea66"
|
||||
sha256: "8d9c6198b98fbbfb511edd42e7364e24d85c163e47398919871b952dc86a423e"
|
||||
url: "https://pub.dev"
|
||||
source: hosted
|
||||
version: "0.13.3+1"
|
||||
version: "0.14.2"
|
||||
pub_semver:
|
||||
dependency: transitive
|
||||
description:
|
||||
|
@ -657,10 +681,10 @@ packages:
|
|||
dependency: transitive
|
||||
description:
|
||||
name: shared_preferences_foundation
|
||||
sha256: "7bf53a9f2d007329ee6f3df7268fd498f8373602f943c975598bbb34649b62a7"
|
||||
sha256: "7708d83064f38060c7b39db12aefe449cb8cdc031d6062280087bc4cdb988f5c"
|
||||
url: "https://pub.dev"
|
||||
source: hosted
|
||||
version: "2.3.4"
|
||||
version: "2.3.5"
|
||||
shared_preferences_linux:
|
||||
dependency: transitive
|
||||
description:
|
||||
|
@ -673,10 +697,10 @@ packages:
|
|||
dependency: transitive
|
||||
description:
|
||||
name: shared_preferences_platform_interface
|
||||
sha256: d4ec5fc9ebb2f2e056c617112aa75dcf92fc2e4faaf2ae999caa297473f75d8a
|
||||
sha256: "22e2ecac9419b4246d7c22bfbbda589e3acf5c0351137d87dd2939d984d37c3b"
|
||||
url: "https://pub.dev"
|
||||
source: hosted
|
||||
version: "2.3.1"
|
||||
version: "2.3.2"
|
||||
shared_preferences_web:
|
||||
dependency: transitive
|
||||
description:
|
||||
|
@ -734,18 +758,18 @@ packages:
|
|||
dependency: "direct main"
|
||||
description:
|
||||
name: slang
|
||||
sha256: "77fd99f7b0da15e671ef0289b24a0a63e74f693c58a0ca54111388e4c0ddb1dd"
|
||||
sha256: "5e08ac915ac27a3508863f37734280d30c3713d56746cd2e4a5da77413da4b95"
|
||||
url: "https://pub.dev"
|
||||
source: hosted
|
||||
version: "3.28.0"
|
||||
version: "3.30.1"
|
||||
slang_flutter:
|
||||
dependency: "direct main"
|
||||
description:
|
||||
name: slang_flutter
|
||||
sha256: "57817bb15553bb5df37aed3bac497286bdd8c2eab6763f4de6815efe2c0becee"
|
||||
sha256: "9ee040b0d364d3a4d692e4af536acff6ef513870689403494ebc6d59b0dccea6"
|
||||
url: "https://pub.dev"
|
||||
source: hosted
|
||||
version: "3.28.0"
|
||||
version: "3.30.0"
|
||||
source_map_stack_trace:
|
||||
dependency: transitive
|
||||
description:
|
||||
|
@ -774,50 +798,50 @@ packages:
|
|||
dependency: "direct main"
|
||||
description:
|
||||
name: sqflite
|
||||
sha256: "591f1602816e9c31377d5f008c2d9ef7b8aca8941c3f89cc5fd9d84da0c38a9a"
|
||||
sha256: a9016f495c927cb90557c909ff26a6d92d9bd54fc42ba92e19d4e79d61e798c6
|
||||
url: "https://pub.dev"
|
||||
source: hosted
|
||||
version: "2.3.0"
|
||||
version: "2.3.2"
|
||||
sqflite_common:
|
||||
dependency: transitive
|
||||
description:
|
||||
name: sqflite_common
|
||||
sha256: bb4738f15b23352822f4c42a531677e5c6f522e079461fd240ead29d8d8a54a6
|
||||
sha256: "3da423ce7baf868be70e2c0976c28a1bb2f73644268b7ffa7d2e08eab71f16a4"
|
||||
url: "https://pub.dev"
|
||||
source: hosted
|
||||
version: "2.5.0+2"
|
||||
version: "2.5.4"
|
||||
sqflite_common_ffi:
|
||||
dependency: "direct main"
|
||||
description:
|
||||
name: sqflite_common_ffi
|
||||
sha256: "873677ee78738a723d1ded4ccb23980581998d873d30ee9c331f6a81748663ff"
|
||||
sha256: "4d6137c29e930d6e4a8ff373989dd9de7bac12e3bc87bce950f6e844e8ad3bb5"
|
||||
url: "https://pub.dev"
|
||||
source: hosted
|
||||
version: "2.3.1"
|
||||
version: "2.3.3"
|
||||
sqflite_common_ffi_web:
|
||||
dependency: "direct main"
|
||||
description:
|
||||
name: sqflite_common_ffi_web
|
||||
sha256: "3d4b550a09fda9eb0a9ce3bd98c8080f57b2cc1f4b19e844290e82843e73b63d"
|
||||
sha256: "0c2921454d2e4a227675fb952be9fef916cf65fb9e9b606b54cfdf080d3e9450"
|
||||
url: "https://pub.dev"
|
||||
source: hosted
|
||||
version: "0.4.2+2"
|
||||
version: "0.4.2+3"
|
||||
sqlite3:
|
||||
dependency: transitive
|
||||
description:
|
||||
name: sqlite3
|
||||
sha256: c4a4c5a4b2a32e2d0f6837b33d7c91a67903891a5b7dbe706cf4b1f6b0c798c5
|
||||
sha256: "072128763f1547e3e9b4735ce846bfd226d68019ccda54db4cd427b12dfdedc9"
|
||||
url: "https://pub.dev"
|
||||
source: hosted
|
||||
version: "2.3.0"
|
||||
version: "2.4.0"
|
||||
sqlite3_flutter_libs:
|
||||
dependency: "direct main"
|
||||
description:
|
||||
name: sqlite3_flutter_libs
|
||||
sha256: "3e3583b77cf888a68eae2e49ee4f025f66b86623ef0d83c297c8d903daa14871"
|
||||
sha256: d6c31c8511c441d1f12f20b607343df1afe4eddf24a1cf85021677c8eea26060
|
||||
url: "https://pub.dev"
|
||||
source: hosted
|
||||
version: "0.5.18"
|
||||
version: "0.5.20"
|
||||
stack_trace:
|
||||
dependency: transitive
|
||||
description:
|
||||
|
@ -846,18 +870,18 @@ packages:
|
|||
dependency: transitive
|
||||
description:
|
||||
name: syncfusion_flutter_core
|
||||
sha256: "69c827931957d5b121ee9f0b9b0b8d7d0d1ac537b61bcdd5c3fbffc044bbe86e"
|
||||
sha256: "7666506885ebc8f62bb928ad4588a73e20caaff2b2cf2b2b56f67d98f4113525"
|
||||
url: "https://pub.dev"
|
||||
source: hosted
|
||||
version: "24.1.41"
|
||||
version: "24.2.9"
|
||||
syncfusion_flutter_gauges:
|
||||
dependency: "direct main"
|
||||
description:
|
||||
name: syncfusion_flutter_gauges
|
||||
sha256: "78515dcfbed952c36ab9ca4a1e6c99737beb7c6cf2312efe8beca2bd314a3955"
|
||||
sha256: "87be13e520fc1676a725691446f411f549ea5b6ff2580234db0479799f213757"
|
||||
url: "https://pub.dev"
|
||||
source: hosted
|
||||
version: "24.1.41"
|
||||
version: "24.2.9"
|
||||
synchronized:
|
||||
dependency: transitive
|
||||
description:
|
||||
|
@ -910,26 +934,26 @@ packages:
|
|||
dependency: "direct main"
|
||||
description:
|
||||
name: url_launcher
|
||||
sha256: e9aa5ea75c84cf46b3db4eea212523591211c3cf2e13099ee4ec147f54201c86
|
||||
sha256: "0ecc004c62fd3ed36a2ffcbe0dd9700aee63bd7532d0b642a488b1ec310f492e"
|
||||
url: "https://pub.dev"
|
||||
source: hosted
|
||||
version: "6.2.2"
|
||||
version: "6.2.5"
|
||||
url_launcher_android:
|
||||
dependency: transitive
|
||||
description:
|
||||
name: url_launcher_android
|
||||
sha256: "31222ffb0063171b526d3e569079cf1f8b294075ba323443fdc690842bfd4def"
|
||||
sha256: d4ed0711849dd8e33eb2dd69c25db0d0d3fdc37e0a62e629fe32f57a22db2745
|
||||
url: "https://pub.dev"
|
||||
source: hosted
|
||||
version: "6.2.0"
|
||||
version: "6.3.0"
|
||||
url_launcher_ios:
|
||||
dependency: transitive
|
||||
description:
|
||||
name: url_launcher_ios
|
||||
sha256: bba3373219b7abb6b5e0d071b0fe66dfbe005d07517a68e38d4fc3638f35c6d3
|
||||
sha256: "9149d493b075ed740901f3ee844a38a00b33116c7c5c10d7fb27df8987fb51d5"
|
||||
url: "https://pub.dev"
|
||||
source: hosted
|
||||
version: "6.2.1"
|
||||
version: "6.2.5"
|
||||
url_launcher_linux:
|
||||
dependency: transitive
|
||||
description:
|
||||
|
@ -950,18 +974,18 @@ packages:
|
|||
dependency: transitive
|
||||
description:
|
||||
name: url_launcher_platform_interface
|
||||
sha256: "980e8d9af422f477be6948bdfb68df8433be71f5743a188968b0c1b887807e50"
|
||||
sha256: "552f8a1e663569be95a8190206a38187b531910283c3e982193e4f2733f01029"
|
||||
url: "https://pub.dev"
|
||||
source: hosted
|
||||
version: "2.2.0"
|
||||
version: "2.3.2"
|
||||
url_launcher_web:
|
||||
dependency: transitive
|
||||
description:
|
||||
name: url_launcher_web
|
||||
sha256: "7286aec002c8feecc338cc33269e96b73955ab227456e9fb2a91f7fab8a358e9"
|
||||
sha256: fff0932192afeedf63cdd50ecbb1bc825d31aed259f02bb8dba0f3b729a5e88b
|
||||
url: "https://pub.dev"
|
||||
source: hosted
|
||||
version: "2.2.2"
|
||||
version: "2.2.3"
|
||||
url_launcher_windows:
|
||||
dependency: transitive
|
||||
description:
|
||||
|
@ -974,26 +998,26 @@ packages:
|
|||
dependency: transitive
|
||||
description:
|
||||
name: vector_graphics
|
||||
sha256: "0f0c746dd2d6254a0057218ff980fc7f5670fd0fcf5e4db38a490d31eed4ad43"
|
||||
sha256: "32c3c684e02f9bc0afb0ae0aa653337a2fe022e8ab064bcd7ffda27a74e288e3"
|
||||
url: "https://pub.dev"
|
||||
source: hosted
|
||||
version: "1.1.9+1"
|
||||
version: "1.1.11+1"
|
||||
vector_graphics_codec:
|
||||
dependency: transitive
|
||||
description:
|
||||
name: vector_graphics_codec
|
||||
sha256: "0edf6d630d1bfd5589114138ed8fada3234deacc37966bec033d3047c29248b7"
|
||||
sha256: c86987475f162fadff579e7320c7ddda04cd2fdeffbe1129227a85d9ac9e03da
|
||||
url: "https://pub.dev"
|
||||
source: hosted
|
||||
version: "1.1.9+1"
|
||||
version: "1.1.11+1"
|
||||
vector_graphics_compiler:
|
||||
dependency: transitive
|
||||
description:
|
||||
name: vector_graphics_compiler
|
||||
sha256: d24333727332d9bd20990f1483af4e09abdb9b1fc7c3db940b56ab5c42790c26
|
||||
sha256: "12faff3f73b1741a36ca7e31b292ddeb629af819ca9efe9953b70bd63fc8cd81"
|
||||
url: "https://pub.dev"
|
||||
source: hosted
|
||||
version: "1.1.9+1"
|
||||
version: "1.1.11+1"
|
||||
vector_math:
|
||||
dependency: "direct main"
|
||||
description:
|
||||
|
@ -1022,18 +1046,18 @@ packages:
|
|||
dependency: transitive
|
||||
description:
|
||||
name: web
|
||||
sha256: afe077240a270dcfd2aafe77602b4113645af95d0ad31128cc02bce5ac5d5152
|
||||
sha256: "4188706108906f002b3a293509234588823c8c979dc83304e229ff400c996b05"
|
||||
url: "https://pub.dev"
|
||||
source: hosted
|
||||
version: "0.3.0"
|
||||
version: "0.4.2"
|
||||
web_socket_channel:
|
||||
dependency: transitive
|
||||
description:
|
||||
name: web_socket_channel
|
||||
sha256: d88238e5eac9a42bb43ca4e721edba3c08c6354d4a53063afaa568516217621b
|
||||
sha256: "939ab60734a4f8fa95feacb55804fa278de28bdeef38e616dc08e44a84adea23"
|
||||
url: "https://pub.dev"
|
||||
source: hosted
|
||||
version: "2.4.0"
|
||||
version: "2.4.3"
|
||||
webkit_inspection_protocol:
|
||||
dependency: transitive
|
||||
description:
|
||||
|
@ -1046,26 +1070,26 @@ packages:
|
|||
dependency: transitive
|
||||
description:
|
||||
name: win32
|
||||
sha256: b0f37db61ba2f2e9b7a78a1caece0052564d1bc70668156cf3a29d676fe4e574
|
||||
sha256: "8cb58b45c47dcb42ab3651533626161d6b67a2921917d8d429791f76972b3480"
|
||||
url: "https://pub.dev"
|
||||
source: hosted
|
||||
version: "5.1.1"
|
||||
version: "5.3.0"
|
||||
window_manager:
|
||||
dependency: "direct main"
|
||||
description:
|
||||
name: window_manager
|
||||
sha256: dcc865277f26a7dad263a47d0e405d77e21f12cb71f30333a52710a408690bd7
|
||||
sha256: b3c895bdf936c77b83c5254bec2e6b3f066710c1f89c38b20b8acc382b525494
|
||||
url: "https://pub.dev"
|
||||
source: hosted
|
||||
version: "0.3.7"
|
||||
version: "0.3.8"
|
||||
xdg_directories:
|
||||
dependency: transitive
|
||||
description:
|
||||
name: xdg_directories
|
||||
sha256: "589ada45ba9e39405c198fe34eb0f607cddb2108527e658136120892beac46d2"
|
||||
sha256: faea9dee56b520b55a566385b84f2e8de55e7496104adada9962e0bd11bcff1d
|
||||
url: "https://pub.dev"
|
||||
source: hosted
|
||||
version: "1.0.3"
|
||||
version: "1.0.4"
|
||||
xml:
|
||||
dependency: transitive
|
||||
description:
|
||||
|
@ -1083,5 +1107,5 @@ packages:
|
|||
source: hosted
|
||||
version: "3.1.2"
|
||||
sdks:
|
||||
dart: ">=3.2.0 <4.0.0"
|
||||
flutter: ">=3.16.0"
|
||||
dart: ">=3.3.0 <4.0.0"
|
||||
flutter: ">=3.19.0"
|
||||
|
|
|
@ -2,7 +2,7 @@ name: tetra_stats
|
|||
description: Track your and other player stats in TETR.IO
|
||||
publish_to: 'none'
|
||||
|
||||
version: 1.4.1+15
|
||||
version: 1.5.0+16
|
||||
|
||||
environment:
|
||||
sdk: '>=3.0.0'
|
||||
|
|
|
@ -46,6 +46,14 @@
|
|||
"stoppedBeingTracked": "Removed from tracking list!",
|
||||
"tlLeaderboard": "Tetra League leaderboard",
|
||||
"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",
|
||||
"botRecord": "Bots are not allowed to set records",
|
||||
"anonRecord": "Guests are not allowed to set records",
|
||||
|
@ -69,7 +77,10 @@
|
|||
"supporter": "Supporter tier ${tier}",
|
||||
"comparingWith": "Data from ${newDate} comparing with ${oldDate}",
|
||||
"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",
|
||||
"nerdStats": "Nerd Stats",
|
||||
"playersYouTrack": "Players you track",
|
||||
|
@ -93,8 +104,14 @@
|
|||
"yourIDAlertTitle": "Your nickname in TETR.IO",
|
||||
"yourIDText": "When app loads, it will retrieve data for this account",
|
||||
"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",
|
||||
"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}",
|
||||
"statesViewTitle": "${number} states of ${nickname} account",
|
||||
"matchesViewTitle": "${nickname} TL matches",
|
||||
|
@ -119,10 +136,14 @@
|
|||
"openReplay": "Open replay in TETR.IO",
|
||||
"replaySaved": "Replay saved to ${path}",
|
||||
"match": "Match",
|
||||
"timeWeightedmatch": "Match (time-weighted)",
|
||||
"roundNumber": "Round $n",
|
||||
"statsFor": "Stats for",
|
||||
"numberOfRounds": "Number of rounds",
|
||||
"matchLength": "Match Length",
|
||||
"roundLength": "Round Length",
|
||||
"matchStats": "Match stats",
|
||||
"timeWeightedmatchStats": "Time-weighted match stats",
|
||||
"replayIssue": "Can't process replay",
|
||||
"matchIsTooOld": "Replay is not available",
|
||||
"winner": "Winner",
|
||||
|
@ -159,6 +180,15 @@
|
|||
"many": "$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",
|
||||
"entries": "Entries",
|
||||
"minimums": "Minimums",
|
||||
|
@ -238,8 +268,30 @@
|
|||
"numOfGameActions":{
|
||||
"pc": "All Clears",
|
||||
"hold": "Holds",
|
||||
"tspinsTotal": "T-spins total",
|
||||
"lineClears": "Line clears"
|
||||
"inputs": {
|
||||
"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":{
|
||||
"cancel": "Cancel",
|
||||
|
@ -249,21 +301,30 @@
|
|||
"errors":{
|
||||
"connection": "Some issue with connection: ${code} ${message}",
|
||||
"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",
|
||||
"actionSuggestion": "Perhaps, you want to",
|
||||
"p1nkl0bst3rTLmatches": "No Tetra League matches was found",
|
||||
"clientException": "No internet connection",
|
||||
"forbidden": "Your IP address is blocked.\nChange IP address or reach out to osk",
|
||||
"tooManyRequests": "You have been rate limited. Try again later",
|
||||
"forbidden": "Your IP address is blocked",
|
||||
"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",
|
||||
"internalSub": "osk, probably, already aware about it",
|
||||
"internalWebVersion": "Something happend on the tetr.io side (or on oskware_bridge, idk honestly)",
|
||||
"oskwareBridge": "Something happend with oskware_bridge. Let dan63047 know",
|
||||
"p1nkl0bst3rForbidden": "Third party API blocked your IP address.\nChange IP address or reach out to p1nkl0bst3r",
|
||||
"internalWebVersionSub": "If osk status page says that everything is ok, let dan63047 know about this issue",
|
||||
"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",
|
||||
"p1nkl0bst3rinternal": "Something happend on the p1nkl0bst3r side",
|
||||
"p1nkl0bst3rinternalWebVersion": "Something happend on the p1nkl0bst3r side (or on oskware_bridge, idk honestly)",
|
||||
"replayAlreadySaved": "Replay already saved",
|
||||
"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)": {
|
||||
"": "Not selected",
|
||||
|
|
|
@ -46,6 +46,14 @@
|
|||
"compare": "Сравнить",
|
||||
"tlLeaderboard": "Рейтинговая таблица",
|
||||
"noRecords": "Нет записей",
|
||||
"noOldRecords": {
|
||||
"zero": "Нет записей",
|
||||
"one": "Всего один матч",
|
||||
"two": "Всего $n матча",
|
||||
"few": "Всего $n матча",
|
||||
"many": "Всего $n матчей",
|
||||
"other": "$n матчей"
|
||||
},
|
||||
"noRecord": "Нет рекорда",
|
||||
"botRecord": "Ботам нельзя ставить рекорды",
|
||||
"anonRecord": "Гостям нельзя ставить рекорды",
|
||||
|
@ -69,7 +77,10 @@
|
|||
"assignedManualy": "Этот значок был присвоен вручную администрацией TETR.IO",
|
||||
"comparingWith": "Данные от ${newDate} в сравнении с данными от ${oldDate}",
|
||||
"top": "Топ",
|
||||
"topRank": "Топ Ранг",
|
||||
"topRank": "Топ ранг",
|
||||
"verdictGeneral": "$verdict среднего $rank ранга на $n",
|
||||
"verdictBetter": "Лучше",
|
||||
"verdictWorse": "Хуже",
|
||||
"gamesUntilRanked": "${left} матчей до получения рейтинга",
|
||||
"nerdStats": "Для задротов",
|
||||
"playersYouTrack": "Отслеживаемые игроки",
|
||||
|
@ -93,8 +104,14 @@
|
|||
"yourIDAlertTitle": "Ваш ник в TETR.IO",
|
||||
"yourIDText": "При запуске приложения оно будет получать статистику этого игрока.",
|
||||
"language": "Язык (Language)",
|
||||
"customization": "Кастомизация",
|
||||
"customizationDescription": "Здесь только один переключатель, в планах добавить больше",
|
||||
"lbStats": "Показывать статистику, основанную на рейтинговой таблице",
|
||||
"lbStatsDescription": "Это повлияет на время загрузки, но позволит видеть положение в рейтинге и сравнение со средними значениями по рангу по каждой стате",
|
||||
"aboutApp": "О приложении",
|
||||
"aboutAppText": "${appName} (${packageName}) Версия ${version} Сборка ${buildNumber}\n\nРазработал dan63047\nФормулы предоставил kerrmunism\nИсторию предоставляет p1nkl0bst3r\nВозможность скачивать повторы из TETR.IO предоставляет szy",
|
||||
"oskKagari": "\"Оск Кагари\" прикол",
|
||||
"oskKagariDescription": "Если включено, вместо настоящего ранга оска будет рендерится :kagari:",
|
||||
"stateViewTitle": "Аккаунт ${nickname} ${date}",
|
||||
"statesViewTitle": "${number} состояний аккаунта ${nickname}",
|
||||
"matchesViewTitle": "Матчи аккаунта ${nickname}",
|
||||
|
@ -119,10 +136,14 @@
|
|||
"openReplay": "Открыть повтор в TETR.IO",
|
||||
"replaySaved": "Повтор сохранён по пути ${path}",
|
||||
"match": "Матч",
|
||||
"timeWeightedmatch": "Матч (взвешенная по времени)",
|
||||
"roundNumber": "Раунд $n",
|
||||
"statsFor": "Статистика за",
|
||||
"numberOfRounds": "Количество раундов",
|
||||
"matchLength": "Продолжительность матча",
|
||||
"roundLength": "Продолжительность раунда",
|
||||
"matchStats": "Статистика матча",
|
||||
"timeWeightedmatchStats": "Взвешенная по времени cтатистика матча",
|
||||
"replayIssue": "Ошибка обработки повтора",
|
||||
"matchIsTooOld": "Информация о повторе недоступна",
|
||||
"winner": "Победитель",
|
||||
|
@ -159,6 +180,15 @@
|
|||
"many": "$n игроков",
|
||||
"other": "$n игроков"
|
||||
},
|
||||
"games": {
|
||||
"zero": "$n игр",
|
||||
"one": "$n игра",
|
||||
"two": "$n игры",
|
||||
"few": "$n игры",
|
||||
"many": "$n игр",
|
||||
"other": "$n игр"
|
||||
},
|
||||
"gamesPlayed": "$games сыграно",
|
||||
"chart": "График",
|
||||
"entries": "Список",
|
||||
"minimums": "Минимумы",
|
||||
|
@ -238,8 +268,30 @@
|
|||
"numOfGameActions":{
|
||||
"pc": "Все чисто",
|
||||
"hold": "В запас",
|
||||
"tspinsTotal": "T-spins всего",
|
||||
"lineClears": "Линий очищено"
|
||||
"inputs": {
|
||||
"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":{
|
||||
"cancel": "Отменить",
|
||||
|
@ -249,21 +301,30 @@
|
|||
"errors":{
|
||||
"connection": "Проблема с подключением: ${code} ${message}",
|
||||
"noSuchUser": "Нет такого пользователя",
|
||||
"noSuchUserSub": "Либо вы ошиблись при вводе, либо аккаунта больше не существует",
|
||||
"discordNotAssigned": "К данному Discord ID не привязан аккаунт",
|
||||
"discordNotAssignedSub": "Убедитесь в том, что вы вставили правильный ID",
|
||||
"history": "История данного игрока отсутствует",
|
||||
"actionSuggestion": "Возможно, вы хотите",
|
||||
"p1nkl0bst3rTLmatches": "Старых матчей Тетра Лиги не было найдено",
|
||||
"clientException": "Нет соединения с интернетом",
|
||||
"forbidden": "Ваш IP адрес заблокирован.\nСмените IP адрес или свяжитесь с osk-ом",
|
||||
"tooManyRequests": "Слишком много запросов. Попробуйте позже",
|
||||
"forbidden": "Ваш IP адрес заблокирован",
|
||||
"forbiddenSub": "Если у вас работает VPN или прокси, выключите его. Если это не помогло, свяжитесь с $nickname",
|
||||
"tooManyRequests": "Слишком много запросов",
|
||||
"tooManyRequestsSub": "Подождите немного и попробуйте снова",
|
||||
"internal": "Что-то случилось на стороне tetr.io",
|
||||
"internalSub": "Скорее всего, osk уже в курсе об этом",
|
||||
"internalWebVersion": "Что-то случилось на стороне tetr.io (или на стороне oskware_bridge, я хз если честно)",
|
||||
"oskwareBridge": "Что-то случилось с oskware_bridge. Дайте dan63047 знать",
|
||||
"p1nkl0bst3rForbidden": "Стороннее API заблокировало ваш IP адрес.\nСмените IP адрес или свяжитесь с p1nkl0bst3r-ом",
|
||||
"internalWebVersionSub": "Если статус страница osk-а говорит, что всё ок - свяжитесь с dan63047",
|
||||
"oskwareBridge": "Что-то случилось с oskware_bridge",
|
||||
"oskwareBridgeSub": "Дайте dan63047 знать",
|
||||
"p1nkl0bst3rForbidden": "Стороннее API заблокировало ваш IP адрес",
|
||||
"p1nkl0bst3rTooManyRequests": "Слишком много запросов к стороннему API. Попробуйте позже",
|
||||
"p1nkl0bst3rinternal": "Что-то случилось на стороне p1nkl0bst3r-а",
|
||||
"p1nkl0bst3rinternalWebVersion": "Что-то случилось на стороне p1nkl0bst3r-а (или на стороне oskware_bridge, я хз если честно)",
|
||||
"replayAlreadySaved": "Повтор уже сохранён",
|
||||
"replayExpired": "Повтор истёк и больше недоступен",
|
||||
"replayRejected": "Стороннее API заблокировало ваш IP адрес.\nСмените IP адрес или свяжитесь с szy"
|
||||
"replayRejected": "Стороннее API заблокировало ваш IP адрес"
|
||||
},
|
||||
"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:math';
|
||||
import 'dart:ui';
|
||||
import 'package:flutter/foundation.dart';
|
||||
import 'package:flutter/material.dart';
|
||||
|
|
|
@ -18,7 +18,7 @@
|
|||
|
||||
<meta charset="UTF-8">
|
||||
<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 -->
|
||||
<meta name="apple-mobile-web-app-capable" content="yes">
|
||||
|
|