This commit is contained in:
dan63047 2024-03-24 19:38:06 +03:00
parent 8ab4a4db35
commit 3b16822c1f
35 changed files with 1219 additions and 1105 deletions

View File

@ -16,6 +16,7 @@ You can [download an app](https://github.com/dan63047/TetraStats/releases), or [
- Stats Calculator - Stats Calculator
- Player history in charts - Player history in charts
- Tetra League matches history - Tetra League matches history
- Time-weighted stats in Tetra League matches
# Special thanks # Special thanks
- **kerrmunism** — formulas - **kerrmunism** — formulas

View File

@ -25,6 +25,12 @@ apply plugin: 'com.android.application'
apply plugin: 'kotlin-android' apply plugin: 'kotlin-android'
apply from: "$flutterRoot/packages/flutter_tools/gradle/flutter.gradle" apply from: "$flutterRoot/packages/flutter_tools/gradle/flutter.gradle"
def keystoreProperties = new Properties()
def keystorePropertiesFile = rootProject.file('key.properties')
if (keystorePropertiesFile.exists()) {
keystoreProperties.load(new FileInputStream(keystorePropertiesFile))
}
android { android {
compileSdkVersion flutter.compileSdkVersion compileSdkVersion flutter.compileSdkVersion
ndkVersion flutter.ndkVersion ndkVersion flutter.ndkVersion
@ -53,11 +59,17 @@ android {
versionName flutterVersionName versionName flutterVersionName
} }
signingConfigs {
release {
keyAlias keystoreProperties['keyAlias']
keyPassword keystoreProperties['keyPassword']
storeFile keystoreProperties['storeFile'] ? file(keystoreProperties['storeFile']) : null
storePassword keystoreProperties['storePassword']
}
}
buildTypes { buildTypes {
release { release {
// TODO: Add your own signing config for the release build. signingConfig signingConfigs.release
// Signing with the debug keys for now, so `flutter run --release` works.
signingConfig signingConfigs.debug
} }
} }
} }

View File

