diff --git a/README.md b/README.md index d7506ff..093c477 100644 --- a/README.md +++ b/README.md @@ -16,6 +16,7 @@ You can [download an app](https://github.com/dan63047/TetraStats/releases), or [ - Stats Calculator - Player history in charts - Tetra League matches history +- Time-weighted stats in Tetra League matches # Special thanks - **kerrmunism** — formulas diff --git a/android/app/build.gradle b/android/app/build.gradle index 3863f27..ebd2bb0 100644 --- a/android/app/build.gradle +++ b/android/app/build.gradle @@ -25,6 +25,12 @@ apply plugin: 'com.android.application' apply plugin: 'kotlin-android' apply from: "$flutterRoot/packages/flutter_tools/gradle/flutter.gradle" +def keystoreProperties = new Properties() + def keystorePropertiesFile = rootProject.file('key.properties') + if (keystorePropertiesFile.exists()) { + keystoreProperties.load(new FileInputStream(keystorePropertiesFile)) + } + android { compileSdkVersion flutter.compileSdkVersion ndkVersion flutter.ndkVersion @@ -53,11 +59,17 @@ android { versionName flutterVersionName } + signingConfigs { + release { + keyAlias keystoreProperties['keyAlias'] + keyPassword keystoreProperties['keyPassword'] + storeFile keystoreProperties['storeFile'] ? file(keystoreProperties['storeFile']) : null + storePassword keystoreProperties['storePassword'] + } + } buildTypes { release { - // TODO: Add your own signing config for the release build. - // Signing with the debug keys for now, so `flutter run --release` works. - signingConfig signingConfigs.debug + signingConfig signingConfigs.release } } } diff --git a/lib/data_objects/freyhoe_test.dart b/lib/data_objects/freyhoe_test.dart index 5ca2a05..5275e86 100644 --- a/lib/data_objects/freyhoe_test.dart +++ b/lib/data_objects/freyhoe_test.dart @@ -1,12 +1,12 @@ //import 'dart:convert'; -import 'dart:io'; +//import 'dart:io'; //import 'package:path_provider/path_provider.dart'; //import 'tetrio_multiplayer_replay.dart'; /// That thing allows me to test my new staff i'm trying to implement -void main() async { +//void main() async { // List queue = List.from(tetrominoes); // TetrioRNG rng = TetrioRNG(0); // queue = rng.shuffleList(queue); @@ -21,5 +21,5 @@ void main() async { // print(replay.rawJson); //print(""); - exit(0); -} \ No newline at end of file +// exit(0); +//} \ No newline at end of file diff --git a/lib/data_objects/tetrio_multiplayer_replay.dart b/lib/data_objects/tetrio_multiplayer_replay.dart index 03207c9..e453dd3 100644 --- a/lib/data_objects/tetrio_multiplayer_replay.dart +++ b/lib/data_objects/tetrio_multiplayer_replay.dart @@ -261,399 +261,399 @@ class ReplayData{ // can't belive i have to implement that difficult shit -List readEventList(Map json){ - List events = []; - int id = 0; - for (var event in json['data'][0]['replays'][0]['events']){ - int frame = event["frame"]; - EventType type = EventType.values.byName(event['type']); - switch (type) { - case EventType.start: - events.add(Event(id, frame, type)); - break; - case EventType.full: - events.add(EventFull(id, frame, type, DataFull.fromJson(event["data"]))); - break; - case EventType.targets: - // TODO - break; - case EventType.keydown: - events.add(EventKeyPress(id, frame, type, - Keypress( - KeyType.values.byName(event['data']['key']), - event['data']['subframe'], - false) - )); - break; - case EventType.keyup: - events.add(EventKeyPress(id, frame, type, - Keypress( - KeyType.values.byName(event['data']['key']), - event['data']['subframe'], - true) - )); - break; - case EventType.end: - // TODO: Handle this case. - case EventType.ige: - // TODO: Handle this case. - case EventType.exit: - // TODO: Handle this case. - } - id++; - } - return []; -} +// List readEventList(Map json){ +// List events = []; +// int id = 0; +// for (var event in json['data'][0]['replays'][0]['events']){ +// int frame = event["frame"]; +// EventType type = EventType.values.byName(event['type']); +// switch (type) { +// case EventType.start: +// events.add(Event(id, frame, type)); +// break; +// case EventType.full: +// events.add(EventFull(id, frame, type, DataFull.fromJson(event["data"]))); +// break; +// case EventType.targets: +// // TODO +// break; +// case EventType.keydown: +// events.add(EventKeyPress(id, frame, type, +// Keypress( +// KeyType.values.byName(event['data']['key']), +// event['data']['subframe'], +// false) +// )); +// break; +// case EventType.keyup: +// events.add(EventKeyPress(id, frame, type, +// Keypress( +// KeyType.values.byName(event['data']['key']), +// event['data']['subframe'], +// true) +// )); +// break; +// case EventType.end: +// // TODO: Handle this case. +// case EventType.ige: +// // TODO: Handle this case. +// case EventType.exit: +// // TODO: Handle this case. +// } +// id++; +// } +// return []; +// } -enum EventType -{ - start, - end, - full, - keydown, - keyup, - targets, - ige, - exit -} +// enum EventType +// { +// start, +// end, +// full, +// keydown, +// keyup, +// targets, +// ige, +// exit +// } -enum KeyType -{ - moveLeft, - moveRight, - softDrop, - rotateCCW, - rotateCW, - rotate180, - hardDrop, - hold, - chat, - exit, - retry -} +// enum KeyType +// { +// moveLeft, +// moveRight, +// softDrop, +// rotateCCW, +// rotateCW, +// rotate180, +// hardDrop, +// hold, +// chat, +// exit, +// retry +// } -class Event{ - int id; - int frame; - EventType type; - //dynamic data; +// class Event{ +// int id; +// int frame; +// EventType type; +// //dynamic data; - Event(this.id, this.frame, this.type); +// Event(this.id, this.frame, this.type); - @override - String toString(){ - return "E#$id f#$frame: $type"; - } -} +// @override +// String toString(){ +// return "E#$id f#$frame: $type"; +// } +// } -class Keypress{ - KeyType key; - double subframe; - bool released; +// class Keypress{ +// KeyType key; +// double subframe; +// bool released; - Keypress(this.key, this.subframe, this.released); -} +// Keypress(this.key, this.subframe, this.released); +// } -class EventKeyPress extends Event{ - Keypress data; +// class EventKeyPress extends Event{ +// Keypress data; - EventKeyPress(super.id, super.frame, super.type, this.data); -} +// EventKeyPress(super.id, super.frame, super.type, this.data); +// } -class IGE{ - int id; - int frame; - String type; - int amount; +// class IGE{ +// int id; +// int frame; +// String type; +// int amount; - IGE(this.id, this.frame, this.type, this.amount); -} +// IGE(this.id, this.frame, this.type, this.amount); +// } -class EventIGE extends Event{ - IGE data; +// class EventIGE extends Event{ +// IGE data; - EventIGE(super.id, super.frame, super.type, this.data); -} +// EventIGE(super.id, super.frame, super.type, this.data); +// } -class Hold -{ - String? piece; - bool locked; +// class Hold +// { +// String? piece; +// bool locked; - Hold(this.piece, this.locked); -} +// Hold(this.piece, this.locked); +// } -class DataFullOptions{ - int? version; - bool? seedRandom; - int? seed; - double? g; - int? stock; - int? gMargin; - double? gIncrease; - double? garbageMultiplier; - int? garbageMargin; - double? garbageIncrease; - int? garbageCap; - double? garbageCapIncrease; - int? garbageCapMax; - int? garbageHoleSize; - String? garbageBlocking; // TODO: enum - bool? hasGarbage; - int? locktime; - int? garbageSpeed; - int? forfeitTime; - int? are; - int? areLineclear; - bool? infiniteMovement; - int? lockresets; - bool? allow180; - bool? btbChaining; - bool? allclears; - bool? clutch; - bool? noLockout; - String? passthrough; - int? boardwidth; - int? boardheight; - Handling? handling; - int? boardbuffer; +// class DataFullOptions{ +// int? version; +// bool? seedRandom; +// int? seed; +// double? g; +// int? stock; +// int? gMargin; +// double? gIncrease; +// double? garbageMultiplier; +// int? garbageMargin; +// double? garbageIncrease; +// int? garbageCap; +// double? garbageCapIncrease; +// int? garbageCapMax; +// int? garbageHoleSize; +// String? garbageBlocking; // TODO: enum +// bool? hasGarbage; +// int? locktime; +// int? garbageSpeed; +// int? forfeitTime; +// int? are; +// int? areLineclear; +// bool? infiniteMovement; +// int? lockresets; +// bool? allow180; +// bool? btbChaining; +// bool? allclears; +// bool? clutch; +// bool? noLockout; +// String? passthrough; +// int? boardwidth; +// int? boardheight; +// Handling? handling; +// int? boardbuffer; - DataFullOptions.fromJson(Map json){ - version = json["version"]; - seedRandom = json["seed_random"]; - seed = json["seed"]; - g = json["g"]; - stock = json["stock"]; - gMargin = json["gmargin"]; - gIncrease = json["gincrease"]; - garbageMultiplier = json["garbagemultiplier"]; - garbageCapIncrease = json["garbagecapincrease"]; - garbageCapMax = json["garbagecapmax"]; - garbageHoleSize = json["garbageholesize"]; - garbageBlocking = json["garbageblocking"]; - hasGarbage = json["hasgarbage"]; - locktime = json["locktime"]; - garbageSpeed = json["garbagespeed"]; - forfeitTime = json["forfeit_time"]; - are = json["are"]; - areLineclear = json["lineclear_are"]; - infiniteMovement = json["infinitemovement"]; - lockresets = json["lockresets"]; - allow180 = json["allow180"]; - btbChaining = json["b2bchaining"]; - allclears = json["allclears"]; - clutch = json["clutch"]; - noLockout = json["nolockout"]; - passthrough = json["passthrough"]; - boardwidth = json["boardwidth"]; - boardheight = json["boardheight"]; - handling = Handling.fromJson(json["handling"]); - boardbuffer = json["boardbuffer"]; - } -} +// DataFullOptions.fromJson(Map json){ +// version = json["version"]; +// seedRandom = json["seed_random"]; +// seed = json["seed"]; +// g = json["g"]; +// stock = json["stock"]; +// gMargin = json["gmargin"]; +// gIncrease = json["gincrease"]; +// garbageMultiplier = json["garbagemultiplier"]; +// garbageCapIncrease = json["garbagecapincrease"]; +// garbageCapMax = json["garbagecapmax"]; +// garbageHoleSize = json["garbageholesize"]; +// garbageBlocking = json["garbageblocking"]; +// hasGarbage = json["hasgarbage"]; +// locktime = json["locktime"]; +// garbageSpeed = json["garbagespeed"]; +// forfeitTime = json["forfeit_time"]; +// are = json["are"]; +// areLineclear = json["lineclear_are"]; +// infiniteMovement = json["infinitemovement"]; +// lockresets = json["lockresets"]; +// allow180 = json["allow180"]; +// btbChaining = json["b2bchaining"]; +// allclears = json["allclears"]; +// clutch = json["clutch"]; +// noLockout = json["nolockout"]; +// passthrough = json["passthrough"]; +// boardwidth = json["boardwidth"]; +// boardheight = json["boardheight"]; +// handling = Handling.fromJson(json["handling"]); +// boardbuffer = json["boardbuffer"]; +// } +// } -class DataFullStats - { - double? seed; - int? lines; - int? levelLines; - int? levelLinesNeeded; - int? inputs; - int? holds; - int? score; - int? zenLevel; - int? zenProgress; - int? level; - int? combo; - int? currentComboPower; - int? topCombo; - int? btb; - int? topbtb; - int? tspins; - int? piecesPlaced; - Clears? clears; - Garbage? garbage; - int? kills; - Finesse? finesse; +// class DataFullStats +// { +// double? seed; +// int? lines; +// int? levelLines; +// int? levelLinesNeeded; +// int? inputs; +// int? holds; +// int? score; +// int? zenLevel; +// int? zenProgress; +// int? level; +// int? combo; +// int? currentComboPower; +// int? topCombo; +// int? btb; +// int? topbtb; +// int? tspins; +// int? piecesPlaced; +// Clears? clears; +// Garbage? garbage; +// int? kills; +// Finesse? finesse; - DataFullStats.fromJson(Map json){ - seed = json["seed"]; - lines = json["lines"]; - levelLines = json["level_lines"]; - levelLinesNeeded = json["level_lines_needed"]; - inputs = json["inputs"]; - holds = json["holds"]; - score = json["score"]; - zenLevel = json["zenlevel"]; - zenProgress = json["zenprogress"]; - level = json["level"]; - combo = json["combo"]; - currentComboPower = json["currentcombopower"]; - topCombo = json["topcombo"]; - btb = json["btb"]; - topbtb = json["topbtb"]; - tspins = json["tspins"]; - piecesPlaced = json["piecesplaced"]; - clears = Clears.fromJson(json["clears"]); - garbage = Garbage.fromJson(json["garbage"]); - kills = json["kills"]; - finesse = Finesse.fromJson(json["finesse"]); - } - } +// DataFullStats.fromJson(Map json){ +// seed = json["seed"]; +// lines = json["lines"]; +// levelLines = json["level_lines"]; +// levelLinesNeeded = json["level_lines_needed"]; +// inputs = json["inputs"]; +// holds = json["holds"]; +// score = json["score"]; +// zenLevel = json["zenlevel"]; +// zenProgress = json["zenprogress"]; +// level = json["level"]; +// combo = json["combo"]; +// currentComboPower = json["currentcombopower"]; +// topCombo = json["topcombo"]; +// btb = json["btb"]; +// topbtb = json["topbtb"]; +// tspins = json["tspins"]; +// piecesPlaced = json["piecesplaced"]; +// clears = Clears.fromJson(json["clears"]); +// garbage = Garbage.fromJson(json["garbage"]); +// kills = json["kills"]; +// finesse = Finesse.fromJson(json["finesse"]); +// } +// } -class DataFullGame - { - List>? board; - List? bag; - double? g; - bool? playing; - Hold? hold; - String? piece; - Handling? handling; +// class DataFullGame +// { +// List>? board; +// List? bag; +// double? g; +// bool? playing; +// Hold? hold; +// String? piece; +// Handling? handling; - DataFullGame.fromJson(Map json){ - board = json["board"]; - bag = json["bag"]; - hold = Hold(json["hold"]["piece"], json["hold"]["locked"]); - g = json["g"]; - handling = Handling.fromJson(json["handling"]); - } - } +// DataFullGame.fromJson(Map json){ +// board = json["board"]; +// bag = json["bag"]; +// hold = Hold(json["hold"]["piece"], json["hold"]["locked"]); +// g = json["g"]; +// handling = Handling.fromJson(json["handling"]); +// } +// } -class DataFull{ - bool? successful; - String? gameOverReason; - int? fire; - DataFullOptions? options; - DataFullStats? stats; - DataFullGame? game; +// class DataFull{ +// bool? successful; +// String? gameOverReason; +// int? fire; +// DataFullOptions? options; +// DataFullStats? stats; +// DataFullGame? game; - DataFull.fromJson(Map json){ - successful = json["successful"]; - gameOverReason = json["gameoverreason"]; - fire = json["fire"]; - options = DataFullOptions.fromJson(json["options"]); - stats = DataFullStats.fromJson(json["stats"]); - game = DataFullGame.fromJson(json["game"]); - } -} +// DataFull.fromJson(Map json){ +// successful = json["successful"]; +// gameOverReason = json["gameoverreason"]; +// fire = json["fire"]; +// options = DataFullOptions.fromJson(json["options"]); +// stats = DataFullStats.fromJson(json["stats"]); +// game = DataFullGame.fromJson(json["game"]); +// } +// } -class EventFull extends Event{ - DataFull data; +// class EventFull extends Event{ +// DataFull data; - EventFull(super.id, super.frame, super.type, this.data); -} +// EventFull(super.id, super.frame, super.type, this.data); +// } -class TetrioRNG{ - late double _t; +// class TetrioRNG{ +// late double _t; - TetrioRNG(int seed){ - _t = seed % 2147483647; - if (_t <= 0) _t += 2147483646; - } +// TetrioRNG(int seed){ +// _t = seed % 2147483647; +// if (_t <= 0) _t += 2147483646; +// } - int next(){ - _t = 16807 * _t % 2147483647; - return _t.toInt(); - } +// int next(){ +// _t = 16807 * _t % 2147483647; +// return _t.toInt(); +// } - double nextFloat(){ - return (next() - 1) / 2147483646; - } +// double nextFloat(){ +// return (next() - 1) / 2147483646; +// } - List shuffleList(List array){ - int length = array.length; - if (length == 0) return []; +// List shuffleList(List array){ +// int length = array.length; +// if (length == 0) return []; - for (; --length > 0;){ - int swapIndex = ((nextFloat()) * (length + 1)).toInt(); - Tetromino tmp = array[length]; - array[length] = array[swapIndex]; - array[swapIndex] = tmp; - } - return array; - } -} +// for (; --length > 0;){ +// int swapIndex = ((nextFloat()) * (length + 1)).toInt(); +// Tetromino tmp = array[length]; +// array[length] = array[swapIndex]; +// array[swapIndex] = tmp; +// } +// return array; +// } +// } -enum Tetromino{ - Z, - L, - O, - S, - I, - J, - T, - garbage, - empty -} +// enum Tetromino{ +// Z, +// L, +// O, +// S, +// I, +// J, +// T, +// garbage, +// empty +// } -List tetrominoes = [Tetromino.Z, Tetromino.L, Tetromino.O, Tetromino.S, Tetromino.I, Tetromino.J, Tetromino.T]; -List>> shapes = [ - [ // Z - [Vector2(0, 0), Vector2(1, 0), Vector2(1, 1), Vector2(2, 1)], - [Vector2(2, 0), Vector2(1, 1), Vector2(2, 1), Vector2(1, 2)], - [Vector2(0, 1), Vector2(1, 1), Vector2(1, 2), Vector2(2, 2)], - [Vector2(1, 0), Vector2(0, 1), Vector2(1, 1), Vector2(0, 2)] - ], - [ // L - [Vector2(2, 0), Vector2(0, 1), Vector2(1, 1), Vector2(2, 1)], - [Vector2(1, 0), Vector2(1, 1), Vector2(1, 2), Vector2(2, 2)], - [Vector2(0, 1), Vector2(1, 1), Vector2(2, 1), Vector2(0, 2)], - [Vector2(0, 0), Vector2(1, 0), Vector2(1, 1), Vector2(1, 2)] - ], - [ // O - [Vector2(0, 0), Vector2(1, 0), Vector2(0, 1), Vector2(1, 1)], - [Vector2(0, 0), Vector2(1, 0), Vector2(0, 1), Vector2(1, 1)], - [Vector2(0, 0), Vector2(1, 0), Vector2(0, 1), Vector2(1, 1)], - [Vector2(0, 0), Vector2(1, 0), Vector2(0, 1), Vector2(1, 1)] - ], - [ // S - [Vector2(1, 0), Vector2(2, 0), Vector2(0, 1), Vector2(1, 1)], - [Vector2(1, 0), Vector2(1, 1), Vector2(2, 1), Vector2(2, 2)], - [Vector2(1, 1), Vector2(2, 1), Vector2(0, 2), Vector2(1, 2)], - [Vector2(0, 0), Vector2(0, 1), Vector2(1, 1), Vector2(1, 2)] - ], - [ // I - [Vector2(0, 1), Vector2(1, 1), Vector2(2, 1), Vector2(3, 1)], - [Vector2(2, 0), Vector2(2, 1), Vector2(2, 2), Vector2(2, 3)], - [Vector2(0, 2), Vector2(1, 2), Vector2(2, 2), Vector2(3, 2)], - [Vector2(1, 0), Vector2(1, 1), Vector2(1, 2), Vector2(1, 3)] - ], - [ // J - [Vector2(0, 0), Vector2(0, 1), Vector2(1, 1), Vector2(2, 1)], - [Vector2(1, 0), Vector2(2, 0), Vector2(1, 1), Vector2(1, 2)], - [Vector2(0, 1), Vector2(1, 1), Vector2(2, 1), Vector2(2, 2)], - [Vector2(1, 0), Vector2(1, 1), Vector2(0, 2), Vector2(1, 2)] - ], - [ // T - [Vector2(1, 0), Vector2(0, 1), Vector2(1, 1), Vector2(2, 1)], - [Vector2(1, 0), Vector2(1, 1), Vector2(2, 1), Vector2(1, 2)], - [Vector2(0, 1), Vector2(1, 1), Vector2(2, 1), Vector2(1, 2)], - [Vector2(1, 0), Vector2(0, 1), Vector2(1, 1), Vector2(1, 2)] - ] -]; -List spawnPositionFixes = [Vector2(1, 1), Vector2(1, 1), Vector2(0, 1), Vector2(1, 1), Vector2(1, 1), Vector2(1, 1), Vector2(1, 1)]; +// List tetrominoes = [Tetromino.Z, Tetromino.L, Tetromino.O, Tetromino.S, Tetromino.I, Tetromino.J, Tetromino.T]; +// List>> shapes = [ +// [ // Z +// [Vector2(0, 0), Vector2(1, 0), Vector2(1, 1), Vector2(2, 1)], +// [Vector2(2, 0), Vector2(1, 1), Vector2(2, 1), Vector2(1, 2)], +// [Vector2(0, 1), Vector2(1, 1), Vector2(1, 2), Vector2(2, 2)], +// [Vector2(1, 0), Vector2(0, 1), Vector2(1, 1), Vector2(0, 2)] +// ], +// [ // L +// [Vector2(2, 0), Vector2(0, 1), Vector2(1, 1), Vector2(2, 1)], +// [Vector2(1, 0), Vector2(1, 1), Vector2(1, 2), Vector2(2, 2)], +// [Vector2(0, 1), Vector2(1, 1), Vector2(2, 1), Vector2(0, 2)], +// [Vector2(0, 0), Vector2(1, 0), Vector2(1, 1), Vector2(1, 2)] +// ], +// [ // O +// [Vector2(0, 0), Vector2(1, 0), Vector2(0, 1), Vector2(1, 1)], +// [Vector2(0, 0), Vector2(1, 0), Vector2(0, 1), Vector2(1, 1)], +// [Vector2(0, 0), Vector2(1, 0), Vector2(0, 1), Vector2(1, 1)], +// [Vector2(0, 0), Vector2(1, 0), Vector2(0, 1), Vector2(1, 1)] +// ], +// [ // S +// [Vector2(1, 0), Vector2(2, 0), Vector2(0, 1), Vector2(1, 1)], +// [Vector2(1, 0), Vector2(1, 1), Vector2(2, 1), Vector2(2, 2)], +// [Vector2(1, 1), Vector2(2, 1), Vector2(0, 2), Vector2(1, 2)], +// [Vector2(0, 0), Vector2(0, 1), Vector2(1, 1), Vector2(1, 2)] +// ], +// [ // I +// [Vector2(0, 1), Vector2(1, 1), Vector2(2, 1), Vector2(3, 1)], +// [Vector2(2, 0), Vector2(2, 1), Vector2(2, 2), Vector2(2, 3)], +// [Vector2(0, 2), Vector2(1, 2), Vector2(2, 2), Vector2(3, 2)], +// [Vector2(1, 0), Vector2(1, 1), Vector2(1, 2), Vector2(1, 3)] +// ], +// [ // J +// [Vector2(0, 0), Vector2(0, 1), Vector2(1, 1), Vector2(2, 1)], +// [Vector2(1, 0), Vector2(2, 0), Vector2(1, 1), Vector2(1, 2)], +// [Vector2(0, 1), Vector2(1, 1), Vector2(2, 1), Vector2(2, 2)], +// [Vector2(1, 0), Vector2(1, 1), Vector2(0, 2), Vector2(1, 2)] +// ], +// [ // T +// [Vector2(1, 0), Vector2(0, 1), Vector2(1, 1), Vector2(2, 1)], +// [Vector2(1, 0), Vector2(1, 1), Vector2(2, 1), Vector2(1, 2)], +// [Vector2(0, 1), Vector2(1, 1), Vector2(2, 1), Vector2(1, 2)], +// [Vector2(1, 0), Vector2(0, 1), Vector2(1, 1), Vector2(1, 2)] +// ] +// ]; +// List spawnPositionFixes = [Vector2(1, 1), Vector2(1, 1), Vector2(0, 1), Vector2(1, 1), Vector2(1, 1), Vector2(1, 1), Vector2(1, 1)]; -const Map garbage = { - "single": 0, - "double": 1, - "triple": 2, - "quad": 4, - "penta": 5, - "t-spin": 0, - "t-spin single": 2, - "t-spin double": 4, - "t-spin triple": 6, - "t-spin quad": 10, - "t-spin penta": 12, - "t-spin mini": 0, - "t-spin mini single": 0, - "t-spin mini double": 1, - "allclear": 10 -}; -int btbBonus = 1; -double btbLog = 0.8; -double comboBonus = 0.25; -int comboMinifier = 1; -double comboMinifierLog = 1.25; -List comboTable = [0, 1, 1, 2, 2, 3, 3, 4, 4, 4, 5]; +// const Map garbage = { +// "single": 0, +// "double": 1, +// "triple": 2, +// "quad": 4, +// "penta": 5, +// "t-spin": 0, +// "t-spin single": 2, +// "t-spin double": 4, +// "t-spin triple": 6, +// "t-spin quad": 10, +// "t-spin penta": 12, +// "t-spin mini": 0, +// "t-spin mini single": 0, +// "t-spin mini double": 1, +// "allclear": 10 +// }; +// int btbBonus = 1; +// double btbLog = 0.8; +// double comboBonus = 0.25; +// int comboMinifier = 1; +// double comboMinifierLog = 1.25; +// List comboTable = [0, 1, 1, 2, 2, 3, 3, 4, 4, 4, 5]; diff --git a/lib/gen/strings.g.dart b/lib/gen/strings.g.dart index ee03a73..1bed291 100644 --- a/lib/gen/strings.g.dart +++ b/lib/gen/strings.g.dart @@ -4,9 +4,9 @@ /// To regenerate, run: `dart run slang` /// /// 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 // ignore_for_file: type=lint @@ -183,11 +183,11 @@ class Translations implements BaseTranslations { String get noRecords => 'No records'; String noOldRecords({required num n}) => (_root.$meta.cardinalResolver ?? PluralResolvers.cardinal('en'))(n, zero: 'No records', - one: '${n} record', - two: '${n} records', - few: '${n} records', - many: '${n} records', - other: '${n} records', + one: 'Only ${n} record', + two: 'Only ${n} records', + few: 'Only ${n} records', + many: 'Only ${n} records', + other: 'Only ${n} records', ); String get noRecord => 'No record'; String get botRecord => 'Bots are not allowed to set records'; @@ -212,7 +212,7 @@ class Translations implements BaseTranslations { String supporter({required Object tier}) => 'Supporter tier ${tier}'; String comparingWith({required Object newDate, required Object oldDate}) => 'Data from ${newDate} comparing with ${oldDate}'; String get top => 'Top'; - String get topRank => 'Top Rank'; + String get topRank => 'Top rank'; String verdictGeneral({required Object n, required Object verdict, required Object rank}) => '${n} ${verdict} than ${rank} rank average'; String get verdictBetter => 'better'; String get verdictWorse => 'worse'; @@ -271,10 +271,14 @@ class Translations implements BaseTranslations { String get openReplay => 'Open replay in TETR.IO'; String replaySaved({required Object path}) => 'Replay saved to ${path}'; String get match => 'Match'; + String get timeWeightedmatch => 'Match (time-weighted)'; String roundNumber({required Object n}) => 'Round ${n}'; String get statsFor => 'Stats for'; + String get numberOfRounds => 'Number of rounds'; String get matchLength => 'Match Length'; String get roundLength => 'Round Length'; + String get matchStats => 'Match stats'; + String get timeWeightedmatchStats => 'Time-weighted match stats'; String get replayIssue => 'Can\'t process replay'; String get matchIsTooOld => 'Replay is not available'; String get winner => 'Winner'; @@ -311,6 +315,15 @@ class Translations implements BaseTranslations { many: '${n} players', other: '${n} players', ); + String games({required num n}) => (_root.$meta.cardinalResolver ?? PluralResolvers.cardinal('en'))(n, + zero: '${n} games', + one: '${n} game', + two: '${n} games', + few: '${n} games', + many: '${n} games', + other: '${n} games', + ); + String gamesPlayed({required Object games}) => '${games} played'; String get chart => 'Chart'; String get entries => 'Entries'; String get minimums => 'Minimums'; @@ -853,7 +866,7 @@ class _StringsRu implements Translations { @override String get assignedManualy => 'Этот значок был присвоен вручную администрацией TETR.IO'; @override String comparingWith({required Object newDate, required Object oldDate}) => 'Данные от ${newDate} в сравнении с данными от ${oldDate}'; @override String get top => 'Топ'; - @override String get topRank => 'Топ Ранг'; + @override String get topRank => 'Топ ранг'; @override String verdictGeneral({required Object verdict, required Object rank, required Object n}) => '${verdict} среднего ${rank} ранга на ${n}'; @override String get verdictBetter => 'Лучше'; @override String get verdictWorse => 'Хуже'; @@ -912,10 +925,14 @@ class _StringsRu implements Translations { @override String get openReplay => 'Открыть повтор в TETR.IO'; @override String replaySaved({required Object path}) => 'Повтор сохранён по пути ${path}'; @override String get match => 'Матч'; + @override String get timeWeightedmatch => 'Матч (взвешенная по времени)'; @override String roundNumber({required Object n}) => 'Раунд ${n}'; @override String get statsFor => 'Статистика за'; + @override String get numberOfRounds => 'Количество раундов'; @override String get matchLength => 'Продолжительность матча'; @override String get roundLength => 'Продолжительность раунда'; + @override String get matchStats => 'Статистика матча'; + @override String get timeWeightedmatchStats => 'Взвешенная по времени cтатистика матча'; @override String get replayIssue => 'Ошибка обработки повтора'; @override String get matchIsTooOld => 'Информация о повторе недоступна'; @override String get winner => 'Победитель'; @@ -952,6 +969,15 @@ class _StringsRu implements Translations { many: '${n} игроков', other: '${n} игроков', ); + @override String games({required num n}) => (_root.$meta.cardinalResolver ?? PluralResolvers.cardinal('ru'))(n, + zero: '${n} игр', + one: '${n} игра', + two: '${n} игры', + few: '${n} игры', + many: '${n} игр', + other: '${n} игр', + ); + @override String gamesPlayed({required Object games}) => '${games} сыграно'; @override String get chart => 'График'; @override String get entries => 'Список'; @override String get minimums => 'Минимумы'; @@ -1457,11 +1483,11 @@ extension on Translations { case 'noRecords': return 'No records'; case 'noOldRecords': return ({required num n}) => (_root.$meta.cardinalResolver ?? PluralResolvers.cardinal('en'))(n, zero: 'No records', - one: '${n} record', - two: '${n} records', - few: '${n} records', - many: '${n} records', - other: '${n} records', + one: 'Only ${n} record', + two: 'Only ${n} records', + few: 'Only ${n} records', + many: 'Only ${n} records', + other: 'Only ${n} records', ); case 'noRecord': return 'No record'; case 'botRecord': return 'Bots are not allowed to set records'; @@ -1486,7 +1512,7 @@ extension on Translations { case 'supporter': return ({required Object tier}) => 'Supporter tier ${tier}'; case 'comparingWith': return ({required Object newDate, required Object oldDate}) => 'Data from ${newDate} comparing with ${oldDate}'; case 'top': return 'Top'; - case 'topRank': return 'Top Rank'; + case 'topRank': return 'Top rank'; case 'verdictGeneral': return ({required Object n, required Object verdict, required Object rank}) => '${n} ${verdict} than ${rank} rank average'; case 'verdictBetter': return 'better'; case 'verdictWorse': return 'worse'; @@ -1545,10 +1571,14 @@ extension on Translations { case 'openReplay': return 'Open replay in TETR.IO'; case 'replaySaved': return ({required Object path}) => 'Replay saved to ${path}'; case 'match': return 'Match'; + case 'timeWeightedmatch': return 'Match (time-weighted)'; case 'roundNumber': return ({required Object n}) => 'Round ${n}'; case 'statsFor': return 'Stats for'; + case 'numberOfRounds': return 'Number of rounds'; case 'matchLength': return 'Match Length'; case 'roundLength': return 'Round Length'; + case 'matchStats': return 'Match stats'; + case 'timeWeightedmatchStats': return 'Time-weighted match stats'; case 'replayIssue': return 'Can\'t process replay'; case 'matchIsTooOld': return 'Replay is not available'; case 'winner': return 'Winner'; @@ -1585,6 +1615,15 @@ extension on Translations { many: '${n} players', other: '${n} players', ); + case 'games': return ({required num n}) => (_root.$meta.cardinalResolver ?? PluralResolvers.cardinal('en'))(n, + zero: '${n} games', + one: '${n} game', + two: '${n} games', + few: '${n} games', + many: '${n} games', + other: '${n} games', + ); + case 'gamesPlayed': return ({required Object games}) => '${games} played'; case 'chart': return 'Chart'; case 'entries': return 'Entries'; case 'minimums': return 'Minimums'; @@ -2053,7 +2092,7 @@ extension on _StringsRu { case 'assignedManualy': return 'Этот значок был присвоен вручную администрацией TETR.IO'; case 'comparingWith': return ({required Object newDate, required Object oldDate}) => 'Данные от ${newDate} в сравнении с данными от ${oldDate}'; case 'top': return 'Топ'; - case 'topRank': return 'Топ Ранг'; + case 'topRank': return 'Топ ранг'; case 'verdictGeneral': return ({required Object verdict, required Object rank, required Object n}) => '${verdict} среднего ${rank} ранга на ${n}'; case 'verdictBetter': return 'Лучше'; case 'verdictWorse': return 'Хуже'; @@ -2112,10 +2151,14 @@ extension on _StringsRu { case 'openReplay': return 'Открыть повтор в TETR.IO'; case 'replaySaved': return ({required Object path}) => 'Повтор сохранён по пути ${path}'; case 'match': return 'Матч'; + case 'timeWeightedmatch': return 'Матч (взвешенная по времени)'; case 'roundNumber': return ({required Object n}) => 'Раунд ${n}'; case 'statsFor': return 'Статистика за'; + case 'numberOfRounds': return 'Количество раундов'; case 'matchLength': return 'Продолжительность матча'; case 'roundLength': return 'Продолжительность раунда'; + case 'matchStats': return 'Статистика матча'; + case 'timeWeightedmatchStats': return 'Взвешенная по времени cтатистика матча'; case 'replayIssue': return 'Ошибка обработки повтора'; case 'matchIsTooOld': return 'Информация о повторе недоступна'; case 'winner': return 'Победитель'; @@ -2152,6 +2195,15 @@ extension on _StringsRu { many: '${n} игроков', other: '${n} игроков', ); + case 'games': return ({required num n}) => (_root.$meta.cardinalResolver ?? PluralResolvers.cardinal('ru'))(n, + zero: '${n} игр', + one: '${n} игра', + two: '${n} игры', + few: '${n} игры', + many: '${n} игр', + other: '${n} игр', + ); + case 'gamesPlayed': return ({required Object games}) => '${games} сыграно'; case 'chart': return 'График'; case 'entries': return 'Список'; case 'minimums': return 'Минимумы'; diff --git a/lib/services/tetrio_crud.dart b/lib/services/tetrio_crud.dart index 947ae12..a78532f 100644 --- a/lib/services/tetrio_crud.dart +++ b/lib/services/tetrio_crud.dart @@ -415,12 +415,12 @@ class TetrioService extends DB { // parsing data into TetraLeagueAlphaRecord objects for (var entry in csv){ TetraLeagueAlphaRecord match = TetraLeagueAlphaRecord( - replayId: entry[0], - ownId: entry[0], // i gonna disting p1nkl0bst3r entries with it + replayId: entry[0].toString(), + ownId: entry[0].toString(), // i gonna disting p1nkl0bst3r entries with it timestamp: DateTime.parse(entry[1]), endContext: [ EndContextMulti( - userId: entry[2], + userId: entry[2].toString(), username: entry[3].toString(), naturalOrder: 0, inputs: -1, @@ -437,7 +437,7 @@ class TetrioService extends DB { success: true ), EndContextMulti( - userId: entry[8], + userId: entry[8].toString(), username: entry[9].toString(), naturalOrder: 1, inputs: -1, diff --git a/lib/utils/colors_functions.dart b/lib/utils/colors_functions.dart new file mode 100644 index 0000000..70277d9 --- /dev/null +++ b/lib/utils/colors_functions.dart @@ -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; +} \ No newline at end of file diff --git a/lib/utils/numers_formats.dart b/lib/utils/numers_formats.dart index 3f626fc..412820d 100644 --- a/lib/utils/numers_formats.dart +++ b/lib/utils/numers_formats.dart @@ -7,4 +7,5 @@ final NumberFormat f4 = NumberFormat.decimalPatternDigits(locale: LocaleSettings final NumberFormat f3 = NumberFormat.decimalPatternDigits(locale: LocaleSettings.currentLocale.languageCode, decimalDigits: 3); final NumberFormat f2 = NumberFormat.decimalPatternDigits(locale: LocaleSettings.currentLocale.languageCode, decimalDigits: 2); final NumberFormat f2l = NumberFormat.decimalPatternDigits(locale: LocaleSettings.currentLocale.languageCode, decimalDigits: 2)..minimumFractionDigits = 0; -final NumberFormat f0 = NumberFormat.decimalPattern(LocaleSettings.currentLocale.languageCode); \ No newline at end of file +final NumberFormat f0 = NumberFormat.decimalPattern(LocaleSettings.currentLocale.languageCode); +final NumberFormat percentage = NumberFormat.percentPattern(LocaleSettings.currentLocale.languageCode)..maximumFractionDigits = 2; \ No newline at end of file diff --git a/lib/views/calc_view.dart b/lib/views/calc_view.dart index 7762c13..5688d26 100644 --- a/lib/views/calc_view.dart +++ b/lib/views/calc_view.dart @@ -66,76 +66,65 @@ class CalcState extends State { title: Text(t.statsCalc), ), backgroundColor: Colors.black, - body: SafeArea( + body: SingleChildScrollView( child: Center( child: Container( constraints: const BoxConstraints(maxWidth: 768), - child: NestedScrollView( - controller: _scrollController, - headerSliverBuilder: (context, value) { - return [ - SliverToBoxAdapter( - child: Padding( - padding: const EdgeInsets.fromLTRB(14, 16, 16, 32), - child: Row( - children: [ - Expanded( - child: Padding( - padding: const EdgeInsets.only(right: 12), - child: TextField( - onSubmitted: (value) => calc(), - controller: apmController, - keyboardType: TextInputType.number, - decoration: const InputDecoration(label: Text("APM"), alignLabelWithHint: true), - ), - )), - Expanded( - child: TextField( - onSubmitted: (value) => calc(), - controller: ppsController, - keyboardType: TextInputType.number, - decoration: const InputDecoration(label: Text("PPS"), alignLabelWithHint: true), - )), - Expanded( - child: Padding( - padding: const EdgeInsets.only(left: 12), - child: TextField( - onSubmitted: (value) => calc(), - controller: vsController, - keyboardType: TextInputType.number, - decoration: const InputDecoration(label: Text("VS"), alignLabelWithHint: true), - ), - )), - TextButton( - onPressed: () => calc(), - child: Text(t.calc), - ), - ], - ), + child: Column(children: [ + Padding( + padding: const EdgeInsets.fromLTRB(14, 16, 16, 32), + child: Row( + children: [ + Expanded( + child: Padding( + padding: const EdgeInsets.only(right: 12), + child: TextField( + onSubmitted: (value) => calc(), + controller: apmController, + keyboardType: TextInputType.number, + decoration: const InputDecoration(label: Text("APM"), alignLabelWithHint: true), ), + )), + Expanded( + child: TextField( + onSubmitted: (value) => calc(), + controller: ppsController, + keyboardType: TextInputType.number, + decoration: const InputDecoration(label: Text("PPS"), alignLabelWithHint: true), + )), + Expanded( + child: Padding( + padding: const EdgeInsets.only(left: 12), + child: TextField( + onSubmitted: (value) => calc(), + controller: vsController, + keyboardType: TextInputType.number, + decoration: const InputDecoration(label: Text("VS"), alignLabelWithHint: true), + ), + )), + TextButton( + onPressed: () => calc(), + child: Text(t.calc), ), - const SliverToBoxAdapter( - child: Divider(), - ) - ]; - }, - body: nerdStats == null - ? Text(t.calcViewNoValues) - : ListView( - children: [ - _ListEntry(value: nerdStats!.app, label: t.statCellNum.app.replaceAll(RegExp(r'\n'), " "), fractionDigits: 3), - _ListEntry(value: nerdStats!.vsapm, label: "VS/APM", fractionDigits: 3), - _ListEntry(value: nerdStats!.dss, label: t.statCellNum.dss.replaceAll(RegExp(r'\n'), " "), fractionDigits: 3), - _ListEntry(value: nerdStats!.dsp, label: t.statCellNum.dsp.replaceAll(RegExp(r'\n'), " "), fractionDigits: 3), - _ListEntry(value: nerdStats!.appdsp, label: "APP + DS/P", fractionDigits: 3), - _ListEntry(value: nerdStats!.cheese, label: t.statCellNum.cheese.replaceAll(RegExp(r'\n'), " "), fractionDigits: 3), - _ListEntry(value: nerdStats!.gbe, label: t.statCellNum.gbe.replaceAll(RegExp(r'\n'), " "), fractionDigits: 3), - _ListEntry(value: nerdStats!.nyaapp, label: t.statCellNum.nyaapp.replaceAll(RegExp(r'\n'), " "), fractionDigits: 3), - _ListEntry(value: nerdStats!.area, label: t.statCellNum.area.replaceAll(RegExp(r'\n'), " "), fractionDigits: 3), - _ListEntry(value: estTr!.esttr, label: t.statCellNum.estOfTR, fractionDigits: 3), - Graphs(apm!, pps!, vs!, nerdStats!, playstyle!), - ], - )), + ], + ), + ), + Divider(), + if (nerdStats == null) Text(t.calcViewNoValues) + else Column(children: [ + _ListEntry(value: nerdStats!.app, label: t.statCellNum.app.replaceAll(RegExp(r'\n'), " "), fractionDigits: 3), + _ListEntry(value: nerdStats!.vsapm, label: "VS/APM", fractionDigits: 3), + _ListEntry(value: nerdStats!.dss, label: t.statCellNum.dss.replaceAll(RegExp(r'\n'), " "), fractionDigits: 3), + _ListEntry(value: nerdStats!.dsp, label: t.statCellNum.dsp.replaceAll(RegExp(r'\n'), " "), fractionDigits: 3), + _ListEntry(value: nerdStats!.appdsp, label: "APP + DS/P", fractionDigits: 3), + _ListEntry(value: nerdStats!.cheese, label: t.statCellNum.cheese.replaceAll(RegExp(r'\n'), " "), fractionDigits: 3), + _ListEntry(value: nerdStats!.gbe, label: t.statCellNum.gbe.replaceAll(RegExp(r'\n'), " "), fractionDigits: 3), + _ListEntry(value: nerdStats!.nyaapp, label: t.statCellNum.nyaapp.replaceAll(RegExp(r'\n'), " "), fractionDigits: 3), + _ListEntry(value: nerdStats!.area, label: t.statCellNum.area.replaceAll(RegExp(r'\n'), " "), fractionDigits: 3), + _ListEntry(value: estTr!.esttr, label: t.statCellNum.estOfTR, fractionDigits: 3), + Graphs(apm!, pps!, vs!, nerdStats!, playstyle!) + ],) + ],), ), ), ), diff --git a/lib/views/compare_view.dart b/lib/views/compare_view.dart index 8ac89d9..44d0156 100644 --- a/lib/views/compare_view.dart +++ b/lib/views/compare_view.dart @@ -255,452 +255,433 @@ class CompareState extends State { return Scaffold( appBar: AppBar(title: Text("$titleGreenSide ${t.vs} $titleRedSide")), backgroundColor: Colors.black, - body: SafeArea( + body: SingleChildScrollView( + controller: _scrollController, + physics: AlwaysScrollableScrollPhysics(), child: Center( child: Container( constraints: const BoxConstraints(maxWidth: 768), - child: NestedScrollView( - controller: _scrollController, - headerSliverBuilder: (context, value) { - return [ - SliverToBoxAdapter( - child: Padding( - padding: const EdgeInsets.fromLTRB(16, 16, 16, 32), - child: Row( - mainAxisAlignment: MainAxisAlignment.spaceBetween, - crossAxisAlignment: CrossAxisAlignment.start, - children: [ - Expanded( - child: Container( - decoration: const BoxDecoration( - gradient: LinearGradient( - colors: [Colors.green, Colors.transparent], - begin: Alignment.bottomCenter, - end: Alignment.topCenter, - stops: [0.0, 0.4], - )), - child: Padding( - padding: const EdgeInsets.fromLTRB(8, 0, 8, 0), - child: PlayerSelector( - data: theGreenSide, - mode: greenSideMode, - fetch: fetchGreenSide, - change: changeGreenSide, - updateState: _justUpdate, - ), - ), - ), + child: Column(children: [ + Padding( + padding: const EdgeInsets.fromLTRB(16, 16, 16, 32), + child: Row( + mainAxisAlignment: MainAxisAlignment.spaceBetween, + crossAxisAlignment: CrossAxisAlignment.start, + children: [ + Expanded( + child: Container( + decoration: const BoxDecoration( + gradient: LinearGradient( + colors: [Colors.green, Colors.transparent], + begin: Alignment.bottomCenter, + end: Alignment.topCenter, + stops: [0.0, 0.4], + )), + child: Padding( + padding: const EdgeInsets.fromLTRB(8, 0, 8, 0), + child: PlayerSelector( + data: theGreenSide, + mode: greenSideMode, + fetch: fetchGreenSide, + change: changeGreenSide, + updateState: _justUpdate, ), - const Padding( - padding: EdgeInsets.only(top: 16), - child: Text("VS"), - ), - Expanded( - child: Container( - decoration: const BoxDecoration( - gradient: LinearGradient( - colors: [Colors.red, Colors.transparent], - begin: Alignment.bottomCenter, - end: Alignment.topCenter, - stops: [0.0, 0.4], - )), - child: Padding( - padding: const EdgeInsets.fromLTRB(8, 0, 8, 0), - child: PlayerSelector( - data: theRedSide, - mode: redSideMode, - fetch: fetchRedSide, - change: changeRedSide, - updateState: _justUpdate, - ), - ), - ), - ), - ], + ), ), ), - ), - const SliverToBoxAdapter( - child: Divider(), - ) - ]; - }, - 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( - children: [ - CompareRegTimeThingy( - greenSide: theGreenSide[0].registrationTime, - redSide: theRedSide[0].registrationTime, - label: t.registred), - CompareThingy( - label: t.statCellNum.level, - greenSide: theGreenSide[0].level, - redSide: theRedSide[0].level, - higherIsBetter: true, - fractionDigits: 2, - ), - if (!theGreenSide[0].gameTime.isNegative && - !theRedSide[0].gameTime.isNegative) - CompareThingy( - greenSide: theGreenSide[0].gameTime.inMicroseconds / - 1000000 / - 60 / - 60, - redSide: theRedSide[0].gameTime.inMicroseconds / - 1000000 / - 60 / - 60, - label: t.statCellNum.hoursPlayed.replaceAll(RegExp(r'\n'), " "), - higherIsBetter: true, - fractionDigits: 2, - ), - if (theGreenSide[0].gamesPlayed >= 0 && - theRedSide[0].gamesPlayed >= 0) - CompareThingy( - label: t.statCellNum.onlineGames.replaceAll(RegExp(r'\n'), " "), - greenSide: theGreenSide[0].gamesPlayed, - redSide: theRedSide[0].gamesPlayed, - higherIsBetter: true, - ), - if (theGreenSide[0].gamesWon >= 0 && - theRedSide[0].gamesWon >= 0) - CompareThingy( - label: t.statCellNum.gamesWon.replaceAll(RegExp(r'\n'), " "), - greenSide: theGreenSide[0].gamesWon, - redSide: theRedSide[0].gamesWon, - higherIsBetter: true, - ), - CompareThingy( - label: t.statCellNum.friends, - greenSide: theGreenSide[0].friendCount, - redSide: theRedSide[0].friendCount, - higherIsBetter: true, - ), - const Divider(), - ], - ), - if (theGreenSide[0] != null && - theRedSide[0] != null && - (theGreenSide[0]!.role == "banned" || - theRedSide[0]!.role == "banned")) - CompareBoolThingy( - greenSide: theGreenSide[0].role == "banned", - redSide: theRedSide[0].role == "banned", - label: t.normalBanned, - trueIsBetter: false), - (theGreenSide[2].gamesPlayed > 0 || greenSideMode == Mode.stats) && - (theRedSide[2].gamesPlayed > 0 || redSideMode == Mode.stats) - ? Column( - children: [ - Padding( - padding: const EdgeInsets.only(bottom: 16), - child: Text(t.tetraLeague, - style: TextStyle( - fontFamily: "Eurostile Round Extended", - fontSize: bigScreen ? 42 : 28)), - ), - if (theGreenSide[2].gamesPlayed > 9 && - theRedSide[2].gamesPlayed > 9 && - greenSideMode != Mode.stats && - redSideMode != Mode.stats) - CompareThingy( - label: "TR", - greenSide: theGreenSide[2].rating, - redSide: theRedSide[2].rating, - fractionDigits: 2, - higherIsBetter: true, - ), - if (greenSideMode != Mode.stats && - redSideMode != Mode.stats) - CompareThingy( - label: t.statCellNum.gamesPlayed.replaceAll(RegExp(r'\n'), " "), - greenSide: theGreenSide[2].gamesPlayed, - redSide: theRedSide[2].gamesPlayed, - higherIsBetter: true, - ), - if (greenSideMode != Mode.stats && - redSideMode != Mode.stats) - CompareThingy( - label: t.statCellNum.gamesWonTL.replaceAll(RegExp(r'\n'), " "), - greenSide: theGreenSide[2].gamesWon, - redSide: theRedSide[2].gamesWon, - higherIsBetter: true, - ), - if (greenSideMode != Mode.stats && - redSideMode != Mode.stats) - CompareThingy( - label: "WR %", - greenSide: - theGreenSide[2].winrate * 100, - redSide: theRedSide[2].winrate * 100, - fractionDigits: 2, - higherIsBetter: true, - ), - if (theGreenSide[2].gamesPlayed > 9 && - theRedSide[2].gamesPlayed > 9 && - greenSideMode != Mode.stats && - redSideMode != Mode.stats) - CompareThingy( - label: "Glicko", - greenSide: theGreenSide[2].glicko!, - redSide: theRedSide[2].glicko!, - fractionDigits: 2, - higherIsBetter: true, - ), - if (theGreenSide[2].gamesPlayed > 9 && - theRedSide[2].gamesPlayed > 9 && - greenSideMode != Mode.stats && - redSideMode != Mode.stats) - CompareThingy( - label: "RD", - greenSide: theGreenSide[2].rd!, - redSide: theRedSide[2].rd!, - fractionDigits: 3, - higherIsBetter: false, - ), - if (theGreenSide[2].standing > 0 && - theRedSide[2].standing > 0 && - greenSideMode == Mode.player && - redSideMode == Mode.player) - CompareThingy( - label: t.statCellNum.lbpShort, - greenSide: theGreenSide[2].standing, - redSide: theRedSide[2].standing, - higherIsBetter: false, - ), - if (theGreenSide[2].standingLocal > 0 && - theRedSide[2].standingLocal > 0 && - greenSideMode == Mode.player && - redSideMode == Mode.player) - CompareThingy( - label: t.statCellNum.lbpcShort, - greenSide: - theGreenSide[2].standingLocal, - redSide: theRedSide[2].standingLocal, - higherIsBetter: false, - ), - if (theGreenSide[2].apm != null && - theRedSide[2].apm != null) - CompareThingy( - label: "APM", - greenSide: theGreenSide[2].apm!, - redSide: theRedSide[2].apm!, - fractionDigits: 2, - higherIsBetter: true, - ), - if (theGreenSide[2].pps != null && - theRedSide[2].pps != null) - CompareThingy( - label: "PPS", - greenSide: theGreenSide[2].pps!, - redSide: theRedSide[2].pps!, - fractionDigits: 2, - higherIsBetter: true, - ), - if (theGreenSide[2].vs != null && - theRedSide[2].vs != null) - CompareThingy( - label: "VS", - greenSide: theGreenSide[2].vs!, - redSide: theRedSide[2].vs!, - fractionDigits: 2, - higherIsBetter: true, - ), - ], - ) - : CompareBoolThingy( - greenSide: theGreenSide[2].gamesPlayed > 0, - redSide: theRedSide[2].gamesPlayed > 0, - label: t.playedTL, - trueIsBetter: false), - const Divider(), - if (theGreenSide[2].nerdStats != null && - theRedSide[2].nerdStats != null) - Column( - children: [ - Padding( - padding: const EdgeInsets.only(bottom: 16), - child: Text(t.nerdStats, - style: TextStyle( - fontFamily: "Eurostile Round Extended", - fontSize: bigScreen ? 42 : 28)), - ), - CompareThingy( - label: "APP", - greenSide: theGreenSide[2].nerdStats!.app, - redSide: theRedSide[2].nerdStats!.app, - fractionDigits: 3, - higherIsBetter: true, - ), - CompareThingy( - label: "VS/APM", - greenSide: theGreenSide[2].nerdStats!.vsapm, - redSide: theRedSide[2].nerdStats!.vsapm, - fractionDigits: 3, - higherIsBetter: true, - ), - CompareThingy( - label: "DS/S", - greenSide: theGreenSide[2].nerdStats!.dss, - redSide: theRedSide[2].nerdStats!.dss, - fractionDigits: 3, - higherIsBetter: true, - ), - CompareThingy( - label: "DS/P", - greenSide: theGreenSide[2].nerdStats!.dsp, - redSide: theRedSide[2].nerdStats!.dsp, - fractionDigits: 3, - higherIsBetter: true, - ), - CompareThingy( - label: "APP + DS/P", - greenSide: - theGreenSide[2].nerdStats!.appdsp, - redSide: theRedSide[2].nerdStats!.appdsp, - fractionDigits: 3, - higherIsBetter: true, - ), - CompareThingy( - label: t.statCellNum.cheese.replaceAll(RegExp(r'\n'), " "), - greenSide: - theGreenSide[2].nerdStats!.cheese, - redSide: theRedSide[2].nerdStats!.cheese, - fractionDigits: 2, - higherIsBetter: true, - ), - CompareThingy( - label: "Gb Eff.", - greenSide: theGreenSide[2].nerdStats!.gbe, - redSide: theRedSide[2].nerdStats!.gbe, - fractionDigits: 3, - higherIsBetter: true, - ), - CompareThingy( - label: "wAPP", - greenSide: - theGreenSide[2].nerdStats!.nyaapp, - redSide: theRedSide[2].nerdStats!.nyaapp, - fractionDigits: 3, - higherIsBetter: true, - ), - CompareThingy( - label: "Area", - greenSide: theGreenSide[2].nerdStats!.area, - redSide: theRedSide[2].nerdStats!.area, - fractionDigits: 2, - higherIsBetter: true, - ), - CompareThingy( - label: t.statCellNum.estOfTRShort, - greenSide: theGreenSide[2].estTr!.esttr, - redSide: theRedSide[2].estTr!.esttr, - fractionDigits: 2, - higherIsBetter: true, - ), - if (theGreenSide[2].gamesPlayed > 9 && - theGreenSide[2].gamesPlayed > 9 && - greenSideMode != Mode.stats && - redSideMode != Mode.stats) - CompareThingy( - label: t.statCellNum.accOfEstShort, - greenSide: theGreenSide[2].esttracc!, - redSide: theRedSide[2].esttracc!, - fractionDigits: 2, - higherIsBetter: true, - ), - CompareThingy( - label: "Opener", - greenSide: theGreenSide[2].playstyle!.opener, - redSide: theRedSide[2].playstyle!.opener, - fractionDigits: 3, - higherIsBetter: true, - ), - CompareThingy( - label: "Plonk", - greenSide: theGreenSide[2].playstyle!.plonk, - redSide: theRedSide[2].playstyle!.plonk, - fractionDigits: 3, - higherIsBetter: true, - ), - CompareThingy( - label: "Stride", - greenSide: theGreenSide[2].playstyle!.stride, - redSide: theRedSide[2].playstyle!.stride, - fractionDigits: 3, - higherIsBetter: true, - ), - CompareThingy( - label: "Inf. DS", - greenSide: theGreenSide[2].playstyle!.infds, - redSide: theRedSide[2].playstyle!.infds, - fractionDigits: 3, - higherIsBetter: true, - ), - VsGraphs(theGreenSide[2].apm!, theGreenSide[2].pps!, theGreenSide[2].vs!, theGreenSide[2].nerdStats!, theGreenSide[2].playstyle!, theRedSide[2].apm!, theRedSide[2].pps!, theRedSide[2].vs!, theRedSide[2].nerdStats!, theRedSide[2].playstyle!), - const Divider(), - Padding( - padding: const EdgeInsets.only(bottom: 16), - child: Text(t.winChance, - style: TextStyle( - fontFamily: "Eurostile Round Extended", - fontSize: bigScreen ? 42 : 28)), - ), - if (greenSideMode != Mode.stats && redSideMode != Mode.stats && - theGreenSide[2].gamesPlayed > 9 && theRedSide[2].gamesPlayed > 9) - CompareThingy( - label: t.byGlicko, - greenSide: getWinrateByTR( - theGreenSide[2].glicko!, - theGreenSide[2].rd!, - theRedSide[2].glicko!, - theRedSide[2].rd!) * - 100, - redSide: getWinrateByTR( - theRedSide[2].glicko!, - theRedSide[2].rd!, - theGreenSide[2].glicko!, - theGreenSide[2].rd!) * - 100, - fractionDigits: 2, - higherIsBetter: true, - postfix: "%", - ), - CompareThingy( - label: t.byEstTR, - greenSide: getWinrateByTR( - theGreenSide[2].estTr!.estglicko, - theGreenSide[2].rd ?? noTrRd, - theRedSide[2].estTr!.estglicko, - theRedSide[2].rd ?? noTrRd) * - 100, - redSide: getWinrateByTR( - theRedSide[2].estTr!.estglicko, - theRedSide[2].rd ?? noTrRd, - theGreenSide[2].estTr!.estglicko, - theGreenSide[2].rd ?? noTrRd) * - 100, - fractionDigits: 2, - higherIsBetter: true, - postfix: "%", - ), - ], - ) - ] : [Padding( - padding: const EdgeInsets.all(8.0), - child: Text(t.compareViewNoValues(avgR: "\$avgR"), textAlign: TextAlign.center), - )], // This is so fucked up holy shit + const Padding( + padding: EdgeInsets.only(top: 16), + child: Text("VS"), + ), + Expanded( + child: Container( + decoration: const BoxDecoration( + gradient: LinearGradient( + colors: [Colors.red, Colors.transparent], + begin: Alignment.bottomCenter, + end: Alignment.topCenter, + stops: [0.0, 0.4], + )), + child: Padding( + padding: const EdgeInsets.fromLTRB(8, 0, 8, 0), + child: PlayerSelector( + data: theRedSide, + mode: redSideMode, + fetch: fetchRedSide, + change: changeRedSide, + updateState: _justUpdate, + ), ), + ), + ), + ], ), - ) + ), + Divider(), + if (!listEquals(theGreenSide, [null, null, null]) && !listEquals(theRedSide, [null, null, null])) Column( + children: [ + if (theGreenSide[0] != null && theRedSide[0] != null && theGreenSide[0]!.role != "banned" && theRedSide[0]!.role != "banned") + Column( + children: [ + CompareRegTimeThingy( + greenSide: theGreenSide[0].registrationTime, + redSide: theRedSide[0].registrationTime, + label: t.registred), + CompareThingy( + label: t.statCellNum.level, + greenSide: theGreenSide[0].level, + redSide: theRedSide[0].level, + higherIsBetter: true, + fractionDigits: 2, + ), + if (!theGreenSide[0].gameTime.isNegative && !theRedSide[0].gameTime.isNegative) + CompareThingy( + greenSide: theGreenSide[0].gameTime.inMicroseconds / + 1000000 / + 60 / + 60, + redSide: theRedSide[0].gameTime.inMicroseconds / + 1000000 / + 60 / + 60, + label: t.statCellNum.hoursPlayed.replaceAll(RegExp(r'\n'), " "), + higherIsBetter: true, + fractionDigits: 2, + ), + if (theGreenSide[0].gamesPlayed >= 0 && theRedSide[0].gamesPlayed >= 0) + CompareThingy( + label: t.statCellNum.onlineGames.replaceAll(RegExp(r'\n'), " "), + greenSide: theGreenSide[0].gamesPlayed, + redSide: theRedSide[0].gamesPlayed, + higherIsBetter: true, + ), + if (theGreenSide[0].gamesWon >= 0 && theRedSide[0].gamesWon >= 0) + CompareThingy( + label: t.statCellNum.gamesWon.replaceAll(RegExp(r'\n'), " "), + greenSide: theGreenSide[0].gamesWon, + redSide: theRedSide[0].gamesWon, + higherIsBetter: true, + ), + CompareThingy( + label: t.statCellNum.friends, + greenSide: theGreenSide[0].friendCount, + redSide: theRedSide[0].friendCount, + higherIsBetter: true, + ), + const Divider(), + ], + ), + if (theGreenSide[0] != null && theRedSide[0] != null && (theGreenSide[0]!.role == "banned" || theRedSide[0]!.role == "banned")) + CompareBoolThingy( + greenSide: theGreenSide[0].role == "banned", + redSide: theRedSide[0].role == "banned", + label: t.normalBanned, + trueIsBetter: false + ), + (theGreenSide[2].gamesPlayed > 0 || greenSideMode == Mode.stats) && (theRedSide[2].gamesPlayed > 0 || redSideMode == Mode.stats) + ? Column( + children: [ + Padding( + padding: const EdgeInsets.only(bottom: 16), + child: Text(t.tetraLeague, + style: TextStyle( + fontFamily: "Eurostile Round Extended", + fontSize: bigScreen ? 42 : 28)), + ), + if (theGreenSide[2].gamesPlayed > 9 && + theRedSide[2].gamesPlayed > 9 && + greenSideMode != Mode.stats && + redSideMode != Mode.stats) + CompareThingy( + label: "TR", + greenSide: theGreenSide[2].rating, + redSide: theRedSide[2].rating, + fractionDigits: 2, + higherIsBetter: true, + ), + if (greenSideMode != Mode.stats && + redSideMode != Mode.stats) + CompareThingy( + label: t.statCellNum.gamesPlayed.replaceAll(RegExp(r'\n'), " "), + greenSide: theGreenSide[2].gamesPlayed, + redSide: theRedSide[2].gamesPlayed, + higherIsBetter: true, + ), + if (greenSideMode != Mode.stats && + redSideMode != Mode.stats) + CompareThingy( + label: t.statCellNum.gamesWonTL.replaceAll(RegExp(r'\n'), " "), + greenSide: theGreenSide[2].gamesWon, + redSide: theRedSide[2].gamesWon, + higherIsBetter: true, + ), + if (greenSideMode != Mode.stats && + redSideMode != Mode.stats) + CompareThingy( + label: "WR %", + greenSide: + theGreenSide[2].winrate * 100, + redSide: theRedSide[2].winrate * 100, + fractionDigits: 2, + higherIsBetter: true, + ), + if (theGreenSide[2].gamesPlayed > 9 && + theRedSide[2].gamesPlayed > 9 && + greenSideMode != Mode.stats && + redSideMode != Mode.stats) + CompareThingy( + label: "Glicko", + greenSide: theGreenSide[2].glicko!, + redSide: theRedSide[2].glicko!, + fractionDigits: 2, + higherIsBetter: true, + ), + if (theGreenSide[2].gamesPlayed > 9 && + theRedSide[2].gamesPlayed > 9 && + greenSideMode != Mode.stats && + redSideMode != Mode.stats) + CompareThingy( + label: "RD", + greenSide: theGreenSide[2].rd!, + redSide: theRedSide[2].rd!, + fractionDigits: 3, + higherIsBetter: false, + ), + if (theGreenSide[2].standing > 0 && + theRedSide[2].standing > 0 && + greenSideMode == Mode.player && + redSideMode == Mode.player) + CompareThingy( + label: t.statCellNum.lbpShort, + greenSide: theGreenSide[2].standing, + redSide: theRedSide[2].standing, + higherIsBetter: false, + ), + if (theGreenSide[2].standingLocal > 0 && + theRedSide[2].standingLocal > 0 && + greenSideMode == Mode.player && + redSideMode == Mode.player) + CompareThingy( + label: t.statCellNum.lbpcShort, + greenSide: + theGreenSide[2].standingLocal, + redSide: theRedSide[2].standingLocal, + higherIsBetter: false, + ), + if (theGreenSide[2].apm != null && + theRedSide[2].apm != null) + CompareThingy( + label: "APM", + greenSide: theGreenSide[2].apm!, + redSide: theRedSide[2].apm!, + fractionDigits: 2, + higherIsBetter: true, + ), + if (theGreenSide[2].pps != null && + theRedSide[2].pps != null) + CompareThingy( + label: "PPS", + greenSide: theGreenSide[2].pps!, + redSide: theRedSide[2].pps!, + fractionDigits: 2, + higherIsBetter: true, + ), + if (theGreenSide[2].vs != null && + theRedSide[2].vs != null) + CompareThingy( + label: "VS", + greenSide: theGreenSide[2].vs!, + redSide: theRedSide[2].vs!, + fractionDigits: 2, + higherIsBetter: true, + ), + ], + ) + : CompareBoolThingy( + greenSide: theGreenSide[2].gamesPlayed > 0, + redSide: theRedSide[2].gamesPlayed > 0, + label: t.playedTL, + trueIsBetter: false), + const Divider(), + if (theGreenSide[2].nerdStats != null && + theRedSide[2].nerdStats != null) + Column( + children: [ + Padding( + padding: const EdgeInsets.only(bottom: 16), + child: Text(t.nerdStats, + style: TextStyle( + fontFamily: "Eurostile Round Extended", + fontSize: bigScreen ? 42 : 28)), + ), + CompareThingy( + label: "APP", + greenSide: theGreenSide[2].nerdStats!.app, + redSide: theRedSide[2].nerdStats!.app, + fractionDigits: 3, + higherIsBetter: true, + ), + CompareThingy( + label: "VS/APM", + greenSide: theGreenSide[2].nerdStats!.vsapm, + redSide: theRedSide[2].nerdStats!.vsapm, + fractionDigits: 3, + higherIsBetter: true, + ), + CompareThingy( + label: "DS/S", + greenSide: theGreenSide[2].nerdStats!.dss, + redSide: theRedSide[2].nerdStats!.dss, + fractionDigits: 3, + higherIsBetter: true, + ), + CompareThingy( + label: "DS/P", + greenSide: theGreenSide[2].nerdStats!.dsp, + redSide: theRedSide[2].nerdStats!.dsp, + fractionDigits: 3, + higherIsBetter: true, + ), + CompareThingy( + label: "APP + DS/P", + greenSide: + theGreenSide[2].nerdStats!.appdsp, + redSide: theRedSide[2].nerdStats!.appdsp, + fractionDigits: 3, + higherIsBetter: true, + ), + CompareThingy( + label: t.statCellNum.cheese.replaceAll(RegExp(r'\n'), " "), + greenSide: + theGreenSide[2].nerdStats!.cheese, + redSide: theRedSide[2].nerdStats!.cheese, + fractionDigits: 2, + higherIsBetter: true, + ), + CompareThingy( + label: "Gb Eff.", + greenSide: theGreenSide[2].nerdStats!.gbe, + redSide: theRedSide[2].nerdStats!.gbe, + fractionDigits: 3, + higherIsBetter: true, + ), + CompareThingy( + label: "wAPP", + greenSide: + theGreenSide[2].nerdStats!.nyaapp, + redSide: theRedSide[2].nerdStats!.nyaapp, + fractionDigits: 3, + higherIsBetter: true, + ), + CompareThingy( + label: "Area", + greenSide: theGreenSide[2].nerdStats!.area, + redSide: theRedSide[2].nerdStats!.area, + fractionDigits: 2, + higherIsBetter: true, + ), + CompareThingy( + label: t.statCellNum.estOfTRShort, + greenSide: theGreenSide[2].estTr!.esttr, + redSide: theRedSide[2].estTr!.esttr, + fractionDigits: 2, + higherIsBetter: true, + ), + if (theGreenSide[2].gamesPlayed > 9 && + theGreenSide[2].gamesPlayed > 9 && + greenSideMode != Mode.stats && + redSideMode != Mode.stats) + CompareThingy( + label: t.statCellNum.accOfEstShort, + greenSide: theGreenSide[2].esttracc!, + redSide: theRedSide[2].esttracc!, + fractionDigits: 2, + higherIsBetter: true, + ), + CompareThingy( + label: "Opener", + greenSide: theGreenSide[2].playstyle!.opener, + redSide: theRedSide[2].playstyle!.opener, + fractionDigits: 3, + higherIsBetter: true, + ), + CompareThingy( + label: "Plonk", + greenSide: theGreenSide[2].playstyle!.plonk, + redSide: theRedSide[2].playstyle!.plonk, + fractionDigits: 3, + higherIsBetter: true, + ), + CompareThingy( + label: "Stride", + greenSide: theGreenSide[2].playstyle!.stride, + redSide: theRedSide[2].playstyle!.stride, + fractionDigits: 3, + higherIsBetter: true, + ), + CompareThingy( + label: "Inf. DS", + greenSide: theGreenSide[2].playstyle!.infds, + redSide: theRedSide[2].playstyle!.infds, + fractionDigits: 3, + higherIsBetter: true, + ), + VsGraphs(theGreenSide[2].apm!, theGreenSide[2].pps!, theGreenSide[2].vs!, theGreenSide[2].nerdStats!, theGreenSide[2].playstyle!, theRedSide[2].apm!, theRedSide[2].pps!, theRedSide[2].vs!, theRedSide[2].nerdStats!, theRedSide[2].playstyle!), + const Divider(), + Padding( + padding: const EdgeInsets.only(bottom: 16), + child: Text(t.winChance, + style: TextStyle( + fontFamily: "Eurostile Round Extended", + fontSize: bigScreen ? 42 : 28)), + ), + if (greenSideMode != Mode.stats && redSideMode != Mode.stats && + theGreenSide[2].gamesPlayed > 9 && theRedSide[2].gamesPlayed > 9) + CompareThingy( + label: t.byGlicko, + greenSide: getWinrateByTR( + theGreenSide[2].glicko!, + theGreenSide[2].rd!, + theRedSide[2].glicko!, + theRedSide[2].rd!) * + 100, + redSide: getWinrateByTR( + theRedSide[2].glicko!, + theRedSide[2].rd!, + theGreenSide[2].glicko!, + theGreenSide[2].rd!) * + 100, + fractionDigits: 2, + higherIsBetter: true, + postfix: "%", + ), + CompareThingy( + label: t.byEstTR, + greenSide: getWinrateByTR( + theGreenSide[2].estTr!.estglicko, + theGreenSide[2].rd ?? noTrRd, + theRedSide[2].estTr!.estglicko, + theRedSide[2].rd ?? noTrRd) * + 100, + redSide: getWinrateByTR( + theRedSide[2].estTr!.estglicko, + theRedSide[2].rd ?? noTrRd, + theGreenSide[2].estTr!.estglicko, + theGreenSide[2].rd ?? noTrRd) * + 100, + fractionDigits: 2, + higherIsBetter: true, + postfix: "%", + ), + ], + ) + ], + ) + else Padding( + padding: const EdgeInsets.all(8.0), + child: Text(t.compareViewNoValues(avgR: "\$avgR"), textAlign: TextAlign.center), + ) + ], ), ), ), diff --git a/lib/views/main_view.dart b/lib/views/main_view.dart index fb890d6..c7e46e0 100644 --- a/lib/views/main_view.dart +++ b/lib/views/main_view.dart @@ -34,7 +34,7 @@ import 'package:go_router/go_router.dart'; final TetrioService teto = TetrioService(); // thing, that manadge our local DB 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"]; late ScrollController _scrollController; final NumberFormat _timeInSec = NumberFormat("#,###.###s.", LocaleSettings.currentLocale.languageCode); @@ -85,6 +85,7 @@ class _MainState extends State with TickerProviderStateMixin { String _titleNickname = "dan63047"; /// Each dropdown menu item contains list of dots for the graph var chartsData = >>[]; + var chartsDataGamesPlayed = >>[]; //var tableData = []; final bodyGlobalKey = GlobalKey(); bool _showSearchBar = false; @@ -283,6 +284,29 @@ class _MainState extends State 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!.stride)], child: const Text("Stride")), ]; + chartsDataGamesPlayed = >>[ // 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{ compareWith = null; chartsData = []; @@ -393,8 +417,7 @@ class _MainState extends State with TickerProviderStateMixin { return notification.depth == 0; }, child: NestedScrollView( - scrollBehavior: ScrollConfiguration.of(context).copyWith(scrollbars: false), - physics: const AlwaysScrollableScrollPhysics(), + scrollBehavior: ScrollConfiguration.of(context).copyWith(scrollbars: false, physics: const AlwaysScrollableScrollPhysics()), controller: _scrollController, headerSliverBuilder: (context, value) { return [ @@ -448,10 +471,10 @@ class _MainState extends State with TickerProviderStateMixin { ), SizedBox( 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,), _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 with TickerProviderStateMixin { lbPositions: meAmongEveryone ), _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]['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],) @@ -664,10 +687,11 @@ class _TLRecords extends StatelessWidget { final List data; final bool wasActiveInTL; final bool oldMathcesHere; + final bool separateScrollController; /// Widget, that displays Tetra League records. /// 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 Widget build(BuildContext context) { @@ -685,7 +709,7 @@ class _TLRecords extends StatelessWidget { int length = data.length; return ListView.builder( physics: const AlwaysScrollableScrollPhysics(), - controller: ScrollController(), + controller: separateScrollController ? ScrollController() : null, itemCount: oldMathcesHere ? length : length + 1, itemBuilder: (BuildContext context, int index) { if (index == length) { @@ -708,7 +732,6 @@ class _TLRecords extends StatelessWidget { ) ), 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}", 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}"), @@ -730,6 +753,7 @@ class _TLRecords extends StatelessWidget { class _History extends StatelessWidget{ final List>> chartsData; + final List>> chartsDataGamesPlayed; final String userID; final Function update; 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. /// 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 Widget build(BuildContext context) { @@ -763,15 +787,25 @@ class _History extends StatelessWidget{ Wrap( spacing: 20, children: [ - // DropdownButton( - // items: [DropdownMenuItem(child: Text("Chart"), value: false), DropdownMenuItem(child: Text("Table"), value: true)], - // value: _showHistoryAsTable, - // onChanged: (value) { - // _showHistoryAsTable = value!; - // update(); - // } - // ), - DropdownButton( + Row( + mainAxisSize: MainAxisSize.min, + children: [ + const Padding(padding: EdgeInsets.all(8.0), child: Text("X:", style: TextStyle(fontSize: 22))), + DropdownButton( + 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( items: chartsData, value: chartsData[_chartsIndex].value, onChanged: (value) { @@ -779,10 +813,12 @@ class _History extends StatelessWidget{ update(); } ), + ], + ), ], ), - 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, children: [ 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)) ], )) - // 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 double leftSpace; 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. /// [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 - 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 State<_HistoryChartThigy> createState() => _HistoryChartThigyState(); @@ -819,6 +852,7 @@ class _HistoryChartThigy extends StatefulWidget{ class _HistoryChartThigyState extends State<_HistoryChartThigy> { late String previousAxisTitle; + late bool previousGamesPlayedInsteadOfDateAndTime; late double minX; late double maxX; late double minY; @@ -840,6 +874,7 @@ class _HistoryChartThigyState extends State<_HistoryChartThigy> { maxX = widget.data.last.x; setMinMaxY(); previousAxisTitle = widget.yAxisTitle; + previousGamesPlayedInsteadOfDateAndTime = _gamesPlayedInsteadOfDateAndTime; actualMaxY = maxY; actualMinY = minY; recalculateScales(); @@ -945,15 +980,19 @@ class _HistoryChartThigyState extends State<_HistoryChartThigy> { @override Widget build(BuildContext context) { 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); double graphStartX = padding.left+widget.leftSpace; double graphEndX = MediaQuery.sizeOf(context).width - padding.right; - if (previousAxisTitle != widget.yAxisTitle) { - setMinMaxY(); - recalculateScales(); - previousAxisTitle = widget.yAxisTitle; - } return SizedBox( width: MediaQuery.of(context).size.width, 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){ return value != meta.min && value != meta.max ? SideTitleWidget( 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(); })), leftTitles: AxisTitles(sideTitles: SideTitles(showTitles: true, reservedSize: widget.leftSpace, getTitlesWidget: (double value, TitleMeta meta){ @@ -1048,7 +1087,7 @@ class _HistoryChartThigyState extends State<_HistoryChartThigy> { } else { hoveredPointId = touchResponse!.lineBarSpots!.first.spotIndex; 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( text: TextSpan( 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: [ TextSpan(text: blitz != null ? NumberFormat.decimalPattern().format(blitz!.endContext!.score) : "---"), //WidgetSpan(child: Image.asset("res/icons/kagari.png", height: 48)) @@ -1295,6 +1334,7 @@ class _RecordThingy extends StatelessWidget { builder: (context, constraints) { bool bigScreen = constraints.maxWidth > 768; return SingleChildScrollView( + controller: _scrollController, child: Padding( padding: const EdgeInsets.only(top: 8.0), child: Column( diff --git a/lib/views/ranks_averages_view.dart b/lib/views/ranks_averages_view.dart index 02f4e56..b82d8f3 100644 --- a/lib/views/ranks_averages_view.dart +++ b/lib/views/ranks_averages_view.dart @@ -54,7 +54,8 @@ class RanksAverages extends State { return ListTile( leading: Image.asset("res/tetrio_tl_alpha_ranks/${keys[index]}.png", height: 48), title: Text(t.players(n: averages[keys[index]]?[1]["players"]), style: const TextStyle(fontFamily: "Eurostile Round Extended")), - subtitle: Text("${f2.format(averages[keys[index]]?[0].apm)} APM, ${f2.format(averages[keys[index]]?[0].pps)} PPS, ${f2.format(averages[keys[index]]?[0].vs)} VS, ${f2.format(averages[keys[index]]?[0].nerdStats.app)} APP, ${f2.format(averages[keys[index]]?[0].nerdStats.vsapm)} VS/APM"), + subtitle: Text("${f2.format(averages[keys[index]]?[0].apm)} APM, ${f2.format(averages[keys[index]]?[0].pps)} PPS, ${f2.format(averages[keys[index]]?[0].vs)} VS, ${f2.format(averages[keys[index]]?[0].nerdStats.app)} APP, ${f2.format(averages[keys[index]]?[0].nerdStats.vsapm)} VS/APM", + style: TextStyle(fontFamily: "Eurostile Round Condensed", color: Colors.grey)), trailing: Text("${f2.format(averages[keys[index]]?[1]["toEnterTR"])} TR", style: bigScreen ? const TextStyle(fontSize: 28) : null), onTap: (){ if (averages[keys[index]]?[1]["players"] > 0) { diff --git a/lib/views/tl_leaderboard_view.dart b/lib/views/tl_leaderboard_view.dart index 7eb9f29..7fb2422 100644 --- a/lib/views/tl_leaderboard_view.dart +++ b/lib/views/tl_leaderboard_view.dart @@ -175,7 +175,8 @@ class TLLeaderboardState extends State { return ListTile( leading: Text((index+1).toString(), style: bigScreen ? const TextStyle(fontFamily: "Eurostile Round Extended", fontSize: 28) : null), title: Text(allPlayers[index].username, style: const TextStyle(fontFamily: "Eurostile Round Extended")), - subtitle: Text(_sortBy == Stats.tr ? "${f2.format(allPlayers[index].apm)} APM, ${f2.format(allPlayers[index].pps)} PPS, ${f2.format(allPlayers[index].vs)} VS, ${f2.format(allPlayers[index].nerdStats.app)} APP, ${f2.format(allPlayers[index].nerdStats.vsapm)} VS/APM" : "${_f4.format(allPlayers[index].getStatByEnum(_sortBy))} ${chartsShortTitles[_sortBy]}"), + subtitle: Text(_sortBy == Stats.tr ? "${f2.format(allPlayers[index].apm)} APM, ${f2.format(allPlayers[index].pps)} PPS, ${f2.format(allPlayers[index].vs)} VS, ${f2.format(allPlayers[index].nerdStats.app)} APP, ${f2.format(allPlayers[index].nerdStats.vsapm)} VS/APM" : "${_f4.format(allPlayers[index].getStatByEnum(_sortBy))} ${chartsShortTitles[_sortBy]}", + style: TextStyle(fontFamily: "Eurostile Round Condensed", color: _sortBy == Stats.tr ? Colors.grey : null)), trailing: Row( mainAxisSize: MainAxisSize.min, children: [ diff --git a/lib/views/tl_match_view.dart b/lib/views/tl_match_view.dart index 660dc44..202bfb0 100644 --- a/lib/views/tl_match_view.dart +++ b/lib/views/tl_match_view.dart @@ -70,7 +70,7 @@ class TlMatchResultState extends State { timeWeightedStatsAvaliable = true; if (snapshot.connectionState != ConnectionState.done) return const LinearProgressIndicator(); 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); redSidePlayer = snapshot.data!.endcontext.indexWhere((element) => element.userId != widget.initPlayerId); if (roundSelector.isNegative){ @@ -81,7 +81,6 @@ class TlMatchResultState extends State { readableTime = "${t.roundLength}: ${time.inMinutes}:${secs.format(time.inMicroseconds /1000000 % 60)}\n${t.winner}: ${snapshot.data!.roundWinners[roundSelector][1]}"; } }else{ - timeWeightedStatsAvaliable = false; switch (snapshot.error.runtimeType){ case ReplayNotAvalable: reason = t.matchIsTooOld; @@ -509,7 +508,7 @@ class TlMatchResultState extends State { RichText( text: TextSpan( text: "${time.inMinutes}:${NumberFormat("00", LocaleSettings.currentLocale.languageCode).format(time.inSeconds%60)}", - style: const TextStyle(fontFamily: "Eurostile Round Extended", fontSize: 28, fontWeight: FontWeight.w500), + 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))] ), ) @@ -533,6 +532,7 @@ class TlMatchResultState extends State { reason = snapshot.error.toString(); break; } + timeWeightedStatsAvaliable = false; return Column( crossAxisAlignment: CrossAxisAlignment.start, children: [ @@ -553,15 +553,15 @@ class TlMatchResultState extends State { if (widget.record.ownId != widget.record.replayId) Column( crossAxisAlignment: CrossAxisAlignment.end, children: [ - const Text("Number of rounds"), + Text(t.numberOfRounds), RichText( 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( fontFamily: "Eurostile Round Extended", fontSize: 28, 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 { OverflowBar( alignment: MainAxisAlignment.spaceEvenly, children: [ - TextButton( child: const Text('Match stats'), - style: roundSelector == -1 ? ButtonStyle(backgroundColor: MaterialStatePropertyAll(Colors.grey.shade900)) : null, + TextButton( style: roundSelector == -1 ? ButtonStyle(backgroundColor: MaterialStatePropertyAll(Colors.grey.shade900)) : null, onPressed: () { roundSelector = -1; setState(() {}); - }), - TextButton( child: const Text('Time-weighted match stats'), - style: roundSelector == -2 ? ButtonStyle(backgroundColor: MaterialStatePropertyAll(Colors.grey.shade900)) : null, + }, child: Text(t.matchStats)), + TextButton( style: roundSelector == -2 ? ButtonStyle(backgroundColor: MaterialStatePropertyAll(Colors.grey.shade900)) : null, onPressed: timeWeightedStatsAvaliable ? () { roundSelector = -2; setState(() {}); - } : null) , + } : null, child: Text(t.timeWeightedmatchStats)) , //TextButton( child: const Text('Button 3'), onPressed: () {}), ], ) @@ -624,7 +622,7 @@ class TlMatchResultState extends State { leading:RichText( text: TextSpan( text: "${time.inMinutes}:${NumberFormat("00", LocaleSettings.currentLocale.languageCode).format(time.inSeconds%60)}", - style: const TextStyle(fontFamily: "Eurostile Round", fontSize: 22, fontWeight: FontWeight.w500), + 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))] ), ), @@ -682,7 +680,7 @@ class TlMatchResultState extends State { } Widget getMainWidget(double viewportWidth) { - if (viewportWidth <= 1024) { + if (viewportWidth <= 1200) { return Center( child: Container( constraints: const BoxConstraints(maxWidth: 768), @@ -692,9 +690,8 @@ class TlMatchResultState extends State { } else { return Row( mainAxisAlignment: MainAxisAlignment.center, - //mainAxisSize: MainAxisSize.min, children: [ - Container( + SizedBox( width: 768, child: buildComparison(true, false) ), @@ -729,28 +726,7 @@ class TlMatchResultState extends State { onSelected: (value) async { switch (value) { case 1: - if (kIsWeb){ - // final _base64 = base64Encode([1,2,3,4,5]); - // final anchor = AnchorElement(href: 'data:application/octet-stream;base64,$_base64')..target = 'blank'; - //final anchor = AnchorElement(href: 'https://inoue.szy.lol/api/replay/${widget.record.replayId}')..target = 'blank'; - //anchor.download = "${widget.record.replayId}.ttrm"; - //document.body!.append(anchor); - //anchor.click(); - //anchor.remove(); - } else{ - 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))); - } - } + await launchInBrowser(Uri.parse("https://inoue.szy.lol/api/replay/${widget.record.replayId}")); break; case 2: await launchInBrowser(Uri.parse("https://tetr.io/#r:${widget.record.replayId}")); diff --git a/lib/widgets/gauget_num.dart b/lib/widgets/gauget_num.dart index b33362d..a255908 100644 --- a/lib/widgets/gauget_num.dart +++ b/lib/widgets/gauget_num.dart @@ -2,6 +2,7 @@ import 'package:flutter/material.dart'; import 'package:syncfusion_flutter_gauges/gauges.dart'; import 'package:tetra_stats/data_objects/tetrio.dart'; import 'package:tetra_stats/gen/strings.g.dart'; +import 'package:tetra_stats/utils/colors_functions.dart'; import 'package:tetra_stats/utils/numers_formats.dart'; import 'package:tetra_stats/widgets/tl_thingy.dart'; @@ -98,7 +99,7 @@ class GaugetNum extends StatelessWidget { oldPlayerStat! < playerStat ? Colors.redAccent : Colors.greenAccent ),), if ((oldTl != null && oldTl!.gamesPlayed > 0) && pos != null) const TextSpan(text: " • "), - if (pos != null) TextSpan(text: pos!.position >= 1000 ? "${t.top} ${f2.format(pos!.percentage*100)}%" : "№${pos!.position}") + if (pos != null) TextSpan(text: pos!.position >= 1000 ? "${t.top} ${f2.format(pos!.percentage*100)}%" : "№${pos!.position}", style: TextStyle(color: getColorOfRank(pos!.position))) ] ), ), diff --git a/lib/widgets/graphs.dart b/lib/widgets/graphs.dart index cadb397..caf65cb 100644 --- a/lib/widgets/graphs.dart +++ b/lib/widgets/graphs.dart @@ -1,10 +1,7 @@ import 'package:fl_chart/fl_chart.dart'; import 'package:flutter/material.dart'; -import 'package:intl/intl.dart'; import 'package:tetra_stats/data_objects/tetrio.dart'; -import 'package:tetra_stats/gen/strings.g.dart'; - -final NumberFormat _f2 = NumberFormat.decimalPatternDigits(locale: LocaleSettings.currentLocale.languageCode, decimalDigits: 2); +import 'package:tetra_stats/utils/numers_formats.dart'; class Graphs extends StatelessWidget{ const Graphs( @@ -125,13 +122,13 @@ class Graphs extends StatelessWidget{ getTitle: (index, angle) { switch (index) { case 0: - return RadarChartTitle(text: 'Opener\n${_f2.format(playstyle.opener)}', angle: 0, positionPercentageOffset: 0.05); + return RadarChartTitle(text: 'Opener\n${percentage.format(playstyle.opener)}', angle: 0, positionPercentageOffset: 0.05); case 1: - return RadarChartTitle(text: 'Stride\n${_f2.format(playstyle.stride)}', angle: 0, positionPercentageOffset: 0.05); + return RadarChartTitle(text: 'Stride\n${percentage.format(playstyle.stride)}', angle: 0, positionPercentageOffset: 0.05); case 2: - return RadarChartTitle(text: 'Inf Ds\n${_f2.format(playstyle.infds)}', angle: angle + 180, positionPercentageOffset: 0.05); + return RadarChartTitle(text: 'Inf Ds\n${percentage.format(playstyle.infds)}', angle: angle + 180, positionPercentageOffset: 0.05); case 3: - return RadarChartTitle(text: 'Plonk\n${_f2.format(playstyle.plonk)}', angle: 0, positionPercentageOffset: 0.05); + return RadarChartTitle(text: 'Plonk\n${percentage.format(playstyle.plonk)}', angle: 0, positionPercentageOffset: 0.05); default: return const RadarChartTitle(text: ''); } diff --git a/lib/widgets/lineclears_thingy.dart b/lib/widgets/lineclears_thingy.dart index 35b8d3f..2536891 100644 --- a/lib/widgets/lineclears_thingy.dart +++ b/lib/widgets/lineclears_thingy.dart @@ -15,7 +15,7 @@ class LineclearsThingy extends StatelessWidget{ return Wrap( spacing: 20, children: [ - Container( + SizedBox( width: 150, child: Column( mainAxisSize: MainAxisSize.min, @@ -30,7 +30,7 @@ class LineclearsThingy extends StatelessWidget{ ], ), ), - Container( + SizedBox( width: 150, child: Column( mainAxisSize: MainAxisSize.min, diff --git a/lib/widgets/stat_sell_num.dart b/lib/widgets/stat_sell_num.dart index 8ea21a6..4a5ca7c 100644 --- a/lib/widgets/stat_sell_num.dart +++ b/lib/widgets/stat_sell_num.dart @@ -2,6 +2,7 @@ import 'package:flutter/material.dart'; import 'package:intl/intl.dart'; import 'package:tetra_stats/data_objects/tetrio.dart'; import 'package:tetra_stats/gen/strings.g.dart'; +import 'package:tetra_stats/utils/colors_functions.dart'; import 'package:tetra_stats/utils/numers_formats.dart'; class StatCellNum extends StatelessWidget { @@ -70,7 +71,7 @@ class StatCellNum extends StatelessWidget { oldPlayerStat! < playerStat ? Colors.redAccent : Colors.greenAccent ),), if (oldPlayerStat != null && pos != null) const TextSpan(text: " • "), - if (pos != null) TextSpan(text: pos!.position >= 1000 ? "${t.top} ${f2.format(pos!.percentage*100)}%" : "№${pos!.position}") + if (pos != null) TextSpan(text: pos!.position >= 1000 ? "${t.top} ${f2.format(pos!.percentage*100)}%" : "№${pos!.position}", style: TextStyle(color: getColorOfRank(pos!.position))) ] ), ), diff --git a/lib/widgets/tl_thingy.dart b/lib/widgets/tl_thingy.dart index fbcda33..b5bb240 100644 --- a/lib/widgets/tl_thingy.dart +++ b/lib/widgets/tl_thingy.dart @@ -4,6 +4,7 @@ import 'package:tetra_stats/data_objects/tetrio.dart'; import 'package:syncfusion_flutter_gauges/gauges.dart'; import 'package:tetra_stats/gen/strings.g.dart'; import 'package:tetra_stats/main.dart'; +import 'package:tetra_stats/utils/colors_functions.dart'; import 'package:tetra_stats/utils/numers_formats.dart'; import 'package:tetra_stats/widgets/gauget_num.dart'; import 'package:tetra_stats/widgets/graphs.dart'; @@ -299,7 +300,7 @@ class _TLThingyState extends State { //alignment: Alignment.center, width: bigScreen ? MediaQuery.of(context).size.width * 0.4 : MediaQuery.of(context).size.width * 0.85, height: 70, - constraints: BoxConstraints(maxWidth: 768), + constraints: const BoxConstraints(maxWidth: 768), child: Stack( children: [ Positioned( @@ -307,12 +308,12 @@ class _TLThingyState extends State { child: Column( crossAxisAlignment: CrossAxisAlignment.start, children: [ - Text(t.statCellNum.estOfTR, style: TextStyle(height: 0.1),), + Text(t.statCellNum.estOfTR, style: const TextStyle(height: 0.1),), RichText( text: TextSpan( text: intf.format(currentTl.estTr!.esttr.truncate()), style: TextStyle(fontFamily: "Eurostile Round Extended", fontSize: bigScreen ? 36 : 30, fontWeight: FontWeight.w500, color: Colors.white), - children: [TextSpan(text: fractionfEstTR.format(currentTl.estTr!.esttr - currentTl.estTr!.esttr.truncate()).substring(1), style: 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( @@ -323,7 +324,7 @@ class _TLThingyState extends State { color: oldTl!.estTr!.esttr > currentTl.estTr!.esttr ? Colors.redAccent : Colors.greenAccent ),), if (oldTl?.estTr?.esttr != null && widget.lbPositions?.estTr != null) const TextSpan(text: " • "), - if (widget.lbPositions?.estTr != null) TextSpan(text: widget.lbPositions!.estTr!.position >= 1000 ? "${t.top} ${f2.format(widget.lbPositions!.estTr!.percentage*100)}%" : "№${widget.lbPositions!.estTr!.position}"), + if (widget.lbPositions?.estTr != null) TextSpan(text: widget.lbPositions!.estTr!.position >= 1000 ? "${t.top} ${f2.format(widget.lbPositions!.estTr!.percentage*100)}%" : "№${widget.lbPositions!.estTr!.position}", style: TextStyle(color: getColorOfRank(widget.lbPositions!.estTr!.position))), if (widget.lbPositions?.estTr != null) const TextSpan(text: " • "), TextSpan(text: "Glicko: ${f2.format(currentTl.estTr!.estglicko)}") ] @@ -342,7 +343,7 @@ class _TLThingyState extends State { text: (currentTl.esttracc != null && currentTl.bestRank != "z") ? intFDiff.format(currentTl.esttracc!.truncate()) : "---", style: TextStyle(fontFamily: "Eurostile Round", fontSize: bigScreen ? 36 : 30, fontWeight: FontWeight.w500, color: Colors.white), children: [ - TextSpan(text: (currentTl.esttracc != null && currentTl.bestRank != "z") ? fractionfEstTRAcc.format(currentTl.esttracc!.isNegative ? 1 - (currentTl.esttracc! - currentTl.esttracc!.truncate()) : (currentTl.esttracc! - currentTl.esttracc!.truncate())).substring(1) : ".---", style: 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 { color: oldTl!.esttracc! > currentTl.esttracc! ? Colors.redAccent : Colors.greenAccent ),), if (oldTl?.esttracc != null && widget.lbPositions?.accOfEst != null) const TextSpan(text: " • "), - if (widget.lbPositions?.accOfEst != null) TextSpan(text: widget.lbPositions!.accOfEst!.position >= 1000 ? "${t.top} ${f2.format(widget.lbPositions!.accOfEst!.percentage*100)}%" : "№${widget.lbPositions!.accOfEst!.position}") + 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))) ] ), ), diff --git a/lib/widgets/user_thingy.dart b/lib/widgets/user_thingy.dart index 653b33e..a900051 100644 --- a/lib/widgets/user_thingy.dart +++ b/lib/widgets/user_thingy.dart @@ -339,7 +339,7 @@ class UserThingy extends StatelessWidget { children: [ if (player.country != null) TextSpan(text: "${t.countries[player.country]} • "), TextSpan(text: "${t.playerRole[player.role]}${t.playerRoleAccount}${player.registrationTime == null ? t.wasFromBeginning : '${t.created} ${dateFormat.format(player.registrationTime!)}'}"), - if (player.supporterTier > 0) 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) TextSpan(text: player.supporterTier.toString(), style: TextStyle(color: player.supporterTier > 1 ? Colors.yellowAccent : Colors.white)) ] diff --git a/pubspec.lock b/pubspec.lock index 43f3c9c..ff532e5 100644 --- a/pubspec.lock +++ b/pubspec.lock @@ -5,26 +5,26 @@ packages: dependency: transitive description: name: _fe_analyzer_shared - sha256: eb376e9acf6938204f90eb3b1f00b578640d3188b4c8a8ec054f9f479af8d051 + sha256: "0b2f2bd91ba804e53a61d757b986f89f1f9eaed5b11e4b2f5a2468d86d6c9fc7" url: "https://pub.dev" source: hosted - version: "64.0.0" + version: "67.0.0" analyzer: dependency: transitive description: name: analyzer - sha256: "69f54f967773f6c26c7dcb13e93d7ccee8b17a641689da39e878d5cf13b06893" + sha256: "37577842a27e4338429a1cbc32679d508836510b056f1eedf0c8d20e39c1383d" url: "https://pub.dev" source: hosted - version: "6.2.0" + version: "6.4.1" archive: dependency: transitive description: name: archive - sha256: "7b875fd4a20b165a3084bd2d210439b22ebc653f21cea4842729c0c30c82596b" + sha256: "22600aa1e926be775fa5fe7e6894e7fb3df9efda8891c73f70fb3262399a432d" url: "https://pub.dev" source: hosted - version: "3.4.9" + version: "3.4.10" args: dependency: transitive description: @@ -141,10 +141,10 @@ packages: dependency: transitive description: name: dev_build - sha256: e476ac99174842cdb01e64c1d379d041d2150f9ad2cdd2713eb1ca1bdbf30507 + sha256: e5d575f3de4b0e5f004e065e1e2d98fa012d634b61b5855216b5698ed7f1e443 url: "https://pub.dev" source: hosted - version: "0.16.3+2" + version: "0.16.4+3" equatable: dependency: transitive description: @@ -165,10 +165,10 @@ packages: dependency: transitive description: name: ffi - sha256: "7bf0adc28a23d395f19f3f1eb21dd7cfd1dd9f8e1c50051c069122e6853bc878" + sha256: "493f37e7df1804778ff3a53bd691d8692ddf69702cf4c1c1096a2e41b4779e21" url: "https://pub.dev" source: hosted - version: "2.1.0" + version: "2.1.2" file: dependency: transitive description: @@ -181,34 +181,34 @@ packages: dependency: "direct main" description: name: file_picker - sha256: "4e42aacde3b993c5947467ab640882c56947d9d27342a5b6f2895b23956954a6" + sha256: "1bbf65dd997458a08b531042ec3794112a6c39c07c37ff22113d2e7e4f81d4e4" url: "https://pub.dev" source: hosted - version: "6.1.1" + version: "6.2.1" file_selector: dependency: "direct main" description: name: file_selector - sha256: "84eaf3e034d647859167d1f01cfe7b6352488f34c1b4932635012b202014c25b" + sha256: "5019692b593455127794d5718304ff1ae15447dea286cdda9f0db2a796a1b828" url: "https://pub.dev" source: hosted - version: "1.0.1" + version: "1.0.3" file_selector_android: dependency: transitive description: name: file_selector_android - sha256: b7556052dbcc25ef88f6eba45ab98aa5600382af8dfdabc9d644a93d97b7be7f + sha256: "1cd66575f063b689e041aec836905ba7be18d76c9f0634d0d75daec825f67095" url: "https://pub.dev" source: hosted - version: "0.5.0+4" + version: "0.5.0+7" file_selector_ios: dependency: transitive description: name: file_selector_ios - sha256: "2f48db7e338b2255101c35c604b7ca5ab588dce032db7fc418a2fe5f28da63f8" + sha256: b015154e6d9fddbc4d08916794df170b44531798c8dd709a026df162d07ad81d url: "https://pub.dev" source: hosted - version: "0.5.1+7" + version: "0.5.1+8" file_selector_linux: dependency: transitive description: @@ -229,10 +229,10 @@ packages: dependency: transitive description: name: file_selector_platform_interface - sha256: "0aa47a725c346825a2bd396343ce63ac00bda6eff2fbc43eabe99737dede8262" + sha256: a3994c26f10378a039faa11de174d7b78eb8f79e4dd0af2a451410c1a5c3f66b url: "https://pub.dev" source: hosted - version: "2.6.1" + version: "2.6.2" file_selector_web: dependency: transitive description: @@ -253,10 +253,10 @@ packages: dependency: "direct main" description: name: fl_chart - sha256: fe6fec7d85975a99c73b9515a69a6e291364accfa0e4a5b3ce6de814d74b9a1c + sha256: "00b74ae680df6b1135bdbea00a7d1fc072a9180b7c3f3702e4b19a9943f5ed7d" url: "https://pub.dev" source: hosted - version: "0.66.0" + version: "0.66.2" flutter: dependency: "direct main" description: flutter @@ -295,10 +295,10 @@ packages: dependency: "direct main" description: name: flutter_markdown - sha256: "35108526a233cc0755664d445f8a6b4b61e6f8fe993b3658b80b4a26827fc196" + sha256: "87e11b9df25a42e2db315b8b7a51fae8e66f57a4b2f50ec4b822d0fa155e6b52" url: "https://pub.dev" source: hosted - version: "0.6.18+2" + version: "0.6.22" flutter_plugin_android_lifecycle: dependency: transitive description: @@ -311,10 +311,10 @@ packages: dependency: "direct main" description: name: flutter_svg - sha256: d39e7f95621fc84376bc0f7d504f05c3a41488c562f4a8ad410569127507402c + sha256: "7b4ca6cf3304575fe9c8ec64813c8d02ee41d2afe60bcfe0678bcb5375d596a2" url: "https://pub.dev" source: hosted - version: "2.0.9" + version: "2.0.10+1" flutter_test: dependency: "direct dev" description: flutter @@ -345,18 +345,18 @@ packages: dependency: "direct main" description: name: go_router - sha256: ca7e4a2249f96773152f1853fa25933ac752495cdd7fdf5dafb9691bd05830fd + sha256: "7ecb2f391edbca5473db591b48555a8912dde60edd0fb3013bd6743033b2d3f8" url: "https://pub.dev" source: hosted - version: "13.0.0" + version: "13.2.1" http: dependency: "direct main" description: name: http - sha256: d4872660c46d929f6b8a9ef4e7a7eff7e49bbf0c4ec3f385ee32df5119175139 + sha256: a2bbf9d017fcced29139daa8ed2bba4ece450ab222871df93ca9eec6f80c34ba url: "https://pub.dev" source: hosted - version: "1.1.2" + version: "1.2.0" http_multi_server: dependency: transitive description: @@ -377,10 +377,10 @@ packages: dependency: transitive description: name: image - sha256: "028f61960d56f26414eb616b48b04eb37d700cbe477b7fb09bf1d7ce57fd9271" + sha256: "4c68bfd5ae83e700b5204c1e74451e7bf3cf750e6843c6e158289cf56bda018e" url: "https://pub.dev" source: hosted - version: "4.1.3" + version: "4.1.7" intl: dependency: "direct main" description: @@ -421,6 +421,30 @@ packages: url: "https://pub.dev" source: hosted version: "4.8.1" + leak_tracker: + dependency: transitive + description: + name: leak_tracker + sha256: "78eb209deea09858f5269f5a5b02be4049535f568c07b275096836f01ea323fa" + url: "https://pub.dev" + source: hosted + version: "10.0.0" + leak_tracker_flutter_testing: + dependency: transitive + description: + name: leak_tracker_flutter_testing + sha256: b46c5e37c19120a8a01918cfaf293547f47269f7cb4b0058f21531c2465d6ef0 + url: "https://pub.dev" + source: hosted + version: "2.0.1" + leak_tracker_testing: + dependency: transitive + description: + name: leak_tracker_testing + sha256: a597f72a664dbd293f3bfc51f9ba69816f84dcd403cdac7066cb3f6003f3ab47 + url: "https://pub.dev" + source: hosted + version: "2.0.1" lints: dependency: transitive description: @@ -441,34 +465,34 @@ packages: dependency: transitive description: name: markdown - sha256: acf35edccc0463a9d7384e437c015a3535772e09714cf60e07eeef3a15870dcd + sha256: ef2a1298144e3f985cc736b22e0ccdaf188b5b3970648f2d9dc13efd1d9df051 url: "https://pub.dev" source: hosted - version: "7.1.1" + version: "7.2.2" matcher: dependency: transitive description: name: matcher - sha256: "1803e76e6653768d64ed8ff2e1e67bea3ad4b923eb5c56a295c3e634bad5960e" + sha256: d2323aa2060500f906aa31a895b4030b6da3ebdcc5619d14ce1aada65cd161cb url: "https://pub.dev" source: hosted - version: "0.12.16" + version: "0.12.16+1" material_color_utilities: dependency: transitive description: name: material_color_utilities - sha256: "9528f2f296073ff54cb9fee677df673ace1218163c3bc7628093e7eed5203d41" + sha256: "0e0a020085b65b6083975e499759762399b4475f766c21668c4ecca34ea74e5a" url: "https://pub.dev" source: hosted - version: "0.5.0" + version: "0.8.0" meta: dependency: transitive description: name: meta - sha256: a6e590c838b18133bb482a2745ad77c5bb7715fb0451209e1a7567d416678b8e + sha256: d584fa6707a52763a52446f02cc621b077888fb63b93bbcb1143a7be5a0c0c04 url: "https://pub.dev" source: hosted - version: "1.10.0" + version: "1.11.0" mime: dependency: transitive description: @@ -513,10 +537,10 @@ packages: dependency: "direct main" description: name: path - sha256: "8829d8a55c13fc0e37127c29fedf290c102f4e40ae94ada574091fe0ff96c917" + sha256: "087ce49c3f0dc39180befefc60fdb4acd8f8620e5682fe2476afd0b3688bb4af" url: "https://pub.dev" source: hosted - version: "1.8.3" + version: "1.9.0" path_parsing: dependency: transitive description: @@ -529,26 +553,26 @@ packages: dependency: "direct main" description: name: path_provider - sha256: a1aa8aaa2542a6bc57e381f132af822420216c80d4781f7aa085ca3229208aaa + sha256: b27217933eeeba8ff24845c34003b003b2b22151de3c908d0e679e8fe1aa078b url: "https://pub.dev" source: hosted - version: "2.1.1" + version: "2.1.2" path_provider_android: dependency: transitive description: name: path_provider_android - sha256: e595b98692943b4881b219f0a9e3945118d3c16bd7e2813f98ec6e532d905f72 + sha256: "477184d672607c0a3bf68fbbf601805f92ef79c82b64b4d6eb318cbca4c48668" url: "https://pub.dev" source: hosted - version: "2.2.1" + version: "2.2.2" path_provider_foundation: dependency: transitive description: name: path_provider_foundation - sha256: "19314d595120f82aca0ba62787d58dde2cc6b5df7d2f0daf72489e38d1b57f2d" + sha256: "5a7999be66e000916500be4f15a3633ebceb8302719b47b9cc49ce924125350f" url: "https://pub.dev" source: hosted - version: "2.3.1" + version: "2.3.2" path_provider_linux: dependency: transitive description: @@ -561,10 +585,10 @@ packages: dependency: transitive description: name: path_provider_platform_interface - sha256: "94b1e0dd80970c1ce43d5d4e050a9918fce4f4a775e6142424c30a29a363265c" + sha256: "88f5779f72ba699763fa3a3b06aa4bf6de76c8e5de842cf6f29e2e06476c2334" url: "https://pub.dev" source: hosted - version: "2.1.1" + version: "2.1.2" path_provider_windows: dependency: transitive description: @@ -585,26 +609,26 @@ packages: dependency: transitive description: name: platform - sha256: "0a279f0707af40c890e80b1e9df8bb761694c074ba7e1d4ab1bc4b728e200b59" + sha256: "12220bb4b65720483f8fa9450b4332347737cf8213dd2840d8b2c823e47243ec" url: "https://pub.dev" source: hosted - version: "3.1.3" + version: "3.1.4" plugin_platform_interface: dependency: transitive description: name: plugin_platform_interface - sha256: f4f88d4a900933e7267e2b353594774fc0d07fb072b47eedcd5b54e1ea3269f8 + sha256: "4820fbfdb9478b1ebae27888254d445073732dae3d6ea81f0b7e06d5dedc3f02" url: "https://pub.dev" source: hosted - version: "2.1.7" + version: "2.1.8" pointycastle: dependency: transitive description: name: pointycastle - sha256: "7c1e5f0d23c9016c5bbd8b1473d0d3fb3fc851b876046039509e18e0c7485f2c" + sha256: "43ac87de6e10afabc85c445745a7b799e04de84cebaa4fd7bf55a5e1e9604d29" url: "https://pub.dev" source: hosted - version: "3.7.3" + version: "3.7.4" pool: dependency: transitive description: @@ -617,10 +641,10 @@ packages: dependency: transitive description: name: process_run - sha256: "3d5335d17003a7c2fd5148be2d313f5b84244ab2e625162fdd44b4aaa48bea66" + sha256: "8d9c6198b98fbbfb511edd42e7364e24d85c163e47398919871b952dc86a423e" url: "https://pub.dev" source: hosted - version: "0.13.3+1" + version: "0.14.2" pub_semver: dependency: transitive description: @@ -657,10 +681,10 @@ packages: dependency: transitive description: name: shared_preferences_foundation - sha256: "7bf53a9f2d007329ee6f3df7268fd498f8373602f943c975598bbb34649b62a7" + sha256: "7708d83064f38060c7b39db12aefe449cb8cdc031d6062280087bc4cdb988f5c" url: "https://pub.dev" source: hosted - version: "2.3.4" + version: "2.3.5" shared_preferences_linux: dependency: transitive description: @@ -673,10 +697,10 @@ packages: dependency: transitive description: name: shared_preferences_platform_interface - sha256: d4ec5fc9ebb2f2e056c617112aa75dcf92fc2e4faaf2ae999caa297473f75d8a + sha256: "22e2ecac9419b4246d7c22bfbbda589e3acf5c0351137d87dd2939d984d37c3b" url: "https://pub.dev" source: hosted - version: "2.3.1" + version: "2.3.2" shared_preferences_web: dependency: transitive description: @@ -734,18 +758,18 @@ packages: dependency: "direct main" description: name: slang - sha256: "77fd99f7b0da15e671ef0289b24a0a63e74f693c58a0ca54111388e4c0ddb1dd" + sha256: "5e08ac915ac27a3508863f37734280d30c3713d56746cd2e4a5da77413da4b95" url: "https://pub.dev" source: hosted - version: "3.28.0" + version: "3.30.1" slang_flutter: dependency: "direct main" description: name: slang_flutter - sha256: "57817bb15553bb5df37aed3bac497286bdd8c2eab6763f4de6815efe2c0becee" + sha256: "9ee040b0d364d3a4d692e4af536acff6ef513870689403494ebc6d59b0dccea6" url: "https://pub.dev" source: hosted - version: "3.28.0" + version: "3.30.0" source_map_stack_trace: dependency: transitive description: @@ -774,50 +798,50 @@ packages: dependency: "direct main" description: name: sqflite - sha256: "591f1602816e9c31377d5f008c2d9ef7b8aca8941c3f89cc5fd9d84da0c38a9a" + sha256: a9016f495c927cb90557c909ff26a6d92d9bd54fc42ba92e19d4e79d61e798c6 url: "https://pub.dev" source: hosted - version: "2.3.0" + version: "2.3.2" sqflite_common: dependency: transitive description: name: sqflite_common - sha256: bb4738f15b23352822f4c42a531677e5c6f522e079461fd240ead29d8d8a54a6 + sha256: "3da423ce7baf868be70e2c0976c28a1bb2f73644268b7ffa7d2e08eab71f16a4" url: "https://pub.dev" source: hosted - version: "2.5.0+2" + version: "2.5.4" sqflite_common_ffi: dependency: "direct main" description: name: sqflite_common_ffi - sha256: "873677ee78738a723d1ded4ccb23980581998d873d30ee9c331f6a81748663ff" + sha256: "4d6137c29e930d6e4a8ff373989dd9de7bac12e3bc87bce950f6e844e8ad3bb5" url: "https://pub.dev" source: hosted - version: "2.3.1" + version: "2.3.3" sqflite_common_ffi_web: dependency: "direct main" description: name: sqflite_common_ffi_web - sha256: "3d4b550a09fda9eb0a9ce3bd98c8080f57b2cc1f4b19e844290e82843e73b63d" + sha256: "0c2921454d2e4a227675fb952be9fef916cf65fb9e9b606b54cfdf080d3e9450" url: "https://pub.dev" source: hosted - version: "0.4.2+2" + version: "0.4.2+3" sqlite3: dependency: transitive description: name: sqlite3 - sha256: c4a4c5a4b2a32e2d0f6837b33d7c91a67903891a5b7dbe706cf4b1f6b0c798c5 + sha256: "072128763f1547e3e9b4735ce846bfd226d68019ccda54db4cd427b12dfdedc9" url: "https://pub.dev" source: hosted - version: "2.3.0" + version: "2.4.0" sqlite3_flutter_libs: dependency: "direct main" description: name: sqlite3_flutter_libs - sha256: "3e3583b77cf888a68eae2e49ee4f025f66b86623ef0d83c297c8d903daa14871" + sha256: d6c31c8511c441d1f12f20b607343df1afe4eddf24a1cf85021677c8eea26060 url: "https://pub.dev" source: hosted - version: "0.5.18" + version: "0.5.20" stack_trace: dependency: transitive description: @@ -846,18 +870,18 @@ packages: dependency: transitive description: name: syncfusion_flutter_core - sha256: "69c827931957d5b121ee9f0b9b0b8d7d0d1ac537b61bcdd5c3fbffc044bbe86e" + sha256: "7666506885ebc8f62bb928ad4588a73e20caaff2b2cf2b2b56f67d98f4113525" url: "https://pub.dev" source: hosted - version: "24.1.41" + version: "24.2.9" syncfusion_flutter_gauges: dependency: "direct main" description: name: syncfusion_flutter_gauges - sha256: "78515dcfbed952c36ab9ca4a1e6c99737beb7c6cf2312efe8beca2bd314a3955" + sha256: "87be13e520fc1676a725691446f411f549ea5b6ff2580234db0479799f213757" url: "https://pub.dev" source: hosted - version: "24.1.41" + version: "24.2.9" synchronized: dependency: transitive description: @@ -910,26 +934,26 @@ packages: dependency: "direct main" description: name: url_launcher - sha256: e9aa5ea75c84cf46b3db4eea212523591211c3cf2e13099ee4ec147f54201c86 + sha256: "0ecc004c62fd3ed36a2ffcbe0dd9700aee63bd7532d0b642a488b1ec310f492e" url: "https://pub.dev" source: hosted - version: "6.2.2" + version: "6.2.5" url_launcher_android: dependency: transitive description: name: url_launcher_android - sha256: "31222ffb0063171b526d3e569079cf1f8b294075ba323443fdc690842bfd4def" + sha256: d4ed0711849dd8e33eb2dd69c25db0d0d3fdc37e0a62e629fe32f57a22db2745 url: "https://pub.dev" source: hosted - version: "6.2.0" + version: "6.3.0" url_launcher_ios: dependency: transitive description: name: url_launcher_ios - sha256: bba3373219b7abb6b5e0d071b0fe66dfbe005d07517a68e38d4fc3638f35c6d3 + sha256: "9149d493b075ed740901f3ee844a38a00b33116c7c5c10d7fb27df8987fb51d5" url: "https://pub.dev" source: hosted - version: "6.2.1" + version: "6.2.5" url_launcher_linux: dependency: transitive description: @@ -950,18 +974,18 @@ packages: dependency: transitive description: name: url_launcher_platform_interface - sha256: "980e8d9af422f477be6948bdfb68df8433be71f5743a188968b0c1b887807e50" + sha256: "552f8a1e663569be95a8190206a38187b531910283c3e982193e4f2733f01029" url: "https://pub.dev" source: hosted - version: "2.2.0" + version: "2.3.2" url_launcher_web: dependency: transitive description: name: url_launcher_web - sha256: "7286aec002c8feecc338cc33269e96b73955ab227456e9fb2a91f7fab8a358e9" + sha256: fff0932192afeedf63cdd50ecbb1bc825d31aed259f02bb8dba0f3b729a5e88b url: "https://pub.dev" source: hosted - version: "2.2.2" + version: "2.2.3" url_launcher_windows: dependency: transitive description: @@ -974,26 +998,26 @@ packages: dependency: transitive description: name: vector_graphics - sha256: "0f0c746dd2d6254a0057218ff980fc7f5670fd0fcf5e4db38a490d31eed4ad43" + sha256: "32c3c684e02f9bc0afb0ae0aa653337a2fe022e8ab064bcd7ffda27a74e288e3" url: "https://pub.dev" source: hosted - version: "1.1.9+1" + version: "1.1.11+1" vector_graphics_codec: dependency: transitive description: name: vector_graphics_codec - sha256: "0edf6d630d1bfd5589114138ed8fada3234deacc37966bec033d3047c29248b7" + sha256: c86987475f162fadff579e7320c7ddda04cd2fdeffbe1129227a85d9ac9e03da url: "https://pub.dev" source: hosted - version: "1.1.9+1" + version: "1.1.11+1" vector_graphics_compiler: dependency: transitive description: name: vector_graphics_compiler - sha256: d24333727332d9bd20990f1483af4e09abdb9b1fc7c3db940b56ab5c42790c26 + sha256: "12faff3f73b1741a36ca7e31b292ddeb629af819ca9efe9953b70bd63fc8cd81" url: "https://pub.dev" source: hosted - version: "1.1.9+1" + version: "1.1.11+1" vector_math: dependency: "direct main" description: @@ -1022,18 +1046,18 @@ packages: dependency: transitive description: name: web - sha256: afe077240a270dcfd2aafe77602b4113645af95d0ad31128cc02bce5ac5d5152 + sha256: "4188706108906f002b3a293509234588823c8c979dc83304e229ff400c996b05" url: "https://pub.dev" source: hosted - version: "0.3.0" + version: "0.4.2" web_socket_channel: dependency: transitive description: name: web_socket_channel - sha256: d88238e5eac9a42bb43ca4e721edba3c08c6354d4a53063afaa568516217621b + sha256: "939ab60734a4f8fa95feacb55804fa278de28bdeef38e616dc08e44a84adea23" url: "https://pub.dev" source: hosted - version: "2.4.0" + version: "2.4.3" webkit_inspection_protocol: dependency: transitive description: @@ -1046,26 +1070,26 @@ packages: dependency: transitive description: name: win32 - sha256: b0f37db61ba2f2e9b7a78a1caece0052564d1bc70668156cf3a29d676fe4e574 + sha256: "8cb58b45c47dcb42ab3651533626161d6b67a2921917d8d429791f76972b3480" url: "https://pub.dev" source: hosted - version: "5.1.1" + version: "5.3.0" window_manager: dependency: "direct main" description: name: window_manager - sha256: dcc865277f26a7dad263a47d0e405d77e21f12cb71f30333a52710a408690bd7 + sha256: b3c895bdf936c77b83c5254bec2e6b3f066710c1f89c38b20b8acc382b525494 url: "https://pub.dev" source: hosted - version: "0.3.7" + version: "0.3.8" xdg_directories: dependency: transitive description: name: xdg_directories - sha256: "589ada45ba9e39405c198fe34eb0f607cddb2108527e658136120892beac46d2" + sha256: faea9dee56b520b55a566385b84f2e8de55e7496104adada9962e0bd11bcff1d url: "https://pub.dev" source: hosted - version: "1.0.3" + version: "1.0.4" xml: dependency: transitive description: @@ -1083,5 +1107,5 @@ packages: source: hosted version: "3.1.2" sdks: - dart: ">=3.2.0 <4.0.0" - flutter: ">=3.16.0" + dart: ">=3.3.0 <4.0.0" + flutter: ">=3.19.0" diff --git a/pubspec.yaml b/pubspec.yaml index a2fd891..acb5c88 100644 --- a/pubspec.yaml +++ b/pubspec.yaml @@ -2,7 +2,7 @@ name: tetra_stats description: Track your and other player stats in TETR.IO publish_to: 'none' -version: 1.4.1+15 +version: 1.5.0+16 environment: sdk: '>=3.0.0' diff --git a/res/i18n/strings.i18n.json b/res/i18n/strings.i18n.json index 63ec0f8..ba3cb2b 100644 --- a/res/i18n/strings.i18n.json +++ b/res/i18n/strings.i18n.json @@ -48,11 +48,11 @@ "noRecords": "No records", "noOldRecords": { "zero": "No records", - "one": "$n record", - "two": "$n records", - "few": "$n records", - "many": "$n records", - "other": "$n records" + "one": "Only $n record", + "two": "Only $n records", + "few": "Only $n records", + "many": "Only $n records", + "other": "Only $n records" }, "noRecord": "No record", "botRecord": "Bots are not allowed to set records", @@ -77,7 +77,7 @@ "supporter": "Supporter tier ${tier}", "comparingWith": "Data from ${newDate} comparing with ${oldDate}", "top": "Top", - "topRank": "Top Rank", + "topRank": "Top rank", "verdictGeneral": "$n $verdict than $rank rank average", "verdictBetter": "better", "verdictWorse": "worse", @@ -136,10 +136,14 @@ "openReplay": "Open replay in TETR.IO", "replaySaved": "Replay saved to ${path}", "match": "Match", + "timeWeightedmatch": "Match (time-weighted)", "roundNumber": "Round $n", "statsFor": "Stats for", + "numberOfRounds": "Number of rounds", "matchLength": "Match Length", "roundLength": "Round Length", + "matchStats": "Match stats", + "timeWeightedmatchStats": "Time-weighted match stats", "replayIssue": "Can't process replay", "matchIsTooOld": "Replay is not available", "winner": "Winner", @@ -176,6 +180,15 @@ "many": "$n players", "other": "$n players" }, + "games": { + "zero": "$n games", + "one": "$n game", + "two": "$n games", + "few": "$n games", + "many": "$n games", + "other": "$n games" + }, + "gamesPlayed": "$games played", "chart": "Chart", "entries": "Entries", "minimums": "Minimums", diff --git a/res/i18n/strings_ru.i18n.json b/res/i18n/strings_ru.i18n.json index 6911667..88dcfad 100644 --- a/res/i18n/strings_ru.i18n.json +++ b/res/i18n/strings_ru.i18n.json @@ -77,7 +77,7 @@ "assignedManualy": "Этот значок был присвоен вручную администрацией TETR.IO", "comparingWith": "Данные от ${newDate} в сравнении с данными от ${oldDate}", "top": "Топ", - "topRank": "Топ Ранг", + "topRank": "Топ ранг", "verdictGeneral": "$verdict среднего $rank ранга на $n", "verdictBetter": "Лучше", "verdictWorse": "Хуже", @@ -136,10 +136,14 @@ "openReplay": "Открыть повтор в TETR.IO", "replaySaved": "Повтор сохранён по пути ${path}", "match": "Матч", + "timeWeightedmatch": "Матч (взвешенная по времени)", "roundNumber": "Раунд $n", "statsFor": "Статистика за", + "numberOfRounds": "Количество раундов", "matchLength": "Продолжительность матча", "roundLength": "Продолжительность раунда", + "matchStats": "Статистика матча", + "timeWeightedmatchStats": "Взвешенная по времени cтатистика матча", "replayIssue": "Ошибка обработки повтора", "matchIsTooOld": "Информация о повторе недоступна", "winner": "Победитель", @@ -176,6 +180,15 @@ "many": "$n игроков", "other": "$n игроков" }, + "games": { + "zero": "$n игр", + "one": "$n игра", + "two": "$n игры", + "few": "$n игры", + "many": "$n игр", + "other": "$n игр" + }, + "gamesPlayed": "$games сыграно", "chart": "График", "entries": "Список", "minimums": "Минимумы", diff --git a/res/tetrio_badges/mts_1.png b/res/tetrio_badges/mts_1.png new file mode 100644 index 0000000..0cf0b28 Binary files /dev/null and b/res/tetrio_badges/mts_1.png differ diff --git a/res/tetrio_badges/mts_2.png b/res/tetrio_badges/mts_2.png new file mode 100644 index 0000000..eb704f8 Binary files /dev/null and b/res/tetrio_badges/mts_2.png differ diff --git a/res/tetrio_badges/mts_3.png b/res/tetrio_badges/mts_3.png new file mode 100644 index 0000000..8f706f3 Binary files /dev/null and b/res/tetrio_badges/mts_3.png differ diff --git a/res/tetrio_badges/mts_participation.png b/res/tetrio_badges/mts_participation.png new file mode 100644 index 0000000..b48f401 Binary files /dev/null and b/res/tetrio_badges/mts_participation.png differ diff --git a/res/tetrio_badges/stride_1.png b/res/tetrio_badges/stride_1.png new file mode 100644 index 0000000..027ed12 Binary files /dev/null and b/res/tetrio_badges/stride_1.png differ diff --git a/res/tetrio_badges/stride_2.png b/res/tetrio_badges/stride_2.png new file mode 100644 index 0000000..04e692a Binary files /dev/null and b/res/tetrio_badges/stride_2.png differ diff --git a/res/tetrio_badges/stride_3.png b/res/tetrio_badges/stride_3.png new file mode 100644 index 0000000..a4a85f8 Binary files /dev/null and b/res/tetrio_badges/stride_3.png differ diff --git a/res/tetrio_badges/stride_participation.png b/res/tetrio_badges/stride_participation.png new file mode 100644 index 0000000..19c1160 Binary files /dev/null and b/res/tetrio_badges/stride_participation.png differ diff --git a/res/tetrio_badges/uoftflag_1.png b/res/tetrio_badges/uoftflag_1.png new file mode 100644 index 0000000..b6a51db Binary files /dev/null and b/res/tetrio_badges/uoftflag_1.png differ diff --git a/res/tetrio_badges/uoftflag_2.png b/res/tetrio_badges/uoftflag_2.png new file mode 100644 index 0000000..4113f0b Binary files /dev/null and b/res/tetrio_badges/uoftflag_2.png differ diff --git a/res/tetrio_badges/uoftflag_3.png b/res/tetrio_badges/uoftflag_3.png new file mode 100644 index 0000000..d26430c Binary files /dev/null and b/res/tetrio_badges/uoftflag_3.png differ