@ -1,12 +1,12 @@
//import 'dart:convert'; //import 'dart:convert';
import 'dart:io'; //import 'dart:io';
//import 'package:path_provider/path_provider.dart'; //import 'package:path_provider/path_provider.dart';
//import 'tetrio_multiplayer_replay.dart'; //import 'tetrio_multiplayer_replay.dart';
/// That thing allows me to test my new staff i'm trying to implement /// That thing allows me to test my new staff i'm trying to implement
void main() async { //void main() async {
// List<Tetromino> queue = List.from(tetrominoes); // List<Tetromino> queue = List.from(tetrominoes);
// TetrioRNG rng = TetrioRNG(0); // TetrioRNG rng = TetrioRNG(0);
// queue = rng.shuffleList(queue); // queue = rng.shuffleList(queue);
@ -21,5 +21,5 @@ void main() async {
// print(replay.rawJson); // print(replay.rawJson);
//print(""); //print("");
exit(0); // exit(0);
} //}

View File

@ -261,399 +261,399 @@ class ReplayData{
// can't belive i have to implement that difficult shit // can't belive i have to implement that difficult shit
List<Event> readEventList(Map<dynamic, dynamic> json){ // List<Event> readEventList(Map<dynamic, dynamic> json){
List<Event> events = []; // List<Event> events = [];
int id = 0; // int id = 0;
for (var event in json['data'][0]['replays'][0]['events']){ // for (var event in json['data'][0]['replays'][0]['events']){
int frame = event["frame"]; // int frame = event["frame"];
EventType type = EventType.values.byName(event['type']); // EventType type = EventType.values.byName(event['type']);
switch (type) { // switch (type) {
case EventType.start: // case EventType.start:
events.add(Event(id, frame, type)); // events.add(Event(id, frame, type));
break; // break;
case EventType.full: // case EventType.full:
events.add(EventFull(id, frame, type, DataFull.fromJson(event["data"]))); // events.add(EventFull(id, frame, type, DataFull.fromJson(event["data"])));
break; // break;
case EventType.targets: // case EventType.targets:
// TODO // // TODO
break; // break;
case EventType.keydown: // case EventType.keydown:
events.add(EventKeyPress(id, frame, type, // events.add(EventKeyPress(id, frame, type,
Keypress( // Keypress(
KeyType.values.byName(event['data']['key']), // KeyType.values.byName(event['data']['key']),
event['data']['subframe'], // event['data']['subframe'],
false) // false)
)); // ));
break; // break;
case EventType.keyup: // case EventType.keyup:
events.add(EventKeyPress(id, frame, type, // events.add(EventKeyPress(id, frame, type,
Keypress( // Keypress(
KeyType.values.byName(event['data']['key']), // KeyType.values.byName(event['data']['key']),
event['data']['subframe'], // event['data']['subframe'],
true) // true)
)); // ));
break; // break;
case EventType.end: // case EventType.end:
// TODO: Handle this case. // // TODO: Handle this case.
case EventType.ige: // case EventType.ige:
// TODO: Handle this case. // // TODO: Handle this case.
case EventType.exit: // case EventType.exit:
// TODO: Handle this case. // // TODO: Handle this case.
} // }
id++; // id++;
} // }
return []; // return [];
} // }
enum EventType // enum EventType
{ // {
start, // start,
end, // end,
full, // full,
keydown, // keydown,
keyup, // keyup,
targets, // targets,
ige, // ige,
exit // exit
} // }
enum KeyType // enum KeyType
{ // {
moveLeft, // moveLeft,
moveRight, // moveRight,
softDrop, // softDrop,
rotateCCW, // rotateCCW,
rotateCW, // rotateCW,
rotate180, // rotate180,
hardDrop, // hardDrop,
hold, // hold,
chat, // chat,
exit, // exit,
retry // retry
} // }
class Event{ // class Event{
int id; // int id;
int frame; // int frame;
EventType type; // EventType type;
//dynamic data; // //dynamic data;
Event(this.id, this.frame, this.type); // Event(this.id, this.frame, this.type);
@override // @override
String toString(){ // String toString(){
return "E#$id f#$frame: $type"; // return "E#$id f#$frame: $type";
} // }
} // }
class Keypress{ // class Keypress{
KeyType key; // KeyType key;
double subframe; // double subframe;
bool released; // bool released;
Keypress(this.key, this.subframe, this.released); // Keypress(this.key, this.subframe, this.released);
} // }
class EventKeyPress extends Event{ // class EventKeyPress extends Event{
Keypress data; // Keypress data;
EventKeyPress(super.id, super.frame, super.type, this.data); // EventKeyPress(super.id, super.frame, super.type, this.data);
} // }
class IGE{ // class IGE{
int id; // int id;
int frame; // int frame;
String type; // String type;
int amount; // int amount;
IGE(this.id, this.frame, this.type, this.amount); // IGE(this.id, this.frame, this.type, this.amount);
} // }
class EventIGE extends Event{ // class EventIGE extends Event{
IGE data; // IGE data;
EventIGE(super.id, super.frame, super.type, this.data); // EventIGE(super.id, super.frame, super.type, this.data);
} // }
class Hold // class Hold
{ // {
String? piece; // String? piece;
bool locked; // bool locked;
Hold(this.piece, this.locked); // Hold(this.piece, this.locked);
} // }
class DataFullOptions{ // class DataFullOptions{
int? version; // int? version;
bool? seedRandom; // bool? seedRandom;
int? seed; // int? seed;
double? g; // double? g;
int? stock; // int? stock;
int? gMargin; // int? gMargin;
double? gIncrease; // double? gIncrease;
double? garbageMultiplier; // double? garbageMultiplier;
int? garbageMargin; // int? garbageMargin;
double? garbageIncrease; // double? garbageIncrease;
int? garbageCap; // int? garbageCap;
double? garbageCapIncrease; // double? garbageCapIncrease;
int? garbageCapMax; // int? garbageCapMax;
int? garbageHoleSize; // int? garbageHoleSize;
String? garbageBlocking; // TODO: enum // String? garbageBlocking; // TODO: enum
bool? hasGarbage; // bool? hasGarbage;
int? locktime; // int? locktime;
int? garbageSpeed; // int? garbageSpeed;
int? forfeitTime; // int? forfeitTime;
int? are; // int? are;
int? areLineclear; // int? areLineclear;
bool? infiniteMovement; // bool? infiniteMovement;
int? lockresets; // int? lockresets;
bool? allow180; // bool? allow180;
bool? btbChaining; // bool? btbChaining;
bool? allclears; // bool? allclears;
bool? clutch; // bool? clutch;
bool? noLockout; // bool? noLockout;
String? passthrough; // String? passthrough;
int? boardwidth; // int? boardwidth;
int? boardheight; // int? boardheight;
Handling? handling; // Handling? handling;
int? boardbuffer; // int? boardbuffer;
DataFullOptions.fromJson(Map<String, dynamic> json){ // DataFullOptions.fromJson(Map<String, dynamic> json){
version = json["version"]; // version = json["version"];
seedRandom = json["seed_random"]; // seedRandom = json["seed_random"];
seed = json["seed"]; // seed = json["seed"];
g = json["g"]; // g = json["g"];
stock = json["stock"]; // stock = json["stock"];
gMargin = json["gmargin"]; // gMargin = json["gmargin"];
gIncrease = json["gincrease"]; // gIncrease = json["gincrease"];
garbageMultiplier = json["garbagemultiplier"]; // garbageMultiplier = json["garbagemultiplier"];
garbageCapIncrease = json["garbagecapincrease"]; // garbageCapIncrease = json["garbagecapincrease"];
garbageCapMax = json["garbagecapmax"]; // garbageCapMax = json["garbagecapmax"];
garbageHoleSize = json["garbageholesize"]; // garbageHoleSize = json["garbageholesize"];
garbageBlocking = json["garbageblocking"]; // garbageBlocking = json["garbageblocking"];
hasGarbage = json["hasgarbage"]; // hasGarbage = json["hasgarbage"];
locktime = json["locktime"]; // locktime = json["locktime"];
garbageSpeed = json["garbagespeed"]; // garbageSpeed = json["garbagespeed"];
forfeitTime = json["forfeit_time"]; // forfeitTime = json["forfeit_time"];
are = json["are"]; // are = json["are"];
areLineclear = json["lineclear_are"]; // areLineclear = json["lineclear_are"];
infiniteMovement = json["infinitemovement"]; // infiniteMovement = json["infinitemovement"];
lockresets = json["lockresets"]; // lockresets = json["lockresets"];
allow180 = json["allow180"]; // allow180 = json["allow180"];
btbChaining = json["b2bchaining"]; // btbChaining = json["b2bchaining"];
allclears = json["allclears"]; // allclears = json["allclears"];
clutch = json["clutch"]; // clutch = json["clutch"];
noLockout = json["nolockout"]; // noLockout = json["nolockout"];
passthrough = json["passthrough"]; // passthrough = json["passthrough"];
boardwidth = json["boardwidth"]; // boardwidth = json["boardwidth"];
boardheight = json["boardheight"]; // boardheight = json["boardheight"];
handling = Handling.fromJson(json["handling"]); // handling = Handling.fromJson(json["handling"]);
boardbuffer = json["boardbuffer"]; // boardbuffer = json["boardbuffer"];
} // }
} // }
class DataFullStats // class DataFullStats
{ // {
double? seed; // double? seed;
int? lines; // int? lines;
int? levelLines; // int? levelLines;
int? levelLinesNeeded; // int? levelLinesNeeded;
int? inputs; // int? inputs;
int? holds; // int? holds;
int? score; // int? score;
int? zenLevel; // int? zenLevel;
int? zenProgress; // int? zenProgress;
int? level; // int? level;
int? combo; // int? combo;
int? currentComboPower; // int? currentComboPower;
int? topCombo; // int? topCombo;
int? btb; // int? btb;
int? topbtb; // int? topbtb;
int? tspins; // int? tspins;
int? piecesPlaced; // int? piecesPlaced;
Clears? clears; // Clears? clears;
Garbage? garbage; // Garbage? garbage;
int? kills; // int? kills;
Finesse? finesse; // Finesse? finesse;
DataFullStats.fromJson(Map<String, dynamic> json){ // DataFullStats.fromJson(Map<String, dynamic> json){
seed = json["seed"]; // seed = json["seed"];
lines = json["lines"]; // lines = json["lines"];
levelLines = json["level_lines"]; // levelLines = json["level_lines"];
levelLinesNeeded = json["level_lines_needed"]; // levelLinesNeeded = json["level_lines_needed"];
inputs = json["inputs"]; // inputs = json["inputs"];
holds = json["holds"]; // holds = json["holds"];
score = json["score"]; // score = json["score"];
zenLevel = json["zenlevel"]; // zenLevel = json["zenlevel"];
zenProgress = json["zenprogress"]; // zenProgress = json["zenprogress"];
level = json["level"]; // level = json["level"];
combo = json["combo"]; // combo = json["combo"];
currentComboPower = json["currentcombopower"]; // currentComboPower = json["currentcombopower"];
topCombo = json["topcombo"]; // topCombo = json["topcombo"];
btb = json["btb"]; // btb = json["btb"];
topbtb = json["topbtb"]; // topbtb = json["topbtb"];
tspins = json["tspins"]; // tspins = json["tspins"];
piecesPlaced = json["piecesplaced"]; // piecesPlaced = json["piecesplaced"];
clears = Clears.fromJson(json["clears"]); // clears = Clears.fromJson(json["clears"]);
garbage = Garbage.fromJson(json["garbage"]); // garbage = Garbage.fromJson(json["garbage"]);
kills = json["kills"]; // kills = json["kills"];
finesse = Finesse.fromJson(json["finesse"]); // finesse = Finesse.fromJson(json["finesse"]);
} // }
} // }
class DataFullGame // class DataFullGame
{ // {
List<List<String?>>? board; // List<List<String?>>? board;
List<String>? bag; // List<String>? bag;
double? g; // double? g;
bool? playing; // bool? playing;
Hold? hold; // Hold? hold;
String? piece; // String? piece;
Handling? handling; // Handling? handling;
DataFullGame.fromJson(Map<String, dynamic> json){ // DataFullGame.fromJson(Map<String, dynamic> json){
board = json["board"]; // board = json["board"];
bag = json["bag"]; // bag = json["bag"];
hold = Hold(json["hold"]["piece"], json["hold"]["locked"]); // hold = Hold(json["hold"]["piece"], json["hold"]["locked"]);
g = json["g"]; // g = json["g"];
handling = Handling.fromJson(json["handling"]); // handling = Handling.fromJson(json["handling"]);
} // }
} // }
class DataFull{ // class DataFull{
bool? successful; // bool? successful;
String? gameOverReason; // String? gameOverReason;
int? fire; // int? fire;
DataFullOptions? options; // DataFullOptions? options;
DataFullStats? stats; // DataFullStats? stats;
DataFullGame? game; // DataFullGame? game;
DataFull.fromJson(Map<String, dynamic> json){ // DataFull.fromJson(Map<String, dynamic> json){
successful = json["successful"]; // successful = json["successful"];
gameOverReason = json["gameoverreason"]; // gameOverReason = json["gameoverreason"];
fire = json["fire"]; // fire = json["fire"];
options = DataFullOptions.fromJson(json["options"]); // options = DataFullOptions.fromJson(json["options"]);
stats = DataFullStats.fromJson(json["stats"]); // stats = DataFullStats.fromJson(json["stats"]);
game = DataFullGame.fromJson(json["game"]); // game = DataFullGame.fromJson(json["game"]);
} // }
} // }
class EventFull extends Event{ // class EventFull extends Event{
DataFull data; // DataFull data;
EventFull(super.id, super.frame, super.type, this.data); // EventFull(super.id, super.frame, super.type, this.data);
} // }
class TetrioRNG{ // class TetrioRNG{
late double _t; // late double _t;
TetrioRNG(int seed){ // TetrioRNG(int seed){
_t = seed % 2147483647; // _t = seed % 2147483647;
if (_t <= 0) _t += 2147483646; // if (_t <= 0) _t += 2147483646;
} // }
int next(){ // int next(){
_t = 16807 * _t % 2147483647; // _t = 16807 * _t % 2147483647;
return _t.toInt(); // return _t.toInt();
} // }
double nextFloat(){ // double nextFloat(){
return (next() - 1) / 2147483646; // return (next() - 1) / 2147483646;
} // }
List<Tetromino> shuffleList(List<Tetromino> array){ // List<Tetromino> shuffleList(List<Tetromino> array){
int length = array.length; // int length = array.length;
if (length == 0) return []; // if (length == 0) return [];
for (; --length > 0;){ // for (; --length > 0;){
int swapIndex = ((nextFloat()) * (length + 1)).toInt(); // int swapIndex = ((nextFloat()) * (length + 1)).toInt();
Tetromino tmp = array[length]; // Tetromino tmp = array[length];
array[length] = array[swapIndex]; // array[length] = array[swapIndex];
array[swapIndex] = tmp; // array[swapIndex] = tmp;
} // }
return array; // return array;
} // }
} // }
enum Tetromino{ // enum Tetromino{
Z, // Z,
L, // L,
O, // O,
S, // S,
I, // I,
J, // J,
T, // T,
garbage, // garbage,
empty // empty
} // }
List<Tetromino> tetrominoes = [Tetromino.Z, Tetromino.L, Tetromino.O, Tetromino.S, Tetromino.I, Tetromino.J, Tetromino.T]; // List<Tetromino> tetrominoes = [Tetromino.Z, Tetromino.L, Tetromino.O, Tetromino.S, Tetromino.I, Tetromino.J, Tetromino.T];
List<List<List<Vector2>>> shapes = [ // List<List<List<Vector2>>> shapes = [
[ // Z // [ // Z
[Vector2(0, 0), Vector2(1, 0), Vector2(1, 1), Vector2(2, 1)], // [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(2, 0), Vector2(1, 1), Vector2(2, 1), Vector2(1, 2)],
[Vector2(0, 1), Vector2(1, 1), Vector2(1, 2), Vector2(2, 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)] // [Vector2(1, 0), Vector2(0, 1), Vector2(1, 1), Vector2(0, 2)]
], // ],
[ // L // [ // L
[Vector2(2, 0), Vector2(0, 1), Vector2(1, 1), Vector2(2, 1)], // [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(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, 1), Vector2(1, 1), Vector2(2, 1), Vector2(0, 2)],
[Vector2(0, 0), Vector2(1, 0), Vector2(1, 1), Vector2(1, 2)] // [Vector2(0, 0), Vector2(1, 0), Vector2(1, 1), Vector2(1, 2)]
], // ],
[ // O // [ // 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)],
[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 // [ // S
[Vector2(1, 0), Vector2(2, 0), Vector2(0, 1), Vector2(1, 1)], // [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, 0), Vector2(1, 1), Vector2(2, 1), Vector2(2, 2)],
[Vector2(1, 1), Vector2(2, 1), Vector2(0, 2), Vector2(1, 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)] // [Vector2(0, 0), Vector2(0, 1), Vector2(1, 1), Vector2(1, 2)]
], // ],
[ // I // [ // I
[Vector2(0, 1), Vector2(1, 1), Vector2(2, 1), Vector2(3, 1)], // [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(2, 0), Vector2(2, 1), Vector2(2, 2), Vector2(2, 3)],
[Vector2(0, 2), Vector2(1, 2), Vector2(2, 2), Vector2(3, 2)], // [Vector2(0, 2), Vector2(1, 2), Vector2(2, 2), Vector2(3, 2)],
[Vector2(1, 0), Vector2(1, 1), Vector2(1, 2), Vector2(1, 3)] // [Vector2(1, 0), Vector2(1, 1), Vector2(1, 2), Vector2(1, 3)]
], // ],
[ // J // [ // J
[Vector2(0, 0), Vector2(0, 1), Vector2(1, 1), Vector2(2, 1)], // [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(1, 0), Vector2(2, 0), Vector2(1, 1), Vector2(1, 2)],
[Vector2(0, 1), Vector2(1, 1), Vector2(2, 1), Vector2(2, 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)] // [Vector2(1, 0), Vector2(1, 1), Vector2(0, 2), Vector2(1, 2)]
], // ],
[ // T // [ // T
[Vector2(1, 0), Vector2(0, 1), Vector2(1, 1), Vector2(2, 1)], // [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(1, 0), Vector2(1, 1), Vector2(2, 1), Vector2(1, 2)],
[Vector2(0, 1), 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)] // [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)]; // 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 = { // const Map<String, double> garbage = {
"single": 0, // "single": 0,
"double": 1, // "double": 1,
"triple": 2, // "triple": 2,
"quad": 4, // "quad": 4,
"penta": 5, // "penta": 5,
"t-spin": 0, // "t-spin": 0,
"t-spin single": 2, // "t-spin single": 2,
"t-spin double": 4, // "t-spin double": 4,
"t-spin triple": 6, // "t-spin triple": 6,
"t-spin quad": 10, // "t-spin quad": 10,
"t-spin penta": 12, // "t-spin penta": 12,
"t-spin mini": 0, // "t-spin mini": 0,
"t-spin mini single": 0, // "t-spin mini single": 0,
"t-spin mini double": 1, // "t-spin mini double": 1,
"allclear": 10 // "allclear": 10
}; // };
int btbBonus = 1; // int btbBonus = 1;
double btbLog = 0.8; // double btbLog = 0.8;
double comboBonus = 0.25; // double comboBonus = 0.25;
int comboMinifier = 1; // int comboMinifier = 1;
double comboMinifierLog = 1.25; // double comboMinifierLog = 1.25;
List<int> comboTable = [0, 1, 1, 2, 2, 3, 3, 4, 4, 4, 5]; // List<int> comboTable = [0, 1, 1, 2, 2, 3, 3, 4, 4, 4, 5];

View File

@ -4,9 +4,9 @@
/// To regenerate, run: `dart run slang` /// To regenerate, run: `dart run slang`
/// ///
/// Locales: 2 /// Locales: 2
/// Strings: 1098 (549 per locale) /// Strings: 1120 (560 per locale)
/// ///
/// Built on 2024-03-20 at 22:41 UTC /// Built on 2024-03-24 at 14:28 UTC
// coverage:ignore-file // coverage:ignore-file
// ignore_for_file: type=lint // ignore_for_file: type=lint
@ -183,11 +183,11 @@ class Translations implements BaseTranslations<AppLocale, Translations> {
String get noRecords => 'No records'; String get noRecords => 'No records';
String noOldRecords({required num n}) => (_root.$meta.cardinalResolver ?? PluralResolvers.cardinal('en'))(n, String noOldRecords({required num n}) => (_root.$meta.cardinalResolver ?? PluralResolvers.cardinal('en'))(n,
zero: 'No records', zero: 'No records',
one: '${n} record', one: 'Only ${n} record',
two: '${n} records', two: 'Only ${n} records',
few: '${n} records', few: 'Only ${n} records',
many: '${n} records', many: 'Only ${n} records',
other: '${n} records', other: 'Only ${n} records',
); );
String get noRecord => 'No record'; String get noRecord => 'No record';
String get botRecord => 'Bots are not allowed to set records'; String get botRecord => 'Bots are not allowed to set records';
@ -212,7 +212,7 @@ class Translations implements BaseTranslations<AppLocale, Translations> {
String supporter({required Object tier}) => 'Supporter tier ${tier}'; String supporter({required Object tier}) => 'Supporter tier ${tier}';
String comparingWith({required Object newDate, required Object oldDate}) => 'Data from ${newDate} comparing with ${oldDate}'; String comparingWith({required Object newDate, required Object oldDate}) => 'Data from ${newDate} comparing with ${oldDate}';
String get top => 'Top'; String get top => 'Top';
String get topRank => 'Top Rank'; String get topRank => 'Top rank';
String verdictGeneral({required Object n, required Object verdict, required Object rank}) => '${n} ${verdict} than ${rank} rank average'; String verdictGeneral({required Object n, required Object verdict, required Object rank}) => '${n} ${verdict} than ${rank} rank average';
String get verdictBetter => 'better'; String get verdictBetter => 'better';
String get verdictWorse => 'worse'; String get verdictWorse => 'worse';
@ -271,10 +271,14 @@ class Translations implements BaseTranslations<AppLocale, Translations> {
String get openReplay => 'Open replay in TETR.IO'; String get openReplay => 'Open replay in TETR.IO';
String replaySaved({required Object path}) => 'Replay saved to ${path}'; String replaySaved({required Object path}) => 'Replay saved to ${path}';
String get match => 'Match'; String get match => 'Match';
String get timeWeightedmatch => 'Match (time-weighted)';
String roundNumber({required Object n}) => 'Round ${n}'; String roundNumber({required Object n}) => 'Round ${n}';
String get statsFor => 'Stats for'; String get statsFor => 'Stats for';
String get numberOfRounds => 'Number of rounds';
String get matchLength => 'Match Length'; String get matchLength => 'Match Length';
String get roundLength => 'Round Length'; String get roundLength => 'Round Length';
String get matchStats => 'Match stats';
String get timeWeightedmatchStats => 'Time-weighted match stats';
String get replayIssue => 'Can\'t process replay'; String get replayIssue => 'Can\'t process replay';
String get matchIsTooOld => 'Replay is not available'; String get matchIsTooOld => 'Replay is not available';
String get winner => 'Winner'; String get winner => 'Winner';
@ -311,6 +315,15 @@ class Translations implements BaseTranslations<AppLocale, Translations> {
many: '${n} players', many: '${n} players',
other: '${n} players', other: '${n} players',
); );
String games({required num n}) => (_root.$meta.cardinalResolver ?? PluralResolvers.cardinal('en'))(n,
zero: '${n} games',
one: '${n} game',
two: '${n} games',
few: '${n} games',
many: '${n} games',
other: '${n} games',
);
String gamesPlayed({required Object games}) => '${games} played';
String get chart => 'Chart'; String get chart => 'Chart';
String get entries => 'Entries'; String get entries => 'Entries';
String get minimums => 'Minimums'; String get minimums => 'Minimums';
@ -853,7 +866,7 @@ class _StringsRu implements Translations {
@override String get assignedManualy => 'Этот значок был присвоен вручную администрацией TETR.IO'; @override String get assignedManualy => 'Этот значок был присвоен вручную администрацией TETR.IO';
@override String comparingWith({required Object newDate, required Object oldDate}) => 'Данные от ${newDate} в сравнении с данными от ${oldDate}'; @override String comparingWith({required Object newDate, required Object oldDate}) => 'Данные от ${newDate} в сравнении с данными от ${oldDate}';
@override String get top => 'Топ'; @override String get top => 'Топ';
@override String get topRank => 'Топ Ранг'; @override String get topRank => 'Топ ранг';
@override String verdictGeneral({required Object verdict, required Object rank, required Object n}) => '${verdict} среднего ${rank} ранга на ${n}'; @override String verdictGeneral({required Object verdict, required Object rank, required Object n}) => '${verdict} среднего ${rank} ранга на ${n}';
@override String get verdictBetter => 'Лучше'; @override String get verdictBetter => 'Лучше';
@override String get verdictWorse => 'Хуже'; @override String get verdictWorse => 'Хуже';
@ -912,10 +925,14 @@ class _StringsRu implements Translations {
@override String get openReplay => 'Открыть повтор в TETR.IO'; @override String get openReplay => 'Открыть повтор в TETR.IO';
@override String replaySaved({required Object path}) => 'Повтор сохранён по пути ${path}'; @override String replaySaved({required Object path}) => 'Повтор сохранён по пути ${path}';
@override String get match => 'Матч'; @override String get match => 'Матч';
@override String get timeWeightedmatch => 'Матч (взвешенная по времени)';
@override String roundNumber({required Object n}) => 'Раунд ${n}'; @override String roundNumber({required Object n}) => 'Раунд ${n}';
@override String get statsFor => 'Статистика за'; @override String get statsFor => 'Статистика за';
@override String get numberOfRounds => 'Количество раундов';
@override String get matchLength => 'Продолжительность матча'; @override String get matchLength => 'Продолжительность матча';
@override String get roundLength => 'Продолжительность раунда'; @override String get roundLength => 'Продолжительность раунда';
@override String get matchStats => 'Статистика матча';
@override String get timeWeightedmatchStats => 'Взвешенная по времени cтатистика матча';
@override String get replayIssue => 'Ошибка обработки повтора'; @override String get replayIssue => 'Ошибка обработки повтора';
@override String get matchIsTooOld => 'Информация о повторе недоступна'; @override String get matchIsTooOld => 'Информация о повторе недоступна';
@override String get winner => 'Победитель'; @override String get winner => 'Победитель';
@ -952,6 +969,15 @@ class _StringsRu implements Translations {
many: '${n} игроков', many: '${n} игроков',
other: '${n} игроков', other: '${n} игроков',
); );
@override String games({required num n}) => (_root.$meta.cardinalResolver ?? PluralResolvers.cardinal('ru'))(n,
zero: '${n} игр',
one: '${n} игра',
two: '${n} игры',
few: '${n} игры',
many: '${n} игр',
other: '${n} игр',
);
@override String gamesPlayed({required Object games}) => '${games} сыграно';
@override String get chart => 'График'; @override String get chart => 'График';
@override String get entries => 'Список'; @override String get entries => 'Список';
@override String get minimums => 'Минимумы'; @override String get minimums => 'Минимумы';
@ -1457,11 +1483,11 @@ extension on Translations {
case 'noRecords': return 'No records'; case 'noRecords': return 'No records';
case 'noOldRecords': return ({required num n}) => (_root.$meta.cardinalResolver ?? PluralResolvers.cardinal('en'))(n, case 'noOldRecords': return ({required num n}) => (_root.$meta.cardinalResolver ?? PluralResolvers.cardinal('en'))(n,
zero: 'No records', zero: 'No records',
one: '${n} record', one: 'Only ${n} record',
two: '${n} records', two: 'Only ${n} records',
few: '${n} records', few: 'Only ${n} records',
many: '${n} records', many: 'Only ${n} records',
other: '${n} records', other: 'Only ${n} records',
); );
case 'noRecord': return 'No record'; case 'noRecord': return 'No record';
case 'botRecord': return 'Bots are not allowed to set records'; case 'botRecord': return 'Bots are not allowed to set records';
@ -1486,7 +1512,7 @@ extension on Translations {
case 'supporter': return ({required Object tier}) => 'Supporter tier ${tier}'; case 'supporter': return ({required Object tier}) => 'Supporter tier ${tier}';
case 'comparingWith': return ({required Object newDate, required Object oldDate}) => 'Data from ${newDate} comparing with ${oldDate}'; case 'comparingWith': return ({required Object newDate, required Object oldDate}) => 'Data from ${newDate} comparing with ${oldDate}';
case 'top': return 'Top'; case 'top': return 'Top';
case 'topRank': return 'Top Rank'; case 'topRank': return 'Top rank';
case 'verdictGeneral': return ({required Object n, required Object verdict, required Object rank}) => '${n} ${verdict} than ${rank} rank average'; case 'verdictGeneral': return ({required Object n, required Object verdict, required Object rank}) => '${n} ${verdict} than ${rank} rank average';
case 'verdictBetter': return 'better'; case 'verdictBetter': return 'better';
case 'verdictWorse': return 'worse'; case 'verdictWorse': return 'worse';
@ -1545,10 +1571,14 @@ extension on Translations {
case 'openReplay': return 'Open replay in TETR.IO'; case 'openReplay': return 'Open replay in TETR.IO';
case 'replaySaved': return ({required Object path}) => 'Replay saved to ${path}'; case 'replaySaved': return ({required Object path}) => 'Replay saved to ${path}';
case 'match': return 'Match'; case 'match': return 'Match';
case 'timeWeightedmatch': return 'Match (time-weighted)';
case 'roundNumber': return ({required Object n}) => 'Round ${n}'; case 'roundNumber': return ({required Object n}) => 'Round ${n}';
case 'statsFor': return 'Stats for'; case 'statsFor': return 'Stats for';
case 'numberOfRounds': return 'Number of rounds';
case 'matchLength': return 'Match Length'; case 'matchLength': return 'Match Length';
case 'roundLength': return 'Round Length'; case 'roundLength': return 'Round Length';
case 'matchStats': return 'Match stats';
case 'timeWeightedmatchStats': return 'Time-weighted match stats';
case 'replayIssue': return 'Can\'t process replay'; case 'replayIssue': return 'Can\'t process replay';
case 'matchIsTooOld': return 'Replay is not available'; case 'matchIsTooOld': return 'Replay is not available';
case 'winner': return 'Winner'; case 'winner': return 'Winner';
@ -1585,6 +1615,15 @@ extension on Translations {
many: '${n} players', many: '${n} players',
other: '${n} players', other: '${n} players',
); );
case 'games': return ({required num n}) => (_root.$meta.cardinalResolver ?? PluralResolvers.cardinal('en'))(n,
zero: '${n} games',
one: '${n} game',
two: '${n} games',
few: '${n} games',
many: '${n} games',
other: '${n} games',
);
case 'gamesPlayed': return ({required Object games}) => '${games} played';
case 'chart': return 'Chart'; case 'chart': return 'Chart';
case 'entries': return 'Entries'; case 'entries': return 'Entries';
case 'minimums': return 'Minimums'; case 'minimums': return 'Minimums';
@ -2053,7 +2092,7 @@ extension on _StringsRu {
case 'assignedManualy': return 'Этот значок был присвоен вручную администрацией TETR.IO'; case 'assignedManualy': return 'Этот значок был присвоен вручную администрацией TETR.IO';
case 'comparingWith': return ({required Object newDate, required Object oldDate}) => 'Данные от ${newDate} в сравнении с данными от ${oldDate}'; case 'comparingWith': return ({required Object newDate, required Object oldDate}) => 'Данные от ${newDate} в сравнении с данными от ${oldDate}';
case 'top': return 'Топ'; case 'top': return 'Топ';
case 'topRank': return 'Топ Ранг'; case 'topRank': return 'Топ ранг';
case 'verdictGeneral': return ({required Object verdict, required Object rank, required Object n}) => '${verdict} среднего ${rank} ранга на ${n}'; case 'verdictGeneral': return ({required Object verdict, required Object rank, required Object n}) => '${verdict} среднего ${rank} ранга на ${n}';
case 'verdictBetter': return 'Лучше'; case 'verdictBetter': return 'Лучше';
case 'verdictWorse': return 'Хуже'; case 'verdictWorse': return 'Хуже';
@ -2112,10 +2151,14 @@ extension on _StringsRu {
case 'openReplay': return 'Открыть повтор в TETR.IO'; case 'openReplay': return 'Открыть повтор в TETR.IO';
case 'replaySaved': return ({required Object path}) => 'Повтор сохранён по пути ${path}'; case 'replaySaved': return ({required Object path}) => 'Повтор сохранён по пути ${path}';
case 'match': return 'Матч'; case 'match': return 'Матч';
case 'timeWeightedmatch': return 'Матч (взвешенная по времени)';
case 'roundNumber': return ({required Object n}) => 'Раунд ${n}'; case 'roundNumber': return ({required Object n}) => 'Раунд ${n}';
case 'statsFor': return 'Статистика за'; case 'statsFor': return 'Статистика за';
case 'numberOfRounds': return 'Количество раундов';
case 'matchLength': return 'Продолжительность матча'; case 'matchLength': return 'Продолжительность матча';
case 'roundLength': return 'Продолжительность раунда'; case 'roundLength': return 'Продолжительность раунда';
case 'matchStats': return 'Статистика матча';
case 'timeWeightedmatchStats': return 'Взвешенная по времени cтатистика матча';
case 'replayIssue': return 'Ошибка обработки повтора'; case 'replayIssue': return 'Ошибка обработки повтора';
case 'matchIsTooOld': return 'Информация о повторе недоступна'; case 'matchIsTooOld': return 'Информация о повторе недоступна';
case 'winner': return 'Победитель'; case 'winner': return 'Победитель';
@ -2152,6 +2195,15 @@ extension on _StringsRu {
many: '${n} игроков', many: '${n} игроков',
other: '${n} игроков', other: '${n} игроков',
); );
case 'games': return ({required num n}) => (_root.$meta.cardinalResolver ?? PluralResolvers.cardinal('ru'))(n,
zero: '${n} игр',
one: '${n} игра',
two: '${n} игры',
few: '${n} игры',
many: '${n} игр',
other: '${n} игр',
);
case 'gamesPlayed': return ({required Object games}) => '${games} сыграно';
case 'chart': return 'График'; case 'chart': return 'График';
case 'entries': return 'Список'; case 'entries': return 'Список';
case 'minimums': return 'Минимумы'; case 'minimums': return 'Минимумы';

View File

@ -415,12 +415,12 @@ class TetrioService extends DB {
// parsing data into TetraLeagueAlphaRecord objects // parsing data into TetraLeagueAlphaRecord objects
for (var entry in csv){ for (var entry in csv){
TetraLeagueAlphaRecord match = TetraLeagueAlphaRecord( TetraLeagueAlphaRecord match = TetraLeagueAlphaRecord(
replayId: entry[0], replayId: entry[0].toString(),
ownId: entry[0], // i gonna disting p1nkl0bst3r entries with it ownId: entry[0].toString(), // i gonna disting p1nkl0bst3r entries with it
timestamp: DateTime.parse(entry[1]), timestamp: DateTime.parse(entry[1]),
endContext: [ endContext: [
EndContextMulti( EndContextMulti(
userId: entry[2], userId: entry[2].toString(),
username: entry[3].toString(), username: entry[3].toString(),
naturalOrder: 0, naturalOrder: 0,
inputs: -1, inputs: -1,
@ -437,7 +437,7 @@ class TetrioService extends DB {
success: true success: true
), ),
EndContextMulti( EndContextMulti(
userId: entry[8], userId: entry[8].toString(),
username: entry[9].toString(), username: entry[9].toString(),
naturalOrder: 1, naturalOrder: 1,
inputs: -1, inputs: -1,

View File

@ -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;
}

View File

@ -8,3 +8,4 @@ final NumberFormat f3 = NumberFormat.decimalPatternDigits(locale: LocaleSettings
final NumberFormat f2 = NumberFormat.decimalPatternDigits(locale: LocaleSettings.currentLocale.languageCode, decimalDigits: 2); 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 f2l = NumberFormat.decimalPatternDigits(locale: LocaleSettings.currentLocale.languageCode, decimalDigits: 2)..minimumFractionDigits = 0;
final NumberFormat f0 = NumberFormat.decimalPattern(LocaleSettings.currentLocale.languageCode); final NumberFormat f0 = NumberFormat.decimalPattern(LocaleSettings.currentLocale.languageCode);
final NumberFormat percentage = NumberFormat.percentPattern(LocaleSettings.currentLocale.languageCode)..maximumFractionDigits = 2;

View File

@ -66,16 +66,12 @@ class CalcState extends State<CalcView> {
title: Text(t.statsCalc), title: Text(t.statsCalc),
), ),
backgroundColor: Colors.black, backgroundColor: Colors.black,
body: SafeArea( body: SingleChildScrollView(
child: Center( child: Center(
child: Container( child: Container(
constraints: const BoxConstraints(maxWidth: 768), constraints: const BoxConstraints(maxWidth: 768),
child: NestedScrollView( child: Column(children: [
controller: _scrollController, Padding(
headerSliverBuilder: (context, value) {
return [
SliverToBoxAdapter(
child: Padding(
padding: const EdgeInsets.fromLTRB(14, 16, 16, 32), padding: const EdgeInsets.fromLTRB(14, 16, 16, 32),
child: Row( child: Row(
children: [ children: [
@ -113,16 +109,9 @@ class CalcState extends State<CalcView> {
], ],
), ),
), ),
), Divider(),
const SliverToBoxAdapter( if (nerdStats == null) Text(t.calcViewNoValues)
child: Divider(), else Column(children: [
)
];
},
body: nerdStats == null
? Text(t.calcViewNoValues)
: ListView(
children: [
_ListEntry(value: nerdStats!.app, label: t.statCellNum.app.replaceAll(RegExp(r'\n'), " "), fractionDigits: 3), _ListEntry(value: nerdStats!.app, label: t.statCellNum.app.replaceAll(RegExp(r'\n'), " "), fractionDigits: 3),
_ListEntry(value: nerdStats!.vsapm, label: "VS/APM", fractionDigits: 3), _ListEntry(value: nerdStats!.vsapm, label: "VS/APM", fractionDigits: 3),
_ListEntry(value: nerdStats!.dss, label: t.statCellNum.dss.replaceAll(RegExp(r'\n'), " "), fractionDigits: 3), _ListEntry(value: nerdStats!.dss, label: t.statCellNum.dss.replaceAll(RegExp(r'\n'), " "), fractionDigits: 3),
@ -133,9 +122,9 @@ class CalcState extends State<CalcView> {
_ListEntry(value: nerdStats!.nyaapp, label: t.statCellNum.nyaapp.replaceAll(RegExp(r'\n'), " "), fractionDigits: 3), _ListEntry(value: nerdStats!.nyaapp, label: t.statCellNum.nyaapp.replaceAll(RegExp(r'\n'), " "), fractionDigits: 3),
_ListEntry(value: nerdStats!.area, label: t.statCellNum.area.replaceAll(RegExp(r'\n'), " "), fractionDigits: 3), _ListEntry(value: nerdStats!.area, label: t.statCellNum.area.replaceAll(RegExp(r'\n'), " "), fractionDigits: 3),
_ListEntry(value: estTr!.esttr, label: t.statCellNum.estOfTR, fractionDigits: 3), _ListEntry(value: estTr!.esttr, label: t.statCellNum.estOfTR, fractionDigits: 3),
Graphs(apm!, pps!, vs!, nerdStats!, playstyle!), Graphs(apm!, pps!, vs!, nerdStats!, playstyle!)
], ],)
)), ],),
), ),
), ),
), ),

View File

@ -255,16 +255,14 @@ class CompareState extends State<CompareView> {
return Scaffold( return Scaffold(
appBar: AppBar(title: Text("$titleGreenSide ${t.vs} $titleRedSide")), appBar: AppBar(title: Text("$titleGreenSide ${t.vs} $titleRedSide")),
backgroundColor: Colors.black, backgroundColor: Colors.black,
body: SafeArea( body: SingleChildScrollView(
controller: _scrollController,
physics: AlwaysScrollableScrollPhysics(),
child: Center( child: Center(
child: Container( child: Container(
constraints: const BoxConstraints(maxWidth: 768), constraints: const BoxConstraints(maxWidth: 768),
child: NestedScrollView( child: Column(children: [
controller: _scrollController, Padding(
headerSliverBuilder: (context, value) {
return [
SliverToBoxAdapter(
child: Padding(
padding: const EdgeInsets.fromLTRB(16, 16, 16, 32), padding: const EdgeInsets.fromLTRB(16, 16, 16, 32),
child: Row( child: Row(
mainAxisAlignment: MainAxisAlignment.spaceBetween, mainAxisAlignment: MainAxisAlignment.spaceBetween,
@ -319,21 +317,10 @@ class CompareState extends State<CompareView> {
], ],
), ),
), ),
), Divider(),
const SliverToBoxAdapter( if (!listEquals(theGreenSide, [null, null, null]) && !listEquals(theRedSide, [null, null, null])) Column(
child: Divider(), children: [
) if (theGreenSide[0] != null && theRedSide[0] != null && theGreenSide[0]!.role != "banned" && theRedSide[0]!.role != "banned")
];
},
body: Center(
child: Container(
constraints: const BoxConstraints(maxWidth: 768),
child: ListView(
children: !listEquals(theGreenSide, [null, null, null]) && !listEquals(theRedSide, [null, null, null])? [
if (theGreenSide[0] != null &&
theRedSide[0] != null &&
theGreenSide[0]!.role != "banned" &&
theRedSide[0]!.role != "banned")
Column( Column(
children: [ children: [
CompareRegTimeThingy( CompareRegTimeThingy(
@ -347,8 +334,7 @@ class CompareState extends State<CompareView> {
higherIsBetter: true, higherIsBetter: true,
fractionDigits: 2, fractionDigits: 2,
), ),
if (!theGreenSide[0].gameTime.isNegative && if (!theGreenSide[0].gameTime.isNegative && !theRedSide[0].gameTime.isNegative)
!theRedSide[0].gameTime.isNegative)
CompareThingy( CompareThingy(
greenSide: theGreenSide[0].gameTime.inMicroseconds / greenSide: theGreenSide[0].gameTime.inMicroseconds /
1000000 / 1000000 /
@ -362,16 +348,14 @@ class CompareState extends State<CompareView> {
higherIsBetter: true, higherIsBetter: true,
fractionDigits: 2, fractionDigits: 2,
), ),
if (theGreenSide[0].gamesPlayed >= 0 && if (theGreenSide[0].gamesPlayed >= 0 && theRedSide[0].gamesPlayed >= 0)
theRedSide[0].gamesPlayed >= 0)
CompareThingy( CompareThingy(
label: t.statCellNum.onlineGames.replaceAll(RegExp(r'\n'), " "), label: t.statCellNum.onlineGames.replaceAll(RegExp(r'\n'), " "),
greenSide: theGreenSide[0].gamesPlayed, greenSide: theGreenSide[0].gamesPlayed,
redSide: theRedSide[0].gamesPlayed, redSide: theRedSide[0].gamesPlayed,
higherIsBetter: true, higherIsBetter: true,
), ),
if (theGreenSide[0].gamesWon >= 0 && if (theGreenSide[0].gamesWon >= 0 && theRedSide[0].gamesWon >= 0)
theRedSide[0].gamesWon >= 0)
CompareThingy( CompareThingy(
label: t.statCellNum.gamesWon.replaceAll(RegExp(r'\n'), " "), label: t.statCellNum.gamesWon.replaceAll(RegExp(r'\n'), " "),
greenSide: theGreenSide[0].gamesWon, greenSide: theGreenSide[0].gamesWon,
@ -387,17 +371,14 @@ class CompareState extends State<CompareView> {
const Divider(), const Divider(),
], ],
), ),
if (theGreenSide[0] != null && if (theGreenSide[0] != null && theRedSide[0] != null && (theGreenSide[0]!.role == "banned" || theRedSide[0]!.role == "banned"))
theRedSide[0] != null &&
(theGreenSide[0]!.role == "banned" ||
theRedSide[0]!.role == "banned"))
CompareBoolThingy( CompareBoolThingy(
greenSide: theGreenSide[0].role == "banned", greenSide: theGreenSide[0].role == "banned",
redSide: theRedSide[0].role == "banned", redSide: theRedSide[0].role == "banned",
label: t.normalBanned, label: t.normalBanned,
trueIsBetter: false), trueIsBetter: false
(theGreenSide[2].gamesPlayed > 0 || greenSideMode == Mode.stats) && ),
(theRedSide[2].gamesPlayed > 0 || redSideMode == Mode.stats) (theGreenSide[2].gamesPlayed > 0 || greenSideMode == Mode.stats) && (theRedSide[2].gamesPlayed > 0 || redSideMode == Mode.stats)
? Column( ? Column(
children: [ children: [
Padding( Padding(
@ -694,13 +675,13 @@ class CompareState extends State<CompareView> {
), ),
], ],
) )
] : [Padding( ],
)
else Padding(
padding: const EdgeInsets.all(8.0), padding: const EdgeInsets.all(8.0),
child: Text(t.compareViewNoValues(avgR: "\$avgR"), textAlign: TextAlign.center), child: Text(t.compareViewNoValues(avgR: "\$avgR"), textAlign: TextAlign.center),
)], // This is so fucked up holy shit
),
),
) )
],
), ),
), ),
), ),

View File

@ -34,7 +34,7 @@ import 'package:go_router/go_router.dart';
final TetrioService teto = TetrioService(); // thing, that manadge our local DB final TetrioService teto = TetrioService(); // thing, that manadge our local DB
int _chartsIndex = 0; int _chartsIndex = 0;
bool _showHistoryAsTable = false; bool _gamesPlayedInsteadOfDateAndTime = false;
List _historyShortTitles = ["TR", "Glicko", "RD", "APM", "PPS", "VS", "APP", "DS/S", "DS/P", "APP + DS/P", "VS/APM", "Cheese", "GbE", "wAPP", "Area", "eTR", "±eTR", "Opener", "Plonk", "Inf. DS", "Stride"]; List _historyShortTitles = ["TR", "Glicko", "RD", "APM", "PPS", "VS", "APP", "DS/S", "DS/P", "APP + DS/P", "VS/APM", "Cheese", "GbE", "wAPP", "Area", "eTR", "±eTR", "Opener", "Plonk", "Inf. DS", "Stride"];
late ScrollController _scrollController; late ScrollController _scrollController;
final NumberFormat _timeInSec = NumberFormat("#,###.###s.", LocaleSettings.currentLocale.languageCode); final NumberFormat _timeInSec = NumberFormat("#,###.###s.", LocaleSettings.currentLocale.languageCode);
@ -85,6 +85,7 @@ class _MainState extends State<MainView> with TickerProviderStateMixin {
String _titleNickname = "dan63047"; String _titleNickname = "dan63047";
/// Each dropdown menu item contains list of dots for the graph /// Each dropdown menu item contains list of dots for the graph
var chartsData = <DropdownMenuItem<List<FlSpot>>>[]; var chartsData = <DropdownMenuItem<List<FlSpot>>>[];
var chartsDataGamesPlayed = <DropdownMenuItem<List<FlSpot>>>[];
//var tableData = <TableRow>[]; //var tableData = <TableRow>[];
final bodyGlobalKey = GlobalKey(); final bodyGlobalKey = GlobalKey();
bool _showSearchBar = false; bool _showSearchBar = false;
@ -283,6 +284,29 @@ class _MainState extends State<MainView> with TickerProviderStateMixin {
DropdownMenuItem(value: [for (var tl in uniqueTL) if (tl.playstyle != null) FlSpot(tl.timestamp.millisecondsSinceEpoch.toDouble(), tl.playstyle!.infds)], child: const Text("Inf. DS")), DropdownMenuItem(value: [for (var tl in uniqueTL) if (tl.playstyle != null) FlSpot(tl.timestamp.millisecondsSinceEpoch.toDouble(), tl.playstyle!.infds)], child: const Text("Inf. DS")),
DropdownMenuItem(value: [for (var tl in uniqueTL) if (tl.playstyle != null) FlSpot(tl.timestamp.millisecondsSinceEpoch.toDouble(), tl.playstyle!.stride)], child: const Text("Stride")), DropdownMenuItem(value: [for (var tl in uniqueTL) if (tl.playstyle != null) FlSpot(tl.timestamp.millisecondsSinceEpoch.toDouble(), tl.playstyle!.stride)], child: const Text("Stride")),
]; ];
chartsDataGamesPlayed = <DropdownMenuItem<List<FlSpot>>>[ // Dumping charts data into dropdown menu items, while cheking if every entry is valid
DropdownMenuItem(value: [for (var tl in uniqueTL) if (tl.gamesPlayed > 9) FlSpot(tl.gamesPlayed.toDouble(), tl.rating)], child: Text(t.statCellNum.tr)),
DropdownMenuItem(value: [for (var tl in uniqueTL) if (tl.gamesPlayed > 9) FlSpot(tl.gamesPlayed.toDouble(), tl.glicko!)], child: const Text("Glicko")),
DropdownMenuItem(value: [for (var tl in uniqueTL) if (tl.gamesPlayed > 9) FlSpot(tl.gamesPlayed.toDouble(), tl.rd!)], child: const Text("Rating Deviation")),
DropdownMenuItem(value: [for (var tl in uniqueTL) if (tl.apm != null) FlSpot(tl.gamesPlayed.toDouble(), tl.apm!)], child: Text(t.statCellNum.apm.replaceAll(RegExp(r'\n'), " "))),
DropdownMenuItem(value: [for (var tl in uniqueTL) if (tl.pps != null) FlSpot(tl.gamesPlayed.toDouble(), tl.pps!)], child: Text(t.statCellNum.pps.replaceAll(RegExp(r'\n'), " "))),
DropdownMenuItem(value: [for (var tl in uniqueTL) if (tl.vs != null) FlSpot(tl.gamesPlayed.toDouble(), tl.vs!)], child: Text(t.statCellNum.vs.replaceAll(RegExp(r'\n'), " "))),
DropdownMenuItem(value: [for (var tl in uniqueTL) if (tl.nerdStats != null) FlSpot(tl.gamesPlayed.toDouble(), tl.nerdStats!.app)], child: Text(t.statCellNum.app.replaceAll(RegExp(r'\n'), " "))),
DropdownMenuItem(value: [for (var tl in uniqueTL) if (tl.nerdStats != null) FlSpot(tl.gamesPlayed.toDouble(), tl.nerdStats!.dss)], child: Text(t.statCellNum.dss.replaceAll(RegExp(r'\n'), " "))),
DropdownMenuItem(value: [for (var tl in uniqueTL) if (tl.nerdStats != null) FlSpot(tl.gamesPlayed.toDouble(), tl.nerdStats!.dsp)], child: Text(t.statCellNum.dsp.replaceAll(RegExp(r'\n'), " "))),
DropdownMenuItem(value: [for (var tl in uniqueTL) if (tl.nerdStats != null) FlSpot(tl.gamesPlayed.toDouble(), tl.nerdStats!.appdsp)], child: const Text("APP + DS/P")),
DropdownMenuItem(value: [for (var tl in uniqueTL) if (tl.nerdStats != null) FlSpot(tl.gamesPlayed.toDouble(), tl.nerdStats!.vsapm)], child: const Text("VS/APM")),
DropdownMenuItem(value: [for (var tl in uniqueTL) if (tl.nerdStats != null) FlSpot(tl.gamesPlayed.toDouble(), tl.nerdStats!.cheese)], child: Text(t.statCellNum.cheese.replaceAll(RegExp(r'\n'), " "))),
DropdownMenuItem(value: [for (var tl in uniqueTL) if (tl.nerdStats != null) FlSpot(tl.gamesPlayed.toDouble(), tl.nerdStats!.gbe)], child: Text(t.statCellNum.gbe.replaceAll(RegExp(r'\n'), " "))),
DropdownMenuItem(value: [for (var tl in uniqueTL) if (tl.nerdStats != null) FlSpot(tl.gamesPlayed.toDouble(), tl.nerdStats!.nyaapp)], child: Text(t.statCellNum.nyaapp.replaceAll(RegExp(r'\n'), " "))),
DropdownMenuItem(value: [for (var tl in uniqueTL) if (tl.nerdStats != null) FlSpot(tl.gamesPlayed.toDouble(), tl.nerdStats!.area)], child: Text(t.statCellNum.area.replaceAll(RegExp(r'\n'), " "))),
DropdownMenuItem(value: [for (var tl in uniqueTL) if (tl.estTr != null) FlSpot(tl.gamesPlayed.toDouble(), tl.estTr!.esttr)], child: Text(t.statCellNum.estOfTR.replaceAll(RegExp(r'\n'), " "))),
DropdownMenuItem(value: [for (var tl in uniqueTL) if (tl.esttracc != null) FlSpot(tl.gamesPlayed.toDouble(), tl.esttracc!)], child: Text(t.statCellNum.accOfEst.replaceAll(RegExp(r'\n'), " "))),
DropdownMenuItem(value: [for (var tl in uniqueTL) if (tl.playstyle != null) FlSpot(tl.gamesPlayed.toDouble(), tl.playstyle!.opener)], child: const Text("Opener")),
DropdownMenuItem(value: [for (var tl in uniqueTL) if (tl.playstyle != null) FlSpot(tl.gamesPlayed.toDouble(), tl.playstyle!.plonk)], child: const Text("Plonk")),
DropdownMenuItem(value: [for (var tl in uniqueTL) if (tl.playstyle != null) FlSpot(tl.gamesPlayed.toDouble(), tl.playstyle!.infds)], child: const Text("Inf. DS")),
DropdownMenuItem(value: [for (var tl in uniqueTL) if (tl.playstyle != null) FlSpot(tl.gamesPlayed.toDouble(), tl.playstyle!.stride)], child: const Text("Stride")),
];
}else{ }else{
compareWith = null; compareWith = null;
chartsData = []; chartsData = [];
@ -393,8 +417,7 @@ class _MainState extends State<MainView> with TickerProviderStateMixin {
return notification.depth == 0; return notification.depth == 0;
}, },
child: NestedScrollView( child: NestedScrollView(
scrollBehavior: ScrollConfiguration.of(context).copyWith(scrollbars: false), scrollBehavior: ScrollConfiguration.of(context).copyWith(scrollbars: false, physics: const AlwaysScrollableScrollPhysics()),
physics: const AlwaysScrollableScrollPhysics(),
controller: _scrollController, controller: _scrollController,
headerSliverBuilder: (context, value) { headerSliverBuilder: (context, value) {
return [ return [
@ -448,10 +471,10 @@ class _MainState extends State<MainView> with TickerProviderStateMixin {
), ),
SizedBox( SizedBox(
width: 450, width: 450,
child: _TLRecords(userID: snapshot.data![0].userId, changePlayer: changePlayer, data: snapshot.data![3], wasActiveInTL: snapshot.data![0].tlSeason1.gamesPlayed > 0, oldMathcesHere: _TLHistoryWasFetched) child: _TLRecords(userID: snapshot.data![0].userId, changePlayer: changePlayer, data: snapshot.data![3], wasActiveInTL: snapshot.data![0].tlSeason1.gamesPlayed > 0, oldMathcesHere: _TLHistoryWasFetched, separateScrollController: true,)
), ),
],), ],),
_History(chartsData: chartsData, changePlayer: changePlayer, userID: _searchFor, update: _justUpdate, wasActiveInTL: snapshot.data![0].tlSeason1.gamesPlayed > 0), _History(chartsData: chartsData, chartsDataGamesPlayed: chartsDataGamesPlayed, changePlayer: changePlayer, userID: _searchFor, update: _justUpdate, wasActiveInTL: snapshot.data![0].tlSeason1.gamesPlayed > 0),
_TwoRecordsThingy(sprint: snapshot.data![1]['sprint'], blitz: snapshot.data![1]['blitz'], rank: snapshot.data![0].tlSeason1.percentileRank,), _TwoRecordsThingy(sprint: snapshot.data![1]['sprint'], blitz: snapshot.data![1]['blitz'], rank: snapshot.data![0].tlSeason1.percentileRank,),
_OtherThingy(zen: snapshot.data![1]['zen'], bio: snapshot.data![0].bio, distinguishment: snapshot.data![0].distinguishment, newsletter: snapshot.data![6],) _OtherThingy(zen: snapshot.data![1]['zen'], bio: snapshot.data![0].bio, distinguishment: snapshot.data![0].distinguishment, newsletter: snapshot.data![6],)
] : [ ] : [
@ -466,7 +489,7 @@ class _MainState extends State<MainView> with TickerProviderStateMixin {
lbPositions: meAmongEveryone lbPositions: meAmongEveryone
), ),
_TLRecords(userID: snapshot.data![0].userId, changePlayer: changePlayer, data: snapshot.data![3], wasActiveInTL: snapshot.data![0].tlSeason1.gamesPlayed > 0, oldMathcesHere: _TLHistoryWasFetched), _TLRecords(userID: snapshot.data![0].userId, changePlayer: changePlayer, data: snapshot.data![3], wasActiveInTL: snapshot.data![0].tlSeason1.gamesPlayed > 0, oldMathcesHere: _TLHistoryWasFetched),
_History(chartsData: chartsData, changePlayer: changePlayer, userID: _searchFor, update: _justUpdate, wasActiveInTL: snapshot.data![0].tlSeason1.gamesPlayed > 0), _History(chartsData: chartsData, chartsDataGamesPlayed: chartsDataGamesPlayed, changePlayer: changePlayer, userID: _searchFor, update: _justUpdate, wasActiveInTL: snapshot.data![0].tlSeason1.gamesPlayed > 0),
_RecordThingy(record: snapshot.data![1]['sprint'], rank: snapshot.data![0].tlSeason1.percentileRank), _RecordThingy(record: snapshot.data![1]['sprint'], rank: snapshot.data![0].tlSeason1.percentileRank),
_RecordThingy(record: snapshot.data![1]['blitz'], rank: snapshot.data![0].tlSeason1.percentileRank), _RecordThingy(record: snapshot.data![1]['blitz'], rank: snapshot.data![0].tlSeason1.percentileRank),
_OtherThingy(zen: snapshot.data![1]['zen'], bio: snapshot.data![0].bio, distinguishment: snapshot.data![0].distinguishment, newsletter: snapshot.data![6],) _OtherThingy(zen: snapshot.data![1]['zen'], bio: snapshot.data![0].bio, distinguishment: snapshot.data![0].distinguishment, newsletter: snapshot.data![6],)
@ -664,10 +687,11 @@ class _TLRecords extends StatelessWidget {
final List<TetraLeagueAlphaRecord> data; final List<TetraLeagueAlphaRecord> data;
final bool wasActiveInTL; final bool wasActiveInTL;
final bool oldMathcesHere; final bool oldMathcesHere;
final bool separateScrollController;
/// Widget, that displays Tetra League records. /// Widget, that displays Tetra League records.
/// Accepts list of TL records ([data]) and [userID] of player from the view /// Accepts list of TL records ([data]) and [userID] of player from the view
const _TLRecords({required this.userID, required this.changePlayer, required this.data, required this.wasActiveInTL, required this.oldMathcesHere}); const _TLRecords({required this.userID, required this.changePlayer, required this.data, required this.wasActiveInTL, required this.oldMathcesHere, this.separateScrollController = false});
@override @override
Widget build(BuildContext context) { Widget build(BuildContext context) {
@ -685,7 +709,7 @@ class _TLRecords extends StatelessWidget {
int length = data.length; int length = data.length;
return ListView.builder( return ListView.builder(
physics: const AlwaysScrollableScrollPhysics(), physics: const AlwaysScrollableScrollPhysics(),
controller: ScrollController(), controller: separateScrollController ? ScrollController() : null,
itemCount: oldMathcesHere ? length : length + 1, itemCount: oldMathcesHere ? length : length + 1,
itemBuilder: (BuildContext context, int index) { itemBuilder: (BuildContext context, int index) {
if (index == length) { if (index == length) {
@ -708,7 +732,6 @@ class _TLRecords extends StatelessWidget {
) )
), ),
child: ListTile( child: ListTile(
// tileColor: data[index].endContext.firstWhere((element) => element.userId == userID).success ? Colors.green[900] : Colors.red[900],
leading: Text("${data[index].endContext.firstWhere((element) => element.userId == userID).points} : ${data[index].endContext.firstWhere((element) => element.userId != userID).points}", leading: Text("${data[index].endContext.firstWhere((element) => element.userId == userID).points} : ${data[index].endContext.firstWhere((element) => element.userId != userID).points}",
style: bigScreen ? const TextStyle(fontFamily: "Eurostile Round Extended", fontSize: 28, shadows: textShadow) : const TextStyle(fontSize: 28, shadows: textShadow)), style: bigScreen ? const TextStyle(fontFamily: "Eurostile Round Extended", fontSize: 28, shadows: textShadow) : const TextStyle(fontSize: 28, shadows: textShadow)),
title: Text("vs. ${data[index].endContext.firstWhere((element) => element.userId != userID).username}"), title: Text("vs. ${data[index].endContext.firstWhere((element) => element.userId != userID).username}"),
@ -730,6 +753,7 @@ class _TLRecords extends StatelessWidget {
class _History extends StatelessWidget{ class _History extends StatelessWidget{
final List<DropdownMenuItem<List<FlSpot>>> chartsData; final List<DropdownMenuItem<List<FlSpot>>> chartsData;
final List<DropdownMenuItem<List<FlSpot>>> chartsDataGamesPlayed;
final String userID; final String userID;
final Function update; final Function update;
final Function changePlayer; final Function changePlayer;
@ -737,7 +761,7 @@ class _History extends StatelessWidget{
/// Widget, that can show history of some stat of the player on the graph. /// Widget, that can show history of some stat of the player on the graph.
/// Requires player [states], which is list of states and function [update], which rebuild widgets /// Requires player [states], which is list of states and function [update], which rebuild widgets
const _History({required this.chartsData, required this.userID, required this.changePlayer, required this.update, required this.wasActiveInTL}); const _History({required this.chartsData, required this.chartsDataGamesPlayed, required this.userID, required this.changePlayer, required this.update, required this.wasActiveInTL});
@override @override
Widget build(BuildContext context) { Widget build(BuildContext context) {
@ -763,14 +787,24 @@ class _History extends StatelessWidget{
Wrap( Wrap(
spacing: 20, spacing: 20,
children: [ children: [
// DropdownButton( Row(
// items: [DropdownMenuItem(child: Text("Chart"), value: false), DropdownMenuItem(child: Text("Table"), value: true)], mainAxisSize: MainAxisSize.min,
// value: _showHistoryAsTable, children: [
// onChanged: (value) { const Padding(padding: EdgeInsets.all(8.0), child: Text("X:", style: TextStyle(fontSize: 22))),
// _showHistoryAsTable = value!; DropdownButton(
// update(); items: const [DropdownMenuItem(value: false, child: Text("Date & Time")), DropdownMenuItem(value: true, child: Text("Games Played"))],
// } value: _gamesPlayedInsteadOfDateAndTime,
// ), onChanged: (value) {
_gamesPlayedInsteadOfDateAndTime = value!;
update();
}
),
],
),
Row(
mainAxisSize: MainAxisSize.min,
children: [
const Padding(padding: EdgeInsets.all(8.0), child: Text("Y:", style: TextStyle(fontSize: 22))),
DropdownButton( DropdownButton(
items: chartsData, items: chartsData,
value: chartsData[_chartsIndex].value, value: chartsData[_chartsIndex].value,
@ -781,8 +815,10 @@ class _History extends StatelessWidget{
), ),
], ],
), ),
if(chartsData[_chartsIndex].value!.length > 1 && !_showHistoryAsTable) _HistoryChartThigy(data: chartsData[_chartsIndex].value!, yAxisTitle: _historyShortTitles[_chartsIndex], bigScreen: bigScreen, leftSpace: bigScreen? 80 : 45, yFormat: bigScreen? f2 : NumberFormat.compact(),) ],
else if (chartsData[_chartsIndex].value!.length <= 1 && !_showHistoryAsTable) Center(child: Column( ),
if(chartsData[_chartsIndex].value!.length > 1) _HistoryChartThigy(data: _gamesPlayedInsteadOfDateAndTime ? chartsDataGamesPlayed[_chartsIndex].value! : chartsData[_chartsIndex].value!, yAxisTitle: _historyShortTitles[_chartsIndex], bigScreen: bigScreen, leftSpace: bigScreen? 80 : 45, yFormat: bigScreen? f2 : NumberFormat.compact(), xFormat: NumberFormat.compact())
else if (chartsData[_chartsIndex].value!.length <= 1) Center(child: Column(
mainAxisSize: MainAxisSize.min, mainAxisSize: MainAxisSize.min,
children: [ children: [
Text(t.notEnoughData, style: const TextStyle(fontFamily: "Eurostile Round", fontSize: 28)), Text(t.notEnoughData, style: const TextStyle(fontFamily: "Eurostile Round", fontSize: 28)),
@ -790,10 +826,6 @@ class _History extends StatelessWidget{
if (wasActiveInTL) TextButton(onPressed: (){changePlayer(userID, fetchHistory: true);}, child: Text(t.fetchAndsaveTLHistory)) if (wasActiveInTL) TextButton(onPressed: (){changePlayer(userID, fetchHistory: true);}, child: Text(t.fetchAndsaveTLHistory))
], ],
)) ))
// else if (_showHistoryAsTable) Padding(
// padding: const EdgeInsets.fromLTRB(8.0, 0.0, 8.0, 0.0),
// child: _HistoryTableThingy(tableData),
// )
], ],
), ),
), ),
@ -807,11 +839,12 @@ class _HistoryChartThigy extends StatefulWidget{
final bool bigScreen; final bool bigScreen;
final double leftSpace; final double leftSpace;
final NumberFormat yFormat; final NumberFormat yFormat;
final NumberFormat? xFormat;
/// Implements graph for the _History widget. Requires [data] which is a list of dots for the graph. [yAxisTitle] used to keep track of changes. /// Implements graph for the _History widget. Requires [data] which is a list of dots for the graph. [yAxisTitle] used to keep track of changes.
/// [bigScreen] tells if screen wide enough, [leftSpace] sets size, reserved for titles on the left from the graph and [yFormat] sets number format /// [bigScreen] tells if screen wide enough, [leftSpace] sets size, reserved for titles on the left from the graph and [yFormat] sets number format
/// for left titles /// for left titles
const _HistoryChartThigy({required this.data, required this.yAxisTitle, required this.bigScreen, required this.leftSpace, required this.yFormat}); const _HistoryChartThigy({required this.data, required this.yAxisTitle, required this.bigScreen, required this.leftSpace, required this.yFormat, this.xFormat});
@override @override
State<_HistoryChartThigy> createState() => _HistoryChartThigyState(); State<_HistoryChartThigy> createState() => _HistoryChartThigyState();
@ -819,6 +852,7 @@ class _HistoryChartThigy extends StatefulWidget{
class _HistoryChartThigyState extends State<_HistoryChartThigy> { class _HistoryChartThigyState extends State<_HistoryChartThigy> {
late String previousAxisTitle; late String previousAxisTitle;
late bool previousGamesPlayedInsteadOfDateAndTime;
late double minX; late double minX;
late double maxX; late double maxX;
late double minY; late double minY;
@ -840,6 +874,7 @@ class _HistoryChartThigyState extends State<_HistoryChartThigy> {
maxX = widget.data.last.x; maxX = widget.data.last.x;
setMinMaxY(); setMinMaxY();
previousAxisTitle = widget.yAxisTitle; previousAxisTitle = widget.yAxisTitle;
previousGamesPlayedInsteadOfDateAndTime = _gamesPlayedInsteadOfDateAndTime;
actualMaxY = maxY; actualMaxY = maxY;
actualMinY = minY; actualMinY = minY;
recalculateScales(); recalculateScales();
@ -945,15 +980,19 @@ class _HistoryChartThigyState extends State<_HistoryChartThigy> {
@override @override
Widget build(BuildContext context) { Widget build(BuildContext context) {
GlobalKey graphKey = GlobalKey(); GlobalKey graphKey = GlobalKey();
double xInterval = widget.bigScreen ? max(1, xScale / 6) : max(1, xScale / 3); // how far away xTitles should be between each other if ((previousAxisTitle != widget.yAxisTitle) || (previousGamesPlayedInsteadOfDateAndTime != _gamesPlayedInsteadOfDateAndTime)) {
minX = widget.data.first.x;
maxX = widget.data.last.x;
recalculateScales();
setMinMaxY();
previousAxisTitle = widget.yAxisTitle;
previousGamesPlayedInsteadOfDateAndTime = _gamesPlayedInsteadOfDateAndTime;
setState((){});
}
double xInterval = widget.bigScreen ? max(1, xScale / 8) : max(1, xScale / 4); // how far away xTitles should be between each other
EdgeInsets padding = widget.bigScreen ? const EdgeInsets.fromLTRB(40, 30, 40, 30) : const EdgeInsets.fromLTRB(0, 40, 16, 48); EdgeInsets padding = widget.bigScreen ? const EdgeInsets.fromLTRB(40, 30, 40, 30) : const EdgeInsets.fromLTRB(0, 40, 16, 48);
double graphStartX = padding.left+widget.leftSpace; double graphStartX = padding.left+widget.leftSpace;
double graphEndX = MediaQuery.sizeOf(context).width - padding.right; double graphEndX = MediaQuery.sizeOf(context).width - padding.right;
if (previousAxisTitle != widget.yAxisTitle) {
setMinMaxY();
recalculateScales();
previousAxisTitle = widget.yAxisTitle;
}
return SizedBox( return SizedBox(
width: MediaQuery.of(context).size.width, width: MediaQuery.of(context).size.width,
height: MediaQuery.of(context).size.height - 104, height: MediaQuery.of(context).size.height - 104,
@ -1025,7 +1064,7 @@ class _HistoryChartThigyState extends State<_HistoryChartThigy> {
bottomTitles: AxisTitles(sideTitles: SideTitles(interval: xInterval, showTitles: true, reservedSize: 30, getTitlesWidget: (double value, TitleMeta meta){ bottomTitles: AxisTitles(sideTitles: SideTitles(interval: xInterval, showTitles: true, reservedSize: 30, getTitlesWidget: (double value, TitleMeta meta){
return value != meta.min && value != meta.max ? SideTitleWidget( return value != meta.min && value != meta.max ? SideTitleWidget(
axisSide: meta.axisSide, axisSide: meta.axisSide,
child: Text(DateFormat.yMMMd(LocaleSettings.currentLocale.languageCode).format(DateTime.fromMillisecondsSinceEpoch(value.floor()))), child: Text(widget.xFormat != null && _gamesPlayedInsteadOfDateAndTime ? widget.xFormat!.format(value.round()) : DateFormat.yMMMd(LocaleSettings.currentLocale.languageCode).format(DateTime.fromMillisecondsSinceEpoch(value.floor()))),
) : Container(); ) : Container();
})), })),
leftTitles: AxisTitles(sideTitles: SideTitles(showTitles: true, reservedSize: widget.leftSpace, getTitlesWidget: (double value, TitleMeta meta){ leftTitles: AxisTitles(sideTitles: SideTitles(showTitles: true, reservedSize: widget.leftSpace, getTitlesWidget: (double value, TitleMeta meta){
@ -1048,7 +1087,7 @@ class _HistoryChartThigyState extends State<_HistoryChartThigy> {
} else { } else {
hoveredPointId = touchResponse!.lineBarSpots!.first.spotIndex; hoveredPointId = touchResponse!.lineBarSpots!.first.spotIndex;
headerTooltip = "${f4.format(touchResponse.lineBarSpots!.first.y)} ${widget.yAxisTitle}"; headerTooltip = "${f4.format(touchResponse.lineBarSpots!.first.y)} ${widget.yAxisTitle}";
footerTooltip = _dateFormat.format(DateTime.fromMillisecondsSinceEpoch(touchResponse.lineBarSpots!.first.x.floor())); footerTooltip = _gamesPlayedInsteadOfDateAndTime ? "${f0.format(touchResponse.lineBarSpots!.first.x)} games played" : _dateFormat.format(DateTime.fromMillisecondsSinceEpoch(touchResponse.lineBarSpots!.first.x.floor()));
} }
}); });
} }
@ -1207,7 +1246,7 @@ class _TwoRecordsThingy extends StatelessWidget {
RichText( RichText(
text: TextSpan( text: TextSpan(
text: "", text: "",
style: const TextStyle(fontFamily: "Eurostile Round Extended", fontSize: 36, fontWeight: FontWeight.w500), style: const TextStyle(fontFamily: "Eurostile Round Extended", fontSize: 36, fontWeight: FontWeight.w500, color: Colors.white),
children: [ children: [
TextSpan(text: blitz != null ? NumberFormat.decimalPattern().format(blitz!.endContext!.score) : "---"), TextSpan(text: blitz != null ? NumberFormat.decimalPattern().format(blitz!.endContext!.score) : "---"),
//WidgetSpan(child: Image.asset("res/icons/kagari.png", height: 48)) //WidgetSpan(child: Image.asset("res/icons/kagari.png", height: 48))
@ -1295,6 +1334,7 @@ class _RecordThingy extends StatelessWidget {
builder: (context, constraints) { builder: (context, constraints) {
bool bigScreen = constraints.maxWidth > 768; bool bigScreen = constraints.maxWidth > 768;
return SingleChildScrollView( return SingleChildScrollView(
controller: _scrollController,
child: Padding( child: Padding(
padding: const EdgeInsets.only(top: 8.0), padding: const EdgeInsets.only(top: 8.0),
child: Column( child: Column(

View File

@ -54,7 +54,8 @@ class RanksAverages extends State<RankAveragesView> {
return ListTile( return ListTile(
leading: Image.asset("res/tetrio_tl_alpha_ranks/${keys[index]}.png", height: 48), leading: Image.asset("res/tetrio_tl_alpha_ranks/${keys[index]}.png", height: 48),
title: Text(t.players(n: averages[keys[index]]?[1]["players"]), style: const TextStyle(fontFamily: "Eurostile Round Extended")), title: Text(t.players(n: averages[keys[index]]?[1]["players"]), style: const TextStyle(fontFamily: "Eurostile Round Extended")),
subtitle: Text("${f2.format(averages[keys[index]]?[0].apm)} APM, ${f2.format(averages[keys[index]]?[0].pps)} PPS, ${f2.format(averages[keys[index]]?[0].vs)} VS, ${f2.format(averages[keys[index]]?[0].nerdStats.app)} APP, ${f2.format(averages[keys[index]]?[0].nerdStats.vsapm)} VS/APM"), subtitle: Text("${f2.format(averages[keys[index]]?[0].apm)} APM, ${f2.format(averages[keys[index]]?[0].pps)} PPS, ${f2.format(averages[keys[index]]?[0].vs)} VS, ${f2.format(averages[keys[index]]?[0].nerdStats.app)} APP, ${f2.format(averages[keys[index]]?[0].nerdStats.vsapm)} VS/APM",
style: TextStyle(fontFamily: "Eurostile Round Condensed", color: Colors.grey)),
trailing: Text("${f2.format(averages[keys[index]]?[1]["toEnterTR"])} TR", style: bigScreen ? const TextStyle(fontSize: 28) : null), trailing: Text("${f2.format(averages[keys[index]]?[1]["toEnterTR"])} TR", style: bigScreen ? const TextStyle(fontSize: 28) : null),
onTap: (){ onTap: (){
if (averages[keys[index]]?[1]["players"] > 0) { if (averages[keys[index]]?[1]["players"] > 0) {

View File

@ -175,7 +175,8 @@ class TLLeaderboardState extends State<TLLeaderboardView> {
return ListTile( return ListTile(
leading: Text((index+1).toString(), style: bigScreen ? const TextStyle(fontFamily: "Eurostile Round Extended", fontSize: 28) : null), leading: Text((index+1).toString(), style: bigScreen ? const TextStyle(fontFamily: "Eurostile Round Extended", fontSize: 28) : null),
title: Text(allPlayers[index].username, style: const TextStyle(fontFamily: "Eurostile Round Extended")), title: Text(allPlayers[index].username, style: const TextStyle(fontFamily: "Eurostile Round Extended")),
subtitle: Text(_sortBy == Stats.tr ? "${f2.format(allPlayers[index].apm)} APM, ${f2.format(allPlayers[index].pps)} PPS, ${f2.format(allPlayers[index].vs)} VS, ${f2.format(allPlayers[index].nerdStats.app)} APP, ${f2.format(allPlayers[index].nerdStats.vsapm)} VS/APM" : "${_f4.format(allPlayers[index].getStatByEnum(_sortBy))} ${chartsShortTitles[_sortBy]}"), subtitle: Text(_sortBy == Stats.tr ? "${f2.format(allPlayers[index].apm)} APM, ${f2.format(allPlayers[index].pps)} PPS, ${f2.format(allPlayers[index].vs)} VS, ${f2.format(allPlayers[index].nerdStats.app)} APP, ${f2.format(allPlayers[index].nerdStats.vsapm)} VS/APM" : "${_f4.format(allPlayers[index].getStatByEnum(_sortBy))} ${chartsShortTitles[_sortBy]}",
style: TextStyle(fontFamily: "Eurostile Round Condensed", color: _sortBy == Stats.tr ? Colors.grey : null)),
trailing: Row( trailing: Row(
mainAxisSize: MainAxisSize.min, mainAxisSize: MainAxisSize.min,
children: [ children: [

View File

@ -70,7 +70,7 @@ class TlMatchResultState extends State<TlMatchResultView> {
timeWeightedStatsAvaliable = true; timeWeightedStatsAvaliable = true;
if (snapshot.connectionState != ConnectionState.done) return const LinearProgressIndicator(); if (snapshot.connectionState != ConnectionState.done) return const LinearProgressIndicator();
if (!snapshot.hasError){ if (!snapshot.hasError){
if (rounds.indexWhere((element) => element.value == -2) == -1) rounds.insert(1, const DropdownMenuItem(value: -2, child: Text("timeWeightedStats"))); if (rounds.indexWhere((element) => element.value == -2) == -1) rounds.insert(1, DropdownMenuItem(value: -2, child: Text(t.timeWeightedmatch)));
greenSidePlayer = snapshot.data!.endcontext.indexWhere((element) => element.userId == widget.initPlayerId); greenSidePlayer = snapshot.data!.endcontext.indexWhere((element) => element.userId == widget.initPlayerId);
redSidePlayer = snapshot.data!.endcontext.indexWhere((element) => element.userId != widget.initPlayerId); redSidePlayer = snapshot.data!.endcontext.indexWhere((element) => element.userId != widget.initPlayerId);
if (roundSelector.isNegative){ if (roundSelector.isNegative){
@ -81,7 +81,6 @@ class TlMatchResultState extends State<TlMatchResultView> {
readableTime = "${t.roundLength}: ${time.inMinutes}:${secs.format(time.inMicroseconds /1000000 % 60)}\n${t.winner}: ${snapshot.data!.roundWinners[roundSelector][1]}"; readableTime = "${t.roundLength}: ${time.inMinutes}:${secs.format(time.inMicroseconds /1000000 % 60)}\n${t.winner}: ${snapshot.data!.roundWinners[roundSelector][1]}";
} }
}else{ }else{
timeWeightedStatsAvaliable = false;
switch (snapshot.error.runtimeType){ switch (snapshot.error.runtimeType){
case ReplayNotAvalable: case ReplayNotAvalable:
reason = t.matchIsTooOld; reason = t.matchIsTooOld;
@ -509,7 +508,7 @@ class TlMatchResultState extends State<TlMatchResultView> {
RichText( RichText(
text: TextSpan( text: TextSpan(
text: "${time.inMinutes}:${NumberFormat("00", LocaleSettings.currentLocale.languageCode).format(time.inSeconds%60)}", text: "${time.inMinutes}:${NumberFormat("00", LocaleSettings.currentLocale.languageCode).format(time.inSeconds%60)}",
style: const TextStyle(fontFamily: "Eurostile Round Extended", fontSize: 28, fontWeight: FontWeight.w500), style: const TextStyle(fontFamily: "Eurostile Round Extended", fontSize: 28, fontWeight: FontWeight.w500, color: Colors.white),
children: [TextSpan(text: ".${NumberFormat("000", LocaleSettings.currentLocale.languageCode).format(time.inMilliseconds%1000)}", style: const TextStyle(fontFamily: "Eurostile Round", fontSize: 14, fontWeight: FontWeight.w100))] children: [TextSpan(text: ".${NumberFormat("000", LocaleSettings.currentLocale.languageCode).format(time.inMilliseconds%1000)}", style: const TextStyle(fontFamily: "Eurostile Round", fontSize: 14, fontWeight: FontWeight.w100))]
), ),
) )
@ -533,6 +532,7 @@ class TlMatchResultState extends State<TlMatchResultView> {
reason = snapshot.error.toString(); reason = snapshot.error.toString();
break; break;
} }
timeWeightedStatsAvaliable = false;
return Column( return Column(
crossAxisAlignment: CrossAxisAlignment.start, crossAxisAlignment: CrossAxisAlignment.start,
children: [ children: [
@ -553,15 +553,15 @@ class TlMatchResultState extends State<TlMatchResultView> {
if (widget.record.ownId != widget.record.replayId) Column( if (widget.record.ownId != widget.record.replayId) Column(
crossAxisAlignment: CrossAxisAlignment.end, crossAxisAlignment: CrossAxisAlignment.end,
children: [ children: [
const Text("Number of rounds"), Text(t.numberOfRounds),
RichText( RichText(
text: TextSpan( text: TextSpan(
text: widget.record.endContext.first.secondaryTracking.length > 0 ? widget.record.endContext.first.secondaryTracking.length.toString() : "---", text: widget.record.endContext.first.secondaryTracking.isNotEmpty ? widget.record.endContext.first.secondaryTracking.length.toString() : "---",
style: TextStyle( style: TextStyle(
fontFamily: "Eurostile Round Extended", fontFamily: "Eurostile Round Extended",
fontSize: 28, fontSize: 28,
fontWeight: FontWeight.w500, fontWeight: FontWeight.w500,
color: widget.record.endContext.first.secondaryTracking.length == 0 ? Colors.grey : null color: widget.record.endContext.first.secondaryTracking.isEmpty ? Colors.grey : Colors.white
), ),
), ),
) )
@ -570,18 +570,16 @@ class TlMatchResultState extends State<TlMatchResultView> {
OverflowBar( OverflowBar(
alignment: MainAxisAlignment.spaceEvenly, alignment: MainAxisAlignment.spaceEvenly,
children: <Widget>[ children: <Widget>[
TextButton( child: const Text('Match stats'), TextButton( style: roundSelector == -1 ? ButtonStyle(backgroundColor: MaterialStatePropertyAll(Colors.grey.shade900)) : null,
style: roundSelector == -1 ? ButtonStyle(backgroundColor: MaterialStatePropertyAll(Colors.grey.shade900)) : null,
onPressed: () { onPressed: () {
roundSelector = -1; roundSelector = -1;
setState(() {}); setState(() {});
}), }, child: Text(t.matchStats)),
TextButton( child: const Text('Time-weighted match stats'), TextButton( style: roundSelector == -2 ? ButtonStyle(backgroundColor: MaterialStatePropertyAll(Colors.grey.shade900)) : null,
style: roundSelector == -2 ? ButtonStyle(backgroundColor: MaterialStatePropertyAll(Colors.grey.shade900)) : null,
onPressed: timeWeightedStatsAvaliable ? () { onPressed: timeWeightedStatsAvaliable ? () {
roundSelector = -2; roundSelector = -2;
setState(() {}); setState(() {});
} : null) , } : null, child: Text(t.timeWeightedmatchStats)) ,
//TextButton( child: const Text('Button 3'), onPressed: () {}), //TextButton( child: const Text('Button 3'), onPressed: () {}),
], ],
) )
@ -624,7 +622,7 @@ class TlMatchResultState extends State<TlMatchResultView> {
leading:RichText( leading:RichText(
text: TextSpan( text: TextSpan(
text: "${time.inMinutes}:${NumberFormat("00", LocaleSettings.currentLocale.languageCode).format(time.inSeconds%60)}", text: "${time.inMinutes}:${NumberFormat("00", LocaleSettings.currentLocale.languageCode).format(time.inSeconds%60)}",
style: const TextStyle(fontFamily: "Eurostile Round", fontSize: 22, fontWeight: FontWeight.w500), style: const TextStyle(fontFamily: "Eurostile Round", fontSize: 22, fontWeight: FontWeight.w500, color: Colors.white),
children: [TextSpan(text: ".${NumberFormat("000", LocaleSettings.currentLocale.languageCode).format(time.inMilliseconds%1000)}", style: const TextStyle(fontFamily: "Eurostile Round", fontSize: 14, fontWeight: FontWeight.w100))] children: [TextSpan(text: ".${NumberFormat("000", LocaleSettings.currentLocale.languageCode).format(time.inMilliseconds%1000)}", style: const TextStyle(fontFamily: "Eurostile Round", fontSize: 14, fontWeight: FontWeight.w100))]
), ),
), ),
@ -682,7 +680,7 @@ class TlMatchResultState extends State<TlMatchResultView> {
} }
Widget getMainWidget(double viewportWidth) { Widget getMainWidget(double viewportWidth) {
if (viewportWidth <= 1024) { if (viewportWidth <= 1200) {
return Center( return Center(
child: Container( child: Container(
constraints: const BoxConstraints(maxWidth: 768), constraints: const BoxConstraints(maxWidth: 768),
@ -692,9 +690,8 @@ class TlMatchResultState extends State<TlMatchResultView> {
} else { } else {
return Row( return Row(
mainAxisAlignment: MainAxisAlignment.center, mainAxisAlignment: MainAxisAlignment.center,
//mainAxisSize: MainAxisSize.min,
children: [ children: [
Container( SizedBox(
width: 768, width: 768,
child: buildComparison(true, false) child: buildComparison(true, false)
), ),
@ -729,28 +726,7 @@ class TlMatchResultState extends State<TlMatchResultView> {
onSelected: (value) async { onSelected: (value) async {
switch (value) { switch (value) {
case 1: case 1:
if (kIsWeb){ await launchInBrowser(Uri.parse("https://inoue.szy.lol/api/replay/${widget.record.replayId}"));
// final _base64 = base64Encode([1,2,3,4,5]);
// final anchor = AnchorElement(href: 'data:application/octet-stream;base64,$_base64')..target = 'blank';
//final anchor = AnchorElement(href: 'https://inoue.szy.lol/api/replay/${widget.record.replayId}')..target = 'blank';
//anchor.download = "${widget.record.replayId}.ttrm";
//document.body!.append(anchor);
//anchor.click();
//anchor.remove();
} else{
try{
String path = await teto.saveReplay(widget.record.replayId);
ScaffoldMessenger.of(context).showSnackBar(SnackBar(content: Text(t.replaySaved(path: path))));
} on TetrioReplayAlreadyExist{
ScaffoldMessenger.of(context).showSnackBar(SnackBar(content: Text(t.errors.replayAlreadySaved)));
} on SzyNotFound {
ScaffoldMessenger.of(context).showSnackBar(SnackBar(content: Text(t.errors.replayExpired)));
} on SzyForbidden {
ScaffoldMessenger.of(context).showSnackBar(SnackBar(content: Text(t.errors.replayRejected)));
} on SzyTooManyRequests {
ScaffoldMessenger.of(context).showSnackBar(SnackBar(content: Text(t.errors.tooManyRequests)));
}
}
break; break;
case 2: case 2:
await launchInBrowser(Uri.parse("https://tetr.io/#r:${widget.record.replayId}")); await launchInBrowser(Uri.parse("https://tetr.io/#r:${widget.record.replayId}"));

View File

@ -2,6 +2,7 @@ import 'package:flutter/material.dart';
import 'package:syncfusion_flutter_gauges/gauges.dart'; import 'package:syncfusion_flutter_gauges/gauges.dart';
import 'package:tetra_stats/data_objects/tetrio.dart'; import 'package:tetra_stats/data_objects/tetrio.dart';
import 'package:tetra_stats/gen/strings.g.dart'; import 'package:tetra_stats/gen/strings.g.dart';
import 'package:tetra_stats/utils/colors_functions.dart';
import 'package:tetra_stats/utils/numers_formats.dart'; import 'package:tetra_stats/utils/numers_formats.dart';
import 'package:tetra_stats/widgets/tl_thingy.dart'; import 'package:tetra_stats/widgets/tl_thingy.dart';
@ -98,7 +99,7 @@ class GaugetNum extends StatelessWidget {
oldPlayerStat! < playerStat ? Colors.redAccent : Colors.greenAccent oldPlayerStat! < playerStat ? Colors.redAccent : Colors.greenAccent
),), ),),
if ((oldTl != null && oldTl!.gamesPlayed > 0) && pos != null) const TextSpan(text: ""), 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}") if (pos != null) TextSpan(text: pos!.position >= 1000 ? "${t.top} ${f2.format(pos!.percentage*100)}%" : "${pos!.position}", style: TextStyle(color: getColorOfRank(pos!.position)))
] ]
), ),
), ),

View File

@ -1,10 +1,7 @@
import 'package:fl_chart/fl_chart.dart'; import 'package:fl_chart/fl_chart.dart';
import 'package:flutter/material.dart'; import 'package:flutter/material.dart';
import 'package:intl/intl.dart';
import 'package:tetra_stats/data_objects/tetrio.dart'; import 'package:tetra_stats/data_objects/tetrio.dart';
import 'package:tetra_stats/gen/strings.g.dart'; import 'package:tetra_stats/utils/numers_formats.dart';
final NumberFormat _f2 = NumberFormat.decimalPatternDigits(locale: LocaleSettings.currentLocale.languageCode, decimalDigits: 2);
class Graphs extends StatelessWidget{ class Graphs extends StatelessWidget{
const Graphs( const Graphs(
@ -125,13 +122,13 @@ class Graphs extends StatelessWidget{
getTitle: (index, angle) { getTitle: (index, angle) {
switch (index) { switch (index) {
case 0: case 0:
return RadarChartTitle(text: 'Opener\n${_f2.format(playstyle.opener)}', angle: 0, positionPercentageOffset: 0.05); return RadarChartTitle(text: 'Opener\n${percentage.format(playstyle.opener)}', angle: 0, positionPercentageOffset: 0.05);
case 1: case 1:
return RadarChartTitle(text: 'Stride\n${_f2.format(playstyle.stride)}', angle: 0, positionPercentageOffset: 0.05); return RadarChartTitle(text: 'Stride\n${percentage.format(playstyle.stride)}', angle: 0, positionPercentageOffset: 0.05);
case 2: case 2:
return RadarChartTitle(text: 'Inf Ds\n${_f2.format(playstyle.infds)}', angle: angle + 180, positionPercentageOffset: 0.05); return RadarChartTitle(text: 'Inf Ds\n${percentage.format(playstyle.infds)}', angle: angle + 180, positionPercentageOffset: 0.05);
case 3: case 3:
return RadarChartTitle(text: 'Plonk\n${_f2.format(playstyle.plonk)}', angle: 0, positionPercentageOffset: 0.05); return RadarChartTitle(text: 'Plonk\n${percentage.format(playstyle.plonk)}', angle: 0, positionPercentageOffset: 0.05);
default: default:
return const RadarChartTitle(text: ''); return const RadarChartTitle(text: '');
} }

View File

@ -15,7 +15,7 @@ class LineclearsThingy extends StatelessWidget{
return Wrap( return Wrap(
spacing: 20, spacing: 20,
children: [ children: [
Container( SizedBox(
width: 150, width: 150,
child: Column( child: Column(
mainAxisSize: MainAxisSize.min, mainAxisSize: MainAxisSize.min,
@ -30,7 +30,7 @@ class LineclearsThingy extends StatelessWidget{
], ],
), ),
), ),
Container( SizedBox(
width: 150, width: 150,
child: Column( child: Column(
mainAxisSize: MainAxisSize.min, mainAxisSize: MainAxisSize.min,

View File

@ -2,6 +2,7 @@ import 'package:flutter/material.dart';
import 'package:intl/intl.dart'; import 'package:intl/intl.dart';
import 'package:tetra_stats/data_objects/tetrio.dart'; import 'package:tetra_stats/data_objects/tetrio.dart';
import 'package:tetra_stats/gen/strings.g.dart'; import 'package:tetra_stats/gen/strings.g.dart';
import 'package:tetra_stats/utils/colors_functions.dart';
import 'package:tetra_stats/utils/numers_formats.dart'; import 'package:tetra_stats/utils/numers_formats.dart';
class StatCellNum extends StatelessWidget { class StatCellNum extends StatelessWidget {
@ -70,7 +71,7 @@ class StatCellNum extends StatelessWidget {
oldPlayerStat! < playerStat ? Colors.redAccent : Colors.greenAccent oldPlayerStat! < playerStat ? Colors.redAccent : Colors.greenAccent
),), ),),
if (oldPlayerStat != null && pos != null) const TextSpan(text: ""), 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}") if (pos != null) TextSpan(text: pos!.position >= 1000 ? "${t.top} ${f2.format(pos!.percentage*100)}%" : "${pos!.position}", style: TextStyle(color: getColorOfRank(pos!.position)))
] ]
), ),
), ),

View File

@ -4,6 +4,7 @@ import 'package:tetra_stats/data_objects/tetrio.dart';
import 'package:syncfusion_flutter_gauges/gauges.dart'; import 'package:syncfusion_flutter_gauges/gauges.dart';
import 'package:tetra_stats/gen/strings.g.dart'; import 'package:tetra_stats/gen/strings.g.dart';
import 'package:tetra_stats/main.dart'; import 'package:tetra_stats/main.dart';
import 'package:tetra_stats/utils/colors_functions.dart';
import 'package:tetra_stats/utils/numers_formats.dart'; import 'package:tetra_stats/utils/numers_formats.dart';
import 'package:tetra_stats/widgets/gauget_num.dart'; import 'package:tetra_stats/widgets/gauget_num.dart';
import 'package:tetra_stats/widgets/graphs.dart'; import 'package:tetra_stats/widgets/graphs.dart';
@ -299,7 +300,7 @@ class _TLThingyState extends State<TLThingy> {
//alignment: Alignment.center, //alignment: Alignment.center,
width: bigScreen ? MediaQuery.of(context).size.width * 0.4 : MediaQuery.of(context).size.width * 0.85, width: bigScreen ? MediaQuery.of(context).size.width * 0.4 : MediaQuery.of(context).size.width * 0.85,
height: 70, height: 70,
constraints: BoxConstraints(maxWidth: 768), constraints: const BoxConstraints(maxWidth: 768),
child: Stack( child: Stack(
children: [ children: [
Positioned( Positioned(
@ -307,12 +308,12 @@ class _TLThingyState extends State<TLThingy> {
child: Column( child: Column(
crossAxisAlignment: CrossAxisAlignment.start, crossAxisAlignment: CrossAxisAlignment.start,
children: [ children: [
Text(t.statCellNum.estOfTR, style: TextStyle(height: 0.1),), Text(t.statCellNum.estOfTR, style: const TextStyle(height: 0.1),),
RichText( RichText(
text: TextSpan( text: TextSpan(
text: intf.format(currentTl.estTr!.esttr.truncate()), text: intf.format(currentTl.estTr!.esttr.truncate()),
style: TextStyle(fontFamily: "Eurostile Round Extended", fontSize: bigScreen ? 36 : 30, fontWeight: FontWeight.w500, color: Colors.white), 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: TextStyle(fontFamily: "Eurostile Round", fontSize: 14, fontWeight: FontWeight.w100))] children: [TextSpan(text: fractionfEstTR.format(currentTl.estTr!.esttr - currentTl.estTr!.esttr.truncate()).substring(1), style: const TextStyle(fontFamily: "Eurostile Round", fontSize: 14, fontWeight: FontWeight.w100))]
), ),
), ),
RichText(text: TextSpan( RichText(text: TextSpan(
@ -323,7 +324,7 @@ class _TLThingyState extends State<TLThingy> {
color: oldTl!.estTr!.esttr > currentTl.estTr!.esttr ? Colors.redAccent : Colors.greenAccent color: oldTl!.estTr!.esttr > currentTl.estTr!.esttr ? Colors.redAccent : Colors.greenAccent
),), ),),
if (oldTl?.estTr?.esttr != null && widget.lbPositions?.estTr != null) const TextSpan(text: ""), 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}"), 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: ""), if (widget.lbPositions?.estTr != null) const TextSpan(text: ""),
TextSpan(text: "Glicko: ${f2.format(currentTl.estTr!.estglicko)}") TextSpan(text: "Glicko: ${f2.format(currentTl.estTr!.estglicko)}")
] ]
@ -342,7 +343,7 @@ class _TLThingyState extends State<TLThingy> {
text: (currentTl.esttracc != null && currentTl.bestRank != "z") ? intFDiff.format(currentTl.esttracc!.truncate()) : "---", 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), style: TextStyle(fontFamily: "Eurostile Round", fontSize: bigScreen ? 36 : 30, fontWeight: FontWeight.w500, color: Colors.white),
children: [ 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: TextStyle(fontFamily: "Eurostile Round", fontSize: 14, fontWeight: FontWeight.w100)) 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))
] ]
), ),
), ),
@ -354,7 +355,7 @@ class _TLThingyState extends State<TLThingy> {
color: oldTl!.esttracc! > currentTl.esttracc! ? Colors.redAccent : Colors.greenAccent color: oldTl!.esttracc! > currentTl.esttracc! ? Colors.redAccent : Colors.greenAccent
),), ),),
if (oldTl?.esttracc != null && widget.lbPositions?.accOfEst != null) const TextSpan(text: ""), 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}") 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)))
] ]
), ),
), ),

View File

@ -339,7 +339,7 @@ class UserThingy extends StatelessWidget {
children: [ children: [
if (player.country != null) TextSpan(text: "${t.countries[player.country]}"), 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!)}'}"), TextSpan(text: "${t.playerRole[player.role]}${t.playerRoleAccount}${player.registrationTime == null ? t.wasFromBeginning : '${t.created} ${dateFormat.format(player.registrationTime!)}'}"),
if (player.supporterTier > 0) TextSpan(text: ""), 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) 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)) if (player.supporterTier > 0) TextSpan(text: player.supporterTier.toString(), style: TextStyle(color: player.supporterTier > 1 ? Colors.yellowAccent : Colors.white))
] ]

View File

@ -5,26 +5,26 @@ packages:
dependency: transitive dependency: transitive
description: description:
name: _fe_analyzer_shared name: _fe_analyzer_shared
sha256: eb376e9acf6938204f90eb3b1f00b578640d3188b4c8a8ec054f9f479af8d051 sha256: "0b2f2bd91ba804e53a61d757b986f89f1f9eaed5b11e4b2f5a2468d86d6c9fc7"
url: "https://pub.dev" url: "https://pub.dev"
source: hosted source: hosted
version: "64.0.0" version: "67.0.0"
analyzer: analyzer:
dependency: transitive dependency: transitive
description: description:
name: analyzer name: analyzer
sha256: "69f54f967773f6c26c7dcb13e93d7ccee8b17a641689da39e878d5cf13b06893" sha256: "37577842a27e4338429a1cbc32679d508836510b056f1eedf0c8d20e39c1383d"
url: "https://pub.dev" url: "https://pub.dev"
source: hosted source: hosted
version: "6.2.0" version: "6.4.1"
archive: archive:
dependency: transitive dependency: transitive
description: description:
name: archive name: archive
sha256: "7b875fd4a20b165a3084bd2d210439b22ebc653f21cea4842729c0c30c82596b" sha256: "22600aa1e926be775fa5fe7e6894e7fb3df9efda8891c73f70fb3262399a432d"
url: "https://pub.dev" url: "https://pub.dev"
source: hosted source: hosted
version: "3.4.9" version: "3.4.10"
args: args:
dependency: transitive dependency: transitive
description: description:
@ -141,10 +141,10 @@ packages:
dependency: transitive dependency: transitive
description: description:
name: dev_build name: dev_build
sha256: e476ac99174842cdb01e64c1d379d041d2150f9ad2cdd2713eb1ca1bdbf30507 sha256: e5d575f3de4b0e5f004e065e1e2d98fa012d634b61b5855216b5698ed7f1e443
url: "https://pub.dev" url: "https://pub.dev"
source: hosted source: hosted
version: "0.16.3+2" version: "0.16.4+3"
equatable: equatable:
dependency: transitive dependency: transitive
description: description:
@ -165,10 +165,10 @@ packages:
dependency: transitive dependency: transitive
description: description:
name: ffi name: ffi
sha256: "7bf0adc28a23d395f19f3f1eb21dd7cfd1dd9f8e1c50051c069122e6853bc878" sha256: "493f37e7df1804778ff3a53bd691d8692ddf69702cf4c1c1096a2e41b4779e21"
url: "https://pub.dev" url: "https://pub.dev"
source: hosted source: hosted
version: "2.1.0" version: "2.1.2"
file: file:
dependency: transitive dependency: transitive
description: description:
@ -181,34 +181,34 @@ packages:
dependency: "direct main" dependency: "direct main"
description: description:
name: file_picker name: file_picker
sha256: "4e42aacde3b993c5947467ab640882c56947d9d27342a5b6f2895b23956954a6" sha256: "1bbf65dd997458a08b531042ec3794112a6c39c07c37ff22113d2e7e4f81d4e4"
url: "https://pub.dev" url: "https://pub.dev"
source: hosted source: hosted
version: "6.1.1" version: "6.2.1"
file_selector: file_selector:
dependency: "direct main" dependency: "direct main"
description: description:
name: file_selector name: file_selector
sha256: "84eaf3e034d647859167d1f01cfe7b6352488f34c1b4932635012b202014c25b" sha256: "5019692b593455127794d5718304ff1ae15447dea286cdda9f0db2a796a1b828"
url: "https://pub.dev" url: "https://pub.dev"
source: hosted source: hosted
version: "1.0.1" version: "1.0.3"
file_selector_android: file_selector_android:
dependency: transitive dependency: transitive
description: description:
name: file_selector_android name: file_selector_android
sha256: b7556052dbcc25ef88f6eba45ab98aa5600382af8dfdabc9d644a93d97b7be7f sha256: "1cd66575f063b689e041aec836905ba7be18d76c9f0634d0d75daec825f67095"
url: "https://pub.dev" url: "https://pub.dev"
source: hosted source: hosted
version: "0.5.0+4" version: "0.5.0+7"
file_selector_ios: file_selector_ios:
dependency: transitive dependency: transitive
description: description:
name: file_selector_ios name: file_selector_ios
sha256: "2f48db7e338b2255101c35c604b7ca5ab588dce032db7fc418a2fe5f28da63f8" sha256: b015154e6d9fddbc4d08916794df170b44531798c8dd709a026df162d07ad81d
url: "https://pub.dev" url: "https://pub.dev"
source: hosted source: hosted
version: "0.5.1+7" version: "0.5.1+8"
file_selector_linux: file_selector_linux:
dependency: transitive dependency: transitive
description: description:
@ -229,10 +229,10 @@ packages:
dependency: transitive dependency: transitive
description: description:
name: file_selector_platform_interface name: file_selector_platform_interface
sha256: "0aa47a725c346825a2bd396343ce63ac00bda6eff2fbc43eabe99737dede8262" sha256: a3994c26f10378a039faa11de174d7b78eb8f79e4dd0af2a451410c1a5c3f66b
url: "https://pub.dev" url: "https://pub.dev"
source: hosted source: hosted
version: "2.6.1" version: "2.6.2"
file_selector_web: file_selector_web:
dependency: transitive dependency: transitive
description: description:
@ -253,10 +253,10 @@ packages:
dependency: "direct main" dependency: "direct main"
description: description:
name: fl_chart name: fl_chart
sha256: fe6fec7d85975a99c73b9515a69a6e291364accfa0e4a5b3ce6de814d74b9a1c sha256: "00b74ae680df6b1135bdbea00a7d1fc072a9180b7c3f3702e4b19a9943f5ed7d"
url: "https://pub.dev" url: "https://pub.dev"
source: hosted source: hosted
version: "0.66.0" version: "0.66.2"
flutter: flutter:
dependency: "direct main" dependency: "direct main"
description: flutter description: flutter
@ -295,10 +295,10 @@ packages:
dependency: "direct main" dependency: "direct main"
description: description:
name: flutter_markdown name: flutter_markdown
sha256: "35108526a233cc0755664d445f8a6b4b61e6f8fe993b3658b80b4a26827fc196" sha256: "87e11b9df25a42e2db315b8b7a51fae8e66f57a4b2f50ec4b822d0fa155e6b52"
url: "https://pub.dev" url: "https://pub.dev"
source: hosted source: hosted
version: "0.6.18+2" version: "0.6.22"
flutter_plugin_android_lifecycle: flutter_plugin_android_lifecycle:
dependency: transitive dependency: transitive
description: description:
@ -311,10 +311,10 @@ packages:
dependency: "direct main" dependency: "direct main"
description: description:
name: flutter_svg name: flutter_svg
sha256: d39e7f95621fc84376bc0f7d504f05c3a41488c562f4a8ad410569127507402c sha256: "7b4ca6cf3304575fe9c8ec64813c8d02ee41d2afe60bcfe0678bcb5375d596a2"
url: "https://pub.dev" url: "https://pub.dev"
source: hosted source: hosted
version: "2.0.9" version: "2.0.10+1"
flutter_test: flutter_test:
dependency: "direct dev" dependency: "direct dev"
description: flutter description: flutter
@ -345,18 +345,18 @@ packages:
dependency: "direct main" dependency: "direct main"
description: description:
name: go_router name: go_router
sha256: ca7e4a2249f96773152f1853fa25933ac752495cdd7fdf5dafb9691bd05830fd sha256: "7ecb2f391edbca5473db591b48555a8912dde60edd0fb3013bd6743033b2d3f8"
url: "https://pub.dev" url: "https://pub.dev"
source: hosted source: hosted
version: "13.0.0" version: "13.2.1"
http: http:
dependency: "direct main" dependency: "direct main"
description: description:
name: http name: http
sha256: d4872660c46d929f6b8a9ef4e7a7eff7e49bbf0c4ec3f385ee32df5119175139 sha256: a2bbf9d017fcced29139daa8ed2bba4ece450ab222871df93ca9eec6f80c34ba
url: "https://pub.dev" url: "https://pub.dev"
source: hosted source: hosted
version: "1.1.2" version: "1.2.0"
http_multi_server: http_multi_server:
dependency: transitive dependency: transitive
description: description:
@ -377,10 +377,10 @@ packages:
dependency: transitive dependency: transitive
description: description:
name: image name: image
sha256: "028f61960d56f26414eb616b48b04eb37d700cbe477b7fb09bf1d7ce57fd9271" sha256: "4c68bfd5ae83e700b5204c1e74451e7bf3cf750e6843c6e158289cf56bda018e"
url: "https://pub.dev" url: "https://pub.dev"
source: hosted source: hosted
version: "4.1.3" version: "4.1.7"
intl: intl:
dependency: "direct main" dependency: "direct main"
description: description:
@ -421,6 +421,30 @@ packages:
url: "https://pub.dev" url: "https://pub.dev"
source: hosted source: hosted
version: "4.8.1" version: "4.8.1"
leak_tracker:
dependency: transitive
description:
name: leak_tracker
sha256: "78eb209deea09858f5269f5a5b02be4049535f568c07b275096836f01ea323fa"
url: "https://pub.dev"
source: hosted
version: "10.0.0"
leak_tracker_flutter_testing:
dependency: transitive
description:
name: leak_tracker_flutter_testing
sha256: b46c5e37c19120a8a01918cfaf293547f47269f7cb4b0058f21531c2465d6ef0
url: "https://pub.dev"
source: hosted
version: "2.0.1"
leak_tracker_testing:
dependency: transitive
description:
name: leak_tracker_testing
sha256: a597f72a664dbd293f3bfc51f9ba69816f84dcd403cdac7066cb3f6003f3ab47
url: "https://pub.dev"
source: hosted
version: "2.0.1"
lints: lints:
dependency: transitive dependency: transitive
description: description:
@ -441,34 +465,34 @@ packages:
dependency: transitive dependency: transitive
description: description:
name: markdown name: markdown
sha256: acf35edccc0463a9d7384e437c015a3535772e09714cf60e07eeef3a15870dcd sha256: ef2a1298144e3f985cc736b22e0ccdaf188b5b3970648f2d9dc13efd1d9df051
url: "https://pub.dev" url: "https://pub.dev"
source: hosted source: hosted
version: "7.1.1" version: "7.2.2"
matcher: matcher:
dependency: transitive dependency: transitive
description: description:
name: matcher name: matcher
sha256: "1803e76e6653768d64ed8ff2e1e67bea3ad4b923eb5c56a295c3e634bad5960e" sha256: d2323aa2060500f906aa31a895b4030b6da3ebdcc5619d14ce1aada65cd161cb
url: "https://pub.dev" url: "https://pub.dev"
source: hosted source: hosted
version: "0.12.16" version: "0.12.16+1"
material_color_utilities: material_color_utilities:
dependency: transitive dependency: transitive
description: description:
name: material_color_utilities name: material_color_utilities
sha256: "9528f2f296073ff54cb9fee677df673ace1218163c3bc7628093e7eed5203d41" sha256: "0e0a020085b65b6083975e499759762399b4475f766c21668c4ecca34ea74e5a"
url: "https://pub.dev" url: "https://pub.dev"
source: hosted source: hosted
version: "0.5.0" version: "0.8.0"
meta: meta:
dependency: transitive dependency: transitive
description: description:
name: meta name: meta
sha256: a6e590c838b18133bb482a2745ad77c5bb7715fb0451209e1a7567d416678b8e sha256: d584fa6707a52763a52446f02cc621b077888fb63b93bbcb1143a7be5a0c0c04
url: "https://pub.dev" url: "https://pub.dev"
source: hosted source: hosted
version: "1.10.0" version: "1.11.0"
mime: mime:
dependency: transitive dependency: transitive
description: description:
@ -513,10 +537,10 @@ packages:
dependency: "direct main" dependency: "direct main"
description: description:
name: path name: path
sha256: "8829d8a55c13fc0e37127c29fedf290c102f4e40ae94ada574091fe0ff96c917" sha256: "087ce49c3f0dc39180befefc60fdb4acd8f8620e5682fe2476afd0b3688bb4af"
url: "https://pub.dev" url: "https://pub.dev"
source: hosted source: hosted
version: "1.8.3" version: "1.9.0"
path_parsing: path_parsing:
dependency: transitive dependency: transitive
description: description:
@ -529,26 +553,26 @@ packages:
dependency: "direct main" dependency: "direct main"
description: description:
name: path_provider name: path_provider
sha256: a1aa8aaa2542a6bc57e381f132af822420216c80d4781f7aa085ca3229208aaa sha256: b27217933eeeba8ff24845c34003b003b2b22151de3c908d0e679e8fe1aa078b
url: "https://pub.dev" url: "https://pub.dev"
source: hosted source: hosted
version: "2.1.1" version: "2.1.2"
path_provider_android: path_provider_android:
dependency: transitive dependency: transitive
description: description:
name: path_provider_android name: path_provider_android
sha256: e595b98692943b4881b219f0a9e3945118d3c16bd7e2813f98ec6e532d905f72 sha256: "477184d672607c0a3bf68fbbf601805f92ef79c82b64b4d6eb318cbca4c48668"
url: "https://pub.dev" url: "https://pub.dev"
source: hosted source: hosted
version: "2.2.1" version: "2.2.2"
path_provider_foundation: path_provider_foundation:
dependency: transitive dependency: transitive
description: description:
name: path_provider_foundation name: path_provider_foundation
sha256: "19314d595120f82aca0ba62787d58dde2cc6b5df7d2f0daf72489e38d1b57f2d" sha256: "5a7999be66e000916500be4f15a3633ebceb8302719b47b9cc49ce924125350f"
url: "https://pub.dev" url: "https://pub.dev"
source: hosted source: hosted
version: "2.3.1" version: "2.3.2"
path_provider_linux: path_provider_linux:
dependency: transitive dependency: transitive
description: description:
@ -561,10 +585,10 @@ packages:
dependency: transitive dependency: transitive
description: description:
name: path_provider_platform_interface name: path_provider_platform_interface
sha256: "94b1e0dd80970c1ce43d5d4e050a9918fce4f4a775e6142424c30a29a363265c" sha256: "88f5779f72ba699763fa3a3b06aa4bf6de76c8e5de842cf6f29e2e06476c2334"
url: "https://pub.dev" url: "https://pub.dev"
source: hosted source: hosted
version: "2.1.1" version: "2.1.2"
path_provider_windows: path_provider_windows:
dependency: transitive dependency: transitive
description: description:
@ -585,26 +609,26 @@ packages:
dependency: transitive dependency: transitive
description: description:
name: platform name: platform
sha256: "0a279f0707af40c890e80b1e9df8bb761694c074ba7e1d4ab1bc4b728e200b59" sha256: "12220bb4b65720483f8fa9450b4332347737cf8213dd2840d8b2c823e47243ec"
url: "https://pub.dev" url: "https://pub.dev"
source: hosted source: hosted
version: "3.1.3" version: "3.1.4"
plugin_platform_interface: plugin_platform_interface:
dependency: transitive dependency: transitive
description: description:
name: plugin_platform_interface name: plugin_platform_interface
sha256: f4f88d4a900933e7267e2b353594774fc0d07fb072b47eedcd5b54e1ea3269f8 sha256: "4820fbfdb9478b1ebae27888254d445073732dae3d6ea81f0b7e06d5dedc3f02"
url: "https://pub.dev" url: "https://pub.dev"
source: hosted source: hosted
version: "2.1.7" version: "2.1.8"
pointycastle: pointycastle:
dependency: transitive dependency: transitive
description: description:
name: pointycastle name: pointycastle
sha256: "7c1e5f0d23c9016c5bbd8b1473d0d3fb3fc851b876046039509e18e0c7485f2c" sha256: "43ac87de6e10afabc85c445745a7b799e04de84cebaa4fd7bf55a5e1e9604d29"
url: "https://pub.dev" url: "https://pub.dev"
source: hosted source: hosted
version: "3.7.3" version: "3.7.4"
pool: pool:
dependency: transitive dependency: transitive
description: description:
@ -617,10 +641,10 @@ packages:
dependency: transitive dependency: transitive
description: description:
name: process_run name: process_run
sha256: "3d5335d17003a7c2fd5148be2d313f5b84244ab2e625162fdd44b4aaa48bea66" sha256: "8d9c6198b98fbbfb511edd42e7364e24d85c163e47398919871b952dc86a423e"
url: "https://pub.dev" url: "https://pub.dev"
source: hosted source: hosted
version: "0.13.3+1" version: "0.14.2"
pub_semver: pub_semver:
dependency: transitive dependency: transitive
description: description:
@ -657,10 +681,10 @@ packages:
dependency: transitive dependency: transitive
description: description:
name: shared_preferences_foundation name: shared_preferences_foundation
sha256: "7bf53a9f2d007329ee6f3df7268fd498f8373602f943c975598bbb34649b62a7" sha256: "7708d83064f38060c7b39db12aefe449cb8cdc031d6062280087bc4cdb988f5c"
url: "https://pub.dev" url: "https://pub.dev"
source: hosted source: hosted
version: "2.3.4" version: "2.3.5"
shared_preferences_linux: shared_preferences_linux:
dependency: transitive dependency: transitive
description: description:
@ -673,10 +697,10 @@ packages:
dependency: transitive dependency: transitive
description: description:
name: shared_preferences_platform_interface name: shared_preferences_platform_interface
sha256: d4ec5fc9ebb2f2e056c617112aa75dcf92fc2e4faaf2ae999caa297473f75d8a sha256: "22e2ecac9419b4246d7c22bfbbda589e3acf5c0351137d87dd2939d984d37c3b"
url: "https://pub.dev" url: "https://pub.dev"
source: hosted source: hosted
version: "2.3.1" version: "2.3.2"
shared_preferences_web: shared_preferences_web:
dependency: transitive dependency: transitive
description: description:
@ -734,18 +758,18 @@ packages:
dependency: "direct main" dependency: "direct main"
description: description:
name: slang name: slang
sha256: "77fd99f7b0da15e671ef0289b24a0a63e74f693c58a0ca54111388e4c0ddb1dd" sha256: "5e08ac915ac27a3508863f37734280d30c3713d56746cd2e4a5da77413da4b95"
url: "https://pub.dev" url: "https://pub.dev"
source: hosted source: hosted
version: "3.28.0" version: "3.30.1"
slang_flutter: slang_flutter:
dependency: "direct main" dependency: "direct main"
description: description:
name: slang_flutter name: slang_flutter
sha256: "57817bb15553bb5df37aed3bac497286bdd8c2eab6763f4de6815efe2c0becee" sha256: "9ee040b0d364d3a4d692e4af536acff6ef513870689403494ebc6d59b0dccea6"
url: "https://pub.dev" url: "https://pub.dev"
source: hosted source: hosted
version: "3.28.0" version: "3.30.0"
source_map_stack_trace: source_map_stack_trace:
dependency: transitive dependency: transitive
description: description:
@ -774,50 +798,50 @@ packages:
dependency: "direct main" dependency: "direct main"
description: description:
name: sqflite name: sqflite
sha256: "591f1602816e9c31377d5f008c2d9ef7b8aca8941c3f89cc5fd9d84da0c38a9a" sha256: a9016f495c927cb90557c909ff26a6d92d9bd54fc42ba92e19d4e79d61e798c6
url: "https://pub.dev" url: "https://pub.dev"
source: hosted source: hosted
version: "2.3.0" version: "2.3.2"
sqflite_common: sqflite_common:
dependency: transitive dependency: transitive
description: description:
name: sqflite_common name: sqflite_common
sha256: bb4738f15b23352822f4c42a531677e5c6f522e079461fd240ead29d8d8a54a6 sha256: "3da423ce7baf868be70e2c0976c28a1bb2f73644268b7ffa7d2e08eab71f16a4"
url: "https://pub.dev" url: "https://pub.dev"
source: hosted source: hosted
version: "2.5.0+2" version: "2.5.4"
sqflite_common_ffi: sqflite_common_ffi:
dependency: "direct main" dependency: "direct main"
description: description:
name: sqflite_common_ffi name: sqflite_common_ffi
sha256: "873677ee78738a723d1ded4ccb23980581998d873d30ee9c331f6a81748663ff" sha256: "4d6137c29e930d6e4a8ff373989dd9de7bac12e3bc87bce950f6e844e8ad3bb5"
url: "https://pub.dev" url: "https://pub.dev"
source: hosted source: hosted
version: "2.3.1" version: "2.3.3"
sqflite_common_ffi_web: sqflite_common_ffi_web:
dependency: "direct main" dependency: "direct main"
description: description:
name: sqflite_common_ffi_web name: sqflite_common_ffi_web
sha256: "3d4b550a09fda9eb0a9ce3bd98c8080f57b2cc1f4b19e844290e82843e73b63d" sha256: "0c2921454d2e4a227675fb952be9fef916cf65fb9e9b606b54cfdf080d3e9450"
url: "https://pub.dev" url: "https://pub.dev"
source: hosted source: hosted
version: "0.4.2+2" version: "0.4.2+3"
sqlite3: sqlite3:
dependency: transitive dependency: transitive
description: description:
name: sqlite3 name: sqlite3
sha256: c4a4c5a4b2a32e2d0f6837b33d7c91a67903891a5b7dbe706cf4b1f6b0c798c5 sha256: "072128763f1547e3e9b4735ce846bfd226d68019ccda54db4cd427b12dfdedc9"
url: "https://pub.dev" url: "https://pub.dev"
source: hosted source: hosted
version: "2.3.0" version: "2.4.0"
sqlite3_flutter_libs: sqlite3_flutter_libs:
dependency: "direct main" dependency: "direct main"
description: description:
name: sqlite3_flutter_libs name: sqlite3_flutter_libs
sha256: "3e3583b77cf888a68eae2e49ee4f025f66b86623ef0d83c297c8d903daa14871" sha256: d6c31c8511c441d1f12f20b607343df1afe4eddf24a1cf85021677c8eea26060
url: "https://pub.dev" url: "https://pub.dev"
source: hosted source: hosted
version: "0.5.18" version: "0.5.20"
stack_trace: stack_trace:
dependency: transitive dependency: transitive
description: description:
@ -846,18 +870,18 @@ packages:
dependency: transitive dependency: transitive
description: description:
name: syncfusion_flutter_core name: syncfusion_flutter_core
sha256: "69c827931957d5b121ee9f0b9b0b8d7d0d1ac537b61bcdd5c3fbffc044bbe86e" sha256: "7666506885ebc8f62bb928ad4588a73e20caaff2b2cf2b2b56f67d98f4113525"
url: "https://pub.dev" url: "https://pub.dev"
source: hosted source: hosted
version: "24.1.41" version: "24.2.9"
syncfusion_flutter_gauges: syncfusion_flutter_gauges:
dependency: "direct main" dependency: "direct main"
description: description:
name: syncfusion_flutter_gauges name: syncfusion_flutter_gauges
sha256: "78515dcfbed952c36ab9ca4a1e6c99737beb7c6cf2312efe8beca2bd314a3955" sha256: "87be13e520fc1676a725691446f411f549ea5b6ff2580234db0479799f213757"
url: "https://pub.dev" url: "https://pub.dev"
source: hosted source: hosted
version: "24.1.41" version: "24.2.9"
synchronized: synchronized:
dependency: transitive dependency: transitive
description: description:
@ -910,26 +934,26 @@ packages:
dependency: "direct main" dependency: "direct main"
description: description:
name: url_launcher name: url_launcher
sha256: e9aa5ea75c84cf46b3db4eea212523591211c3cf2e13099ee4ec147f54201c86 sha256: "0ecc004c62fd3ed36a2ffcbe0dd9700aee63bd7532d0b642a488b1ec310f492e"
url: "https://pub.dev" url: "https://pub.dev"
source: hosted source: hosted
version: "6.2.2" version: "6.2.5"
url_launcher_android: url_launcher_android:
dependency: transitive dependency: transitive
description: description:
name: url_launcher_android name: url_launcher_android
sha256: "31222ffb0063171b526d3e569079cf1f8b294075ba323443fdc690842bfd4def" sha256: d4ed0711849dd8e33eb2dd69c25db0d0d3fdc37e0a62e629fe32f57a22db2745
url: "https://pub.dev" url: "https://pub.dev"
source: hosted source: hosted
version: "6.2.0" version: "6.3.0"
url_launcher_ios: url_launcher_ios:
dependency: transitive dependency: transitive
description: description:
name: url_launcher_ios name: url_launcher_ios
sha256: bba3373219b7abb6b5e0d071b0fe66dfbe005d07517a68e38d4fc3638f35c6d3 sha256: "9149d493b075ed740901f3ee844a38a00b33116c7c5c10d7fb27df8987fb51d5"
url: "https://pub.dev" url: "https://pub.dev"
source: hosted source: hosted
version: "6.2.1" version: "6.2.5"
url_launcher_linux: url_launcher_linux:
dependency: transitive dependency: transitive
description: description:
@ -950,18 +974,18 @@ packages:
dependency: transitive dependency: transitive
description: description:
name: url_launcher_platform_interface name: url_launcher_platform_interface
sha256: "980e8d9af422f477be6948bdfb68df8433be71f5743a188968b0c1b887807e50" sha256: "552f8a1e663569be95a8190206a38187b531910283c3e982193e4f2733f01029"
url: "https://pub.dev" url: "https://pub.dev"
source: hosted source: hosted
version: "2.2.0" version: "2.3.2"
url_launcher_web: url_launcher_web:
dependency: transitive dependency: transitive
description: description:
name: url_launcher_web name: url_launcher_web
sha256: "7286aec002c8feecc338cc33269e96b73955ab227456e9fb2a91f7fab8a358e9" sha256: fff0932192afeedf63cdd50ecbb1bc825d31aed259f02bb8dba0f3b729a5e88b
url: "https://pub.dev" url: "https://pub.dev"
source: hosted source: hosted
version: "2.2.2" version: "2.2.3"
url_launcher_windows: url_launcher_windows:
dependency: transitive dependency: transitive
description: description:
@ -974,26 +998,26 @@ packages:
dependency: transitive dependency: transitive
description: description:
name: vector_graphics name: vector_graphics
sha256: "0f0c746dd2d6254a0057218ff980fc7f5670fd0fcf5e4db38a490d31eed4ad43" sha256: "32c3c684e02f9bc0afb0ae0aa653337a2fe022e8ab064bcd7ffda27a74e288e3"
url: "https://pub.dev" url: "https://pub.dev"
source: hosted source: hosted
version: "1.1.9+1" version: "1.1.11+1"
vector_graphics_codec: vector_graphics_codec:
dependency: transitive dependency: transitive
description: description:
name: vector_graphics_codec name: vector_graphics_codec
sha256: "0edf6d630d1bfd5589114138ed8fada3234deacc37966bec033d3047c29248b7" sha256: c86987475f162fadff579e7320c7ddda04cd2fdeffbe1129227a85d9ac9e03da
url: "https://pub.dev" url: "https://pub.dev"
source: hosted source: hosted
version: "1.1.9+1" version: "1.1.11+1"
vector_graphics_compiler: vector_graphics_compiler:
dependency: transitive dependency: transitive
description: description:
name: vector_graphics_compiler name: vector_graphics_compiler
sha256: d24333727332d9bd20990f1483af4e09abdb9b1fc7c3db940b56ab5c42790c26 sha256: "12faff3f73b1741a36ca7e31b292ddeb629af819ca9efe9953b70bd63fc8cd81"
url: "https://pub.dev" url: "https://pub.dev"
source: hosted source: hosted
version: "1.1.9+1" version: "1.1.11+1"
vector_math: vector_math:
dependency: "direct main" dependency: "direct main"
description: description:
@ -1022,18 +1046,18 @@ packages:
dependency: transitive dependency: transitive
description: description:
name: web name: web
sha256: afe077240a270dcfd2aafe77602b4113645af95d0ad31128cc02bce5ac5d5152 sha256: "4188706108906f002b3a293509234588823c8c979dc83304e229ff400c996b05"
url: "https://pub.dev" url: "https://pub.dev"
source: hosted source: hosted
version: "0.3.0" version: "0.4.2"
web_socket_channel: web_socket_channel:
dependency: transitive dependency: transitive
description: description:
name: web_socket_channel name: web_socket_channel
sha256: d88238e5eac9a42bb43ca4e721edba3c08c6354d4a53063afaa568516217621b sha256: "939ab60734a4f8fa95feacb55804fa278de28bdeef38e616dc08e44a84adea23"
url: "https://pub.dev" url: "https://pub.dev"
source: hosted source: hosted
version: "2.4.0" version: "2.4.3"
webkit_inspection_protocol: webkit_inspection_protocol:
dependency: transitive dependency: transitive
description: description:
@ -1046,26 +1070,26 @@ packages:
dependency: transitive dependency: transitive
description: description:
name: win32 name: win32
sha256: b0f37db61ba2f2e9b7a78a1caece0052564d1bc70668156cf3a29d676fe4e574 sha256: "8cb58b45c47dcb42ab3651533626161d6b67a2921917d8d429791f76972b3480"
url: "https://pub.dev" url: "https://pub.dev"
source: hosted source: hosted
version: "5.1.1" version: "5.3.0"
window_manager: window_manager:
dependency: "direct main" dependency: "direct main"
description: description:
name: window_manager name: window_manager
sha256: dcc865277f26a7dad263a47d0e405d77e21f12cb71f30333a52710a408690bd7 sha256: b3c895bdf936c77b83c5254bec2e6b3f066710c1f89c38b20b8acc382b525494
url: "https://pub.dev" url: "https://pub.dev"
source: hosted source: hosted
version: "0.3.7" version: "0.3.8"
xdg_directories: xdg_directories:
dependency: transitive dependency: transitive
description: description:
name: xdg_directories name: xdg_directories
sha256: "589ada45ba9e39405c198fe34eb0f607cddb2108527e658136120892beac46d2" sha256: faea9dee56b520b55a566385b84f2e8de55e7496104adada9962e0bd11bcff1d
url: "https://pub.dev" url: "https://pub.dev"
source: hosted source: hosted
version: "1.0.3" version: "1.0.4"
xml: xml:
dependency: transitive dependency: transitive
description: description:
@ -1083,5 +1107,5 @@ packages:
source: hosted source: hosted
version: "3.1.2" version: "3.1.2"
sdks: sdks:
dart: ">=3.2.0 <4.0.0" dart: ">=3.3.0 <4.0.0"
flutter: ">=3.16.0" flutter: ">=3.19.0"

View File

@ -2,7 +2,7 @@ name: tetra_stats
description: Track your and other player stats in TETR.IO description: Track your and other player stats in TETR.IO
publish_to: 'none' publish_to: 'none'
version: 1.4.1+15 version: 1.5.0+16
environment: environment:
sdk: '>=3.0.0' sdk: '>=3.0.0'

View File

@ -48,11 +48,11 @@
"noRecords": "No records", "noRecords": "No records",
"noOldRecords": { "noOldRecords": {
"zero": "No records", "zero": "No records",
"one": "$n record", "one": "Only $n record",
"two": "$n records", "two": "Only $n records",
"few": "$n records", "few": "Only $n records",
"many": "$n records", "many": "Only $n records",
"other": "$n records" "other": "Only $n records"
}, },
"noRecord": "No record", "noRecord": "No record",
"botRecord": "Bots are not allowed to set records", "botRecord": "Bots are not allowed to set records",
@ -77,7 +77,7 @@
"supporter": "Supporter tier ${tier}", "supporter": "Supporter tier ${tier}",
"comparingWith": "Data from ${newDate} comparing with ${oldDate}", "comparingWith": "Data from ${newDate} comparing with ${oldDate}",
"top": "Top", "top": "Top",
"topRank": "Top Rank", "topRank": "Top rank",
"verdictGeneral": "$n $verdict than $rank rank average", "verdictGeneral": "$n $verdict than $rank rank average",
"verdictBetter": "better", "verdictBetter": "better",
"verdictWorse": "worse", "verdictWorse": "worse",
@ -136,10 +136,14 @@
"openReplay": "Open replay in TETR.IO", "openReplay": "Open replay in TETR.IO",
"replaySaved": "Replay saved to ${path}", "replaySaved": "Replay saved to ${path}",
"match": "Match", "match": "Match",
"timeWeightedmatch": "Match (time-weighted)",
"roundNumber": "Round $n", "roundNumber": "Round $n",
"statsFor": "Stats for", "statsFor": "Stats for",
"numberOfRounds": "Number of rounds",
"matchLength": "Match Length", "matchLength": "Match Length",
"roundLength": "Round Length", "roundLength": "Round Length",
"matchStats": "Match stats",
"timeWeightedmatchStats": "Time-weighted match stats",
"replayIssue": "Can't process replay", "replayIssue": "Can't process replay",
"matchIsTooOld": "Replay is not available", "matchIsTooOld": "Replay is not available",
"winner": "Winner", "winner": "Winner",
@ -176,6 +180,15 @@
"many": "$n players", "many": "$n players",
"other": "$n players" "other": "$n players"
}, },
"games": {
"zero": "$n games",
"one": "$n game",
"two": "$n games",
"few": "$n games",
"many": "$n games",
"other": "$n games"
},
"gamesPlayed": "$games played",
"chart": "Chart", "chart": "Chart",
"entries": "Entries", "entries": "Entries",
"minimums": "Minimums", "minimums": "Minimums",

View File

@ -77,7 +77,7 @@
"assignedManualy": "Этот значок был присвоен вручную администрацией TETR.IO", "assignedManualy": "Этот значок был присвоен вручную администрацией TETR.IO",
"comparingWith": "Данные от ${newDate} в сравнении с данными от ${oldDate}", "comparingWith": "Данные от ${newDate} в сравнении с данными от ${oldDate}",
"top": "Топ", "top": "Топ",
"topRank": "Топ Ранг", "topRank": "Топ ранг",
"verdictGeneral": "$verdict среднего $rank ранга на $n", "verdictGeneral": "$verdict среднего $rank ранга на $n",
"verdictBetter": "Лучше", "verdictBetter": "Лучше",
"verdictWorse": "Хуже", "verdictWorse": "Хуже",
@ -136,10 +136,14 @@
"openReplay": "Открыть повтор в TETR.IO", "openReplay": "Открыть повтор в TETR.IO",
"replaySaved": "Повтор сохранён по пути ${path}", "replaySaved": "Повтор сохранён по пути ${path}",
"match": "Матч", "match": "Матч",
"timeWeightedmatch": "Матч (взвешенная по времени)",
"roundNumber": "Раунд $n", "roundNumber": "Раунд $n",
"statsFor": "Статистика за", "statsFor": "Статистика за",
"numberOfRounds": "Количество раундов",
"matchLength": "Продолжительность матча", "matchLength": "Продолжительность матча",
"roundLength": "Продолжительность раунда", "roundLength": "Продолжительность раунда",
"matchStats": "Статистика матча",
"timeWeightedmatchStats": "Взвешенная по времени cтатистика матча",
"replayIssue": "Ошибка обработки повтора", "replayIssue": "Ошибка обработки повтора",
"matchIsTooOld": "Информация о повторе недоступна", "matchIsTooOld": "Информация о повторе недоступна",
"winner": "Победитель", "winner": "Победитель",
@ -176,6 +180,15 @@
"many": "$n игроков", "many": "$n игроков",
"other": "$n игроков" "other": "$n игроков"
}, },
"games": {
"zero": "$n игр",
"one": "$n игра",
"two": "$n игры",
"few": "$n игры",
"many": "$n игр",
"other": "$n игр"
},
"gamesPlayed": "$games сыграно",
"chart": "График", "chart": "График",
"entries": "Список", "entries": "Список",
"minimums": "Минимумы", "minimums": "Минимумы",

BIN
res/tetrio_badges/mts_1.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 45 KiB

BIN
res/tetrio_badges/mts_2.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 45 KiB

BIN
res/tetrio_badges/mts_3.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 41 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 48 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 29 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 30 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 28 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 15 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 42 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 25 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 28 KiB