big and scary refactoring

This commit is contained in:
dan63047 2024-09-06 00:42:21 +03:00
parent c03ea44782
commit e403b0cbee
73 changed files with 2869 additions and 2675 deletions

View File

@ -7,7 +7,10 @@
# The following line activates a set of recommended lints for Flutter apps, # The following line activates a set of recommended lints for Flutter apps,
# packages, and plugins designed to encourage good coding practices. # packages, and plugins designed to encourage good coding practices.
include: package:flutter_lints/flutter.yaml analyzer:
errors:
use_build_context_synchronously: ignore
in ignoreclude: package:flutter_lints/flutter.yaml
linter: linter:
# The lint rules applied to this project can be customized in the # The lint rules applied to this project can be customized in the

View File

@ -0,0 +1,98 @@
// ignore_for_file: hash_and_equals
class Achievement {
late int k;
int? o;
late int rt;
late int vt;
late int min;
late int deci;
late String name;
late String object;
late String category;
late bool hidden;
late int art;
late bool nolb;
late String desc;
late String n;
String? sId;
double? v;
late int? a;
DateTime? t;
int? pos;
int? total;
int? rank;
Achievement(
{required this.k,
this.o,
required this.rt,
required this.vt,
required this.min,
required this.deci,
required this.name,
required this.object,
required this.category,
required this.hidden,
required this.art,
required this.nolb,
required this.desc,
required this.n,
this.sId,
this.v,
required this.a,
this.t,
this.pos,
this.total,
this.rank});
Achievement.fromJson(Map<String, dynamic> json) {
k = json['k'];
o = json['o'];
rt = json['rt'];
vt = json['vt'];
min = json['min'];
deci = json['deci'];
name = json['name'];
object = json['object'];
category = json['category'];
hidden = json['hidden'];
art = json['art'];
nolb = json['nolb'];
desc = json['desc'];
n = json['n'];
sId = json['_id'];
v = json['v']?.toDouble();
a = json['a'];
t = json['t'] != null ? DateTime.parse(json['t']) : null;
pos = json['pos'];
total = json['total'];
rank = json['rank'];
}
Map<String, dynamic> toJson() {
final Map<String, dynamic> data = <String, dynamic>{};
data['k'] = k;
data['o'] = o;
data['rt'] = rt;
data['vt'] = vt;
data['min'] = min;
data['deci'] = deci;
data['name'] = name;
data['object'] = object;
data['category'] = category;
data['hidden'] = hidden;
data['art'] = art;
data['nolb'] = nolb;
data['desc'] = desc;
data['n'] = n;
data['_id'] = sId;
data['v'] = v;
data['a'] = a;
data['t'] = t.toString();
data['pos'] = pos;
data['total'] = total;
data['rank'] = rank;
return data;
}
}

View File

@ -0,0 +1,29 @@
// ignore_for_file: hash_and_equals
import 'package:tetra_stats/data_objects/est_tr.dart';
import 'package:tetra_stats/data_objects/nerd_stats.dart';
import 'package:tetra_stats/data_objects/playstyle.dart';
class AggregateStats{
late double apm;
late double pps;
late double vs;
late NerdStats nerdStats;
late EstTr estTr;
late Playstyle playstyle;
AggregateStats(this.apm, this.pps, this.vs){
nerdStats = NerdStats(apm, pps, vs);
estTr = EstTr(apm, pps, vs, nerdStats.app, nerdStats.dss, nerdStats.dsp, nerdStats.gbe);
playstyle = Playstyle(apm, pps, nerdStats.app, nerdStats.vsapm, nerdStats.dsp, nerdStats.gbe, estTr.srarea, estTr.statrank);
}
AggregateStats.fromJson(Map<String, dynamic> json){
apm = json['apm'] != null ? json['apm'].toDouble() : 0.00;
pps = json['apm'] != null ? json['pps'].toDouble() : 0.00;
vs = json['apm'] != null ? json['vsscore'].toDouble() : 0.00;
nerdStats = NerdStats(apm, pps, vs);
estTr = EstTr(apm, pps, vs, nerdStats.app, nerdStats.dss, nerdStats.dsp, nerdStats.gbe);
playstyle = Playstyle(apm, pps, nerdStats.app, nerdStats.vsapm, nerdStats.dsp, nerdStats.gbe, estTr.srarea, estTr.statrank);
}
}

View File

@ -0,0 +1,34 @@
// ignore_for_file: hash_and_equals
class Badge {
late String badgeId;
late String label;
DateTime? ts;
Badge({required this.badgeId, required this.label, this.ts});
Badge.fromJson(Map<String, dynamic> json) {
badgeId = json['id'];
label = json['label'];
ts = (json['ts'] != null && json['ts'] is String) ? DateTime.parse(json['ts']) : null; // man i love osk
}
Map<String, dynamic> toJson() {
final Map<String, dynamic> data = <String, dynamic>{};
data['id'] = badgeId;
data['label'] = label;
data['ts'] = ts?.toString();
return data;
}
@override
String toString() {
return "Badge $label ($badgeId)";
}
@override
int get hashCode => badgeId.hashCode;
@override
bool operator ==(covariant Badge other) => badgeId == other.badgeId;
}

View File

@ -0,0 +1,21 @@
// ignore_for_file: hash_and_equals
import 'package:tetra_stats/data_objects/beta_league_stats.dart';
class BetaLeagueLeaderboardEntry{
late String id;
late String username;
late int naturalorder;
late int wins;
late BetaLeagueStats stats;
BetaLeagueLeaderboardEntry({required this.id, required this.username, required this.naturalorder, required this.wins, required this.stats});
BetaLeagueLeaderboardEntry.fromJson(Map<String, dynamic> json){
id = json['id'];
username = json['username'];
naturalorder = json['naturalorder'];
wins = json['wins'];
stats = BetaLeagueStats.fromJson(json['stats']);
}
}

View File

@ -0,0 +1,24 @@
// ignore_for_file: hash_and_equals
import 'package:tetra_stats/data_objects/beta_league_leaderboard_entry.dart';
import 'package:tetra_stats/data_objects/beta_league_round.dart';
class BetaLeagueResults{
List<BetaLeagueLeaderboardEntry> leaderboard = [];
List<List<BetaLeagueRound>> rounds = [];
BetaLeagueResults({required this.leaderboard, required this.rounds});
BetaLeagueResults.fromJson(Map<String, dynamic> json){
for (var lbEntry in json['leaderboard']) {
leaderboard.add(BetaLeagueLeaderboardEntry.fromJson(lbEntry));
}
for (var roundEntry in json['rounds']){
List<BetaLeagueRound> round = [];
for (var r in roundEntry) {
round.add(BetaLeagueRound.fromJson(r));
}
rounds.add(round);
}
}
}

View File

@ -0,0 +1,25 @@
// ignore_for_file: hash_and_equals
import 'package:tetra_stats/data_objects/beta_league_stats.dart';
class BetaLeagueRound{
late String id;
late String username;
late bool active;
late int naturalorder;
late bool alive;
late Duration lifetime;
late BetaLeagueStats stats;
BetaLeagueRound({required this.id, required this.username, required this.active, required this.naturalorder, required this.alive, required this.lifetime, required this.stats});
BetaLeagueRound.fromJson(Map<String, dynamic> json){
id = json['id'];
username = json['username'];
active = json['active'];
naturalorder = json['naturalorder'];
alive = json['alive'];
lifetime = Duration(milliseconds: json['lifetime']);
stats = BetaLeagueStats.fromJson(json['stats']);
}
}

View File

@ -0,0 +1,43 @@
// ignore_for_file: hash_and_equals
import 'package:tetra_stats/data_objects/est_tr.dart';
import 'package:tetra_stats/data_objects/nerd_stats.dart';
import 'package:tetra_stats/data_objects/playstyle.dart';
class BetaLeagueStats{
late double apm;
late double pps;
late double vs;
late int garbageSent;
late int garbageReceived;
late int kills;
late double altitude;
late int rank;
int? targetingFactor;
int? targetingRace;
late NerdStats nerdStats;
late EstTr estTr;
late Playstyle playstyle;
BetaLeagueStats({required this.apm, required this.pps, required this.vs, required this.garbageSent, required this.garbageReceived, required this.kills, required this.altitude, required this.rank}){
nerdStats = NerdStats(apm, pps, vs);
estTr = EstTr(apm, pps, vs, nerdStats.app, nerdStats.dss, nerdStats.dsp, nerdStats.gbe);
playstyle = Playstyle(apm, pps, nerdStats.app, nerdStats.vsapm, nerdStats.dsp, nerdStats.gbe, estTr.srarea, estTr.statrank);
}
BetaLeagueStats.fromJson(Map<String, dynamic> json){
apm = json['apm'] != null ? json['apm'].toDouble() : 0.00;
pps = json['apm'] != null ? json['pps'].toDouble() : 0.00;
vs = json['apm'] != null ? json['vsscore'].toDouble() : 0.00;
garbageSent = json['garbagesent'];
garbageReceived = json['garbagereceived'];
kills = json['kills'];
altitude = json['altitude'].toDouble();
rank = json['rank'];
targetingFactor = json['targetingfactor'];
targetingRace = json['targetinggrace'];
nerdStats = NerdStats(apm, pps, vs);
estTr = EstTr(apm, pps, vs, nerdStats.app, nerdStats.dss, nerdStats.dsp, nerdStats.gbe);
playstyle = Playstyle(apm, pps, nerdStats.app, nerdStats.vsapm, nerdStats.dsp, nerdStats.gbe, estTr.srarea, estTr.statrank);
}
}

View File

@ -0,0 +1,25 @@
// ignore_for_file: hash_and_equals
import 'package:tetra_stats/data_objects/beta_league_results.dart';
class BetaRecord{
late String id;
late String replayID;
late String gamemode;
late DateTime ts;
late String enemyUsername;
late String enemyID;
late BetaLeagueResults results;
BetaRecord({required this.id, required this.replayID, required this.gamemode, required this.ts, required this.enemyUsername, required this.enemyID, required this.results});
BetaRecord.fromJson(Map<String, dynamic> json){
id = json['_id'];
replayID = json['replayid'];
gamemode = json['gamemode'];
ts = DateTime.parse(json['ts']);
enemyUsername = json['otherusers'][0]['username'];
enemyID = json['otherusers'][0]['id'];
results = BetaLeagueResults.fromJson(json['results']);
}
}

View File

@ -0,0 +1,102 @@
// ignore_for_file: hash_and_equals
class Clears {
late int singles;
late int doubles;
late int triples;
late int quads;
late int pentas;
late int allClears;
late int tSpinZeros;
late int tSpinSingles;
late int tSpinDoubles;
late int tSpinTriples;
late int tSpinQuads;
late int tSpinPentas;
late int tSpinMiniZeros;
late int tSpinMiniSingles;
late int tSpinMiniDoubles;
late int tSpinMiniTriples;
late int tSpinMiniQuads;
Clears(
{required this.singles,
required this.doubles,
required this.triples,
required this.quads,
required this.pentas,
required this.allClears,
required this.tSpinZeros,
required this.tSpinSingles,
required this.tSpinDoubles,
required this.tSpinTriples,
required this.tSpinPentas,
required this.tSpinQuads,
required this.tSpinMiniZeros,
required this.tSpinMiniSingles,
required this.tSpinMiniDoubles,
required this.tSpinMiniTriples,
required this.tSpinMiniQuads});
Clears.fromJson(Map<String, dynamic> json) {
singles = json['singles'];
doubles = json['doubles'];
triples = json['triples'];
quads = json['quads'];
pentas = json['pentas']??0;
tSpinZeros = json['realtspins'];
tSpinMiniZeros = json['minitspins'];
tSpinMiniSingles = json['minitspinsingles'];
tSpinSingles = json['tspinsingles'];
tSpinMiniDoubles = json['minitspindoubles'];
tSpinDoubles = json['tspindoubles'];
tSpinMiniTriples = json['minitspintriples']??0;
tSpinTriples = json['tspintriples'];
tSpinMiniQuads = json['minitspinquads']??0;
tSpinQuads = json['tspinquads'];
tSpinPentas = json['tspinpentas']??0;
allClears = json['allclear'];
}
Clears operator + (Clears other){
return Clears(
singles: singles + other.singles,
doubles: doubles + other.doubles,
triples: triples + other.triples,
quads: quads + other.quads,
pentas: pentas + other.pentas,
allClears: allClears + other.allClears,
tSpinZeros: tSpinZeros + other.tSpinZeros,
tSpinSingles: tSpinSingles + other.tSpinSingles,
tSpinDoubles: tSpinDoubles + other.tSpinDoubles,
tSpinTriples: tSpinTriples + other.tSpinTriples,
tSpinPentas: tSpinPentas + other.tSpinPentas,
tSpinQuads: tSpinQuads + other.tSpinQuads,
tSpinMiniZeros: tSpinMiniZeros + other.tSpinMiniZeros,
tSpinMiniSingles: tSpinMiniSingles + other.tSpinMiniSingles,
tSpinMiniDoubles: tSpinMiniDoubles + other.tSpinMiniDoubles,
tSpinMiniTriples: tSpinMiniTriples + other.tSpinMiniTriples,
tSpinMiniQuads: tSpinMiniQuads + other.tSpinMiniQuads
);
}
Map<String, dynamic> toJson() {
final Map<String, dynamic> data = <String, dynamic>{};
data['singles'] = singles;
data['doubles'] = doubles;
data['triples'] = triples;
data['quads'] = quads;
data['pentas'] = pentas;
data['realtspins'] = tSpinZeros;
data['minitspins'] = tSpinMiniZeros;
data['minitspinsingles'] = tSpinMiniSingles;
data['tspinsingles'] = tSpinSingles;
data['minitspindoubles'] = tSpinMiniDoubles;
data['tspindoubles'] = tSpinDoubles;
data['tspintriples'] = tSpinTriples;
data['tspinquads'] = tSpinQuads;
data['tspinpentas'] = tSpinPentas;
data['allclear'] = allClears;
return data;
}
}

View File

@ -0,0 +1,43 @@
// ignore_for_file: hash_and_equals
class Connections {
Discord? discord;
Connections({this.discord});
Connections.fromJson(Map<String, dynamic> json) {
discord = json['discord'] != null ? Discord.fromJson(json['discord']) : null;
}
@override
bool operator ==(covariant Connections other) => discord == other.discord;
Map<String, dynamic> toJson() {
final Map<String, dynamic> data = <String, dynamic>{};
if (discord != null) {
data['discord'] = discord!.toJson();
}
return data;
}
}
class Discord {
late String id;
late String username;
Discord({required this.id, required this.username});
Discord.fromJson(Map<String, dynamic> json) {
id = json['id'];
username = json['username'];
}
@override
bool operator ==(covariant Discord other) => id == other.id;
Map<String, dynamic> toJson() {
final Map<String, dynamic> data = <String, dynamic>{};
data['id'] = id;
data['username'] = username;
return data;
}
}

View File

@ -0,0 +1,42 @@
// ignore_for_file: hash_and_equals
class CutoffTetrio {
late int pos;
late double percentile;
late double tr;
late double targetTr;
late double apm;
late double pps;
late double vs;
late int count;
late double countPercentile;
CutoffTetrio.fromJson(Map<String, dynamic> json, int total){
pos = json['pos'];
percentile = json['percentile'].toDouble();
tr = json['tr'].toDouble();
targetTr = json['targettr'].toDouble();
apm = json['apm'].toDouble();
pps = json['pps'].toDouble();
vs = json['vs'].toDouble();
count = json['count'];
countPercentile = count / total;
}
}
class CutoffsTetrio {
late String id;
late DateTime timestamp;
late int total;
Map<String, CutoffTetrio> data = {};
CutoffsTetrio.fromJson(Map<String, dynamic> json){
id = json['s'];
timestamp = DateTime.parse(json['t']);
total = json['data']['total'];
json['data'].remove("total");
for (String rank in json['data'].keys){
data[rank] = CutoffTetrio.fromJson(json['data'][rank], total);
}
}
}

View File

@ -0,0 +1,29 @@
// ignore_for_file: hash_and_equals
class Distinguishment {
late String type;
String? detail;
String? header;
String? footer;
Distinguishment({required this.type, this.detail, this.header, this.footer});
Distinguishment.fromJson(Map<String, dynamic> json) {
type = json['type'];
detail = json['detail'];
header = json['header'];
footer = json['footer'];
}
@override
bool operator ==(covariant Distinguishment other) => type == other.type && detail == other.detail && header == other.header && footer == other.footer;
Map<String, dynamic> toJson() {
final Map<String, dynamic> data = <String, dynamic>{};
data['type'] = type;
data['detail'] = detail;
data['header'] = header;
data['footer'] = footer;
return data;
}
}

View File

@ -0,0 +1,97 @@
// ignore_for_file: hash_and_equals
import 'package:tetra_stats/data_objects/est_tr.dart';
import 'package:tetra_stats/data_objects/handling.dart';
import 'package:tetra_stats/data_objects/nerd_stats.dart';
import 'package:tetra_stats/data_objects/playstyle.dart';
class EndContextMulti {
late String userId;
late String username;
late int naturalOrder;
late int inputs;
late int piecesPlaced;
late Handling handling;
late int points;
late int wins;
late double secondary;
late List secondaryTracking;
late double tertiary;
late List tertiaryTracking;
late double extra;
late List extraTracking;
late bool success;
late NerdStats nerdStats;
late List<NerdStats> nerdStatsTracking;
late EstTr estTr;
late List<EstTr> estTrTracking;
late Playstyle playstyle;
late List<Playstyle> playstyleTracking;
EndContextMulti(
{required this.userId,
required this.username,
required this.naturalOrder,
required this.inputs,
required this.piecesPlaced,
required this.handling,
required this.points,
required this.wins,
required this.secondary,
required this.secondaryTracking,
required this.tertiary,
required this.tertiaryTracking,
required this.extra,
required this.extraTracking,
required this.success}){
nerdStats = NerdStats(secondary, tertiary, extra);
nerdStatsTracking = [for (int i = 0; i < secondaryTracking.length; i++) NerdStats(secondaryTracking[i], tertiaryTracking[i], extraTracking[i])];
estTr = EstTr(secondary, tertiary, extra, nerdStats.app, nerdStats.dss, nerdStats.dsp, nerdStats.gbe);
estTrTracking = [for (int i = 0; i < secondaryTracking.length; i++) EstTr(secondaryTracking[i], tertiaryTracking[i], extraTracking[i], nerdStatsTracking[i].app, nerdStatsTracking[i].dss, nerdStatsTracking[i].dsp, nerdStatsTracking[i].gbe)];
playstyle = Playstyle(secondary, tertiary, nerdStats.app, nerdStats.vsapm, nerdStats.dsp, nerdStats.gbe, estTr.srarea, estTr.statrank);
playstyleTracking = [for (int i = 0; i < secondaryTracking.length; i++) Playstyle(secondaryTracking[i], tertiaryTracking[i], nerdStatsTracking[i].app, nerdStatsTracking[i].vsapm, nerdStatsTracking[i].dsp, nerdStatsTracking[i].gbe, estTrTracking[i].srarea, estTrTracking[i].statrank)];
}
EndContextMulti.fromJson(Map<String, dynamic> json) {
userId = json['id'] ?? json['user']['_id'];
username = json['username'] ?? json['user']['username'];
handling = json['handling'] != null ? Handling.fromJson(json['handling']) : Handling(arr: -1, das: -1, sdf: -1, dcd: 0, cancel: true, safeLock: true);
success = json['success'];
inputs = json['inputs'] ?? -1;
piecesPlaced = json['piecesplaced'] ?? -1;
naturalOrder = json['naturalorder'];
wins = json['wins'];
points = json['points']['primary'];
secondary = json['points']['secondary'].toDouble();
tertiary = json['points']['tertiary'].toDouble();
secondaryTracking = json['points']['secondaryAvgTracking'] != null ? json['points']['secondaryAvgTracking'].map((e) => e.toDouble()).toList() : [];
tertiaryTracking = json['points']['tertiaryAvgTracking'] != null ? json['points']['tertiaryAvgTracking'].map((e) => e.toDouble()).toList() : [];
extra = json['points']['extra']['vs'].toDouble();
extraTracking = json['points']['extraAvgTracking'] != null ? json['points']['extraAvgTracking']['aggregatestats___vsscore'].map((e) => e.toDouble()).toList() : [];
nerdStats = NerdStats(secondary, tertiary, extra);
nerdStatsTracking = [for (int i = 0; i < secondaryTracking.length; i++) NerdStats(secondaryTracking[i], tertiaryTracking[i], extraTracking[i])];
estTr = EstTr(secondary, tertiary, extra, nerdStats.app, nerdStats.dss, nerdStats.dsp, nerdStats.gbe);
estTrTracking = [for (int i = 0; i < secondaryTracking.length; i++) EstTr(secondaryTracking[i], tertiaryTracking[i], extraTracking[i], nerdStatsTracking[i].app, nerdStatsTracking[i].dss, nerdStatsTracking[i].dsp, nerdStatsTracking[i].gbe)];
playstyle = Playstyle(secondary, tertiary, nerdStats.app, nerdStats.vsapm, nerdStats.dsp, nerdStats.gbe, estTr.srarea, estTr.statrank);
playstyleTracking = [for (int i = 0; i < secondaryTracking.length; i++) Playstyle(secondaryTracking[i], tertiaryTracking[i], nerdStatsTracking[i].app, nerdStatsTracking[i].vsapm, nerdStatsTracking[i].dsp, nerdStatsTracking[i].gbe, estTrTracking[i].srarea, estTrTracking[i].statrank)];
}
@override
bool operator == (covariant EndContextMulti other){
if (userId != other.userId) return false;
return true;
}
Map<String, dynamic> toJson() {
final Map<String, dynamic> data = <String, dynamic>{};
data['user'] = {'_id': userId, 'username': username};
data['handling'] = handling.toJson();
data['success'] = success;
data['inputs'] = inputs;
data['piecesplaced'] = piecesPlaced;
data['naturalorder'] = naturalOrder;
data['wins'] = wins;
data['points'] = {'primary': points, 'secondary': secondary, 'tertiary':tertiary, 'extra': {'vs': extra}, 'secondaryAvgTracking': secondaryTracking, 'tertiaryAvgTracking': tertiaryTracking, 'extraAvgTracking': {'aggregatestats___vsscore': extraTracking}};
return data;
}
}

View File

@ -0,0 +1,39 @@
// ignore_for_file: hash_and_equals
import 'dart:math';
class EstTr {
late double esttr;
late double srarea;
late double statrank;
late double estglicko;
EstTr(double apm, double pps, double vs, double app, double dss, double dsp, double gbe) {
srarea = (apm * 0) + (pps * 135) + (vs * 0) + (app * 290) + (dss * 0) + (dsp * 700) + (gbe * 0);
statrank = 11.2 * atan((srarea - 93) / 130) + 1;
if (statrank <= 0) statrank = 0.001;
//estglicko = (4.0867 * srarea + 186.68);
double ntemp = pps*(150+(((vs/apm) - 1.66)*35))+app*290+dsp*700;
estglicko = 0.000013*pow(ntemp, 3) - 0.0196 *pow(ntemp, 2) + (12.645*ntemp)-1005.4;
esttr = 25000 /
(
1 + pow(10, (
(
(
1500-estglicko
)*pi
)/sqrt(
(
(
3*pow(ln10, 2)
)*pow(60, 2)
)+(
2500*(
(64*pow(pi,2))+(147*pow(ln10, 2))
)
)
)
))
);
}
}

View File

@ -0,0 +1,29 @@
// ignore_for_file: hash_and_equals
import 'dart:math';
class Finesse {
late int combo;
late int faults;
late int perfectPieces;
Finesse({required this.combo, required this.faults, required this.perfectPieces});
Finesse.fromJson(Map<String, dynamic> json) {
combo = json['combo'];
faults = json['faults'];
perfectPieces = json['perfectpieces'];
}
Finesse operator + (Finesse other){
return Finesse(combo: max(combo, other.combo), faults: faults + other.faults, perfectPieces: perfectPieces + other.perfectPieces);
}
Map<String, dynamic> toJson() {
final Map<String, dynamic> data = <String, dynamic>{};
data['combo'] = combo;
data['faults'] = faults;
data['perfectpieces'] = perfectPieces;
return data;
}
}

View File

@ -0,0 +1,32 @@
// ignore_for_file: hash_and_equals
class Handling {
late num arr;
late num das;
late num sdf;
late num dcd;
late bool cancel;
late bool safeLock;
Handling({required this.arr, required this.das, required this.sdf, required this.dcd, required this.cancel, required this.safeLock});
Handling.fromJson(Map<String, dynamic> json) {
arr = json['arr'];
das = json['das'];
dcd = json['dcd'];
sdf = json['sdf'];
safeLock = json['safelock'];
cancel = json['cancel'];
}
Map<String, dynamic> toJson() {
final Map<String, dynamic> data = <String, dynamic>{};
data['arr'] = arr.toDouble();
data['das'] = das.toDouble();
data['dcd'] = dcd.toDouble();
data['sdf'] = sdf.toDouble();
data['safelock'] = safeLock;
data['cancel'] = cancel;
return data;
}
}

View File

@ -0,0 +1,8 @@
// ignore_for_file: hash_and_equals
class LeaderboardPosition{
int position;
double percentage;
LeaderboardPosition(this.position, this.percentage);
}

View File

@ -0,0 +1,28 @@
// ignore_for_file: hash_and_equals
import 'dart:math';
import 'package:vector_math/vector_math.dart';
class NerdStats {
late double app;
late double vsapm;
late double dss;
late double dsp;
late double appdsp;
late double cheese;
late double gbe;
late double nyaapp;
late double area;
NerdStats(double apm, double pps, double vs) {
app = apm / (pps * 60);
vsapm = vs / apm;
dss = (vs / 100) - (apm / 60);
dsp = ((vs / 100) - (apm / 60)) / pps;
appdsp = app + dsp;
cheese = (dsp * 150) + ((vsapm - 2) * 50) + (0.6 - app) * 125;
gbe = app * dsp * 2;
nyaapp = app - 5 * tan(radians((cheese / -30) + 1));
area = apm * 1 + pps * 45 + vs * 0.444 + app * 185 + dss * 175 + dsp * 450 + gbe * 315;
}
}

View File

@ -0,0 +1,15 @@
// ignore_for_file: hash_and_equals
import 'package:tetra_stats/data_objects/news_entry.dart';
class News{
late String id;
late List<NewsEntry> news;
News(this.id, this.news);
News.fromJson(Map<String, dynamic> json, String? userID){
id = userID != null ? "user_$userID" : json['news'].first['stream'];
news = [for (var entry in json['news']) NewsEntry.fromJson(entry)];
}
}

View File

@ -0,0 +1,15 @@
// ignore_for_file: hash_and_equals
class NewsEntry {
late String type;
late Map<String, dynamic> data;
late DateTime timestamp;
NewsEntry({required this.type, required this.data, required this.timestamp});
NewsEntry.fromJson(Map<String, dynamic> json){
type = json["type"];
data = json["data"];
timestamp = DateTime.parse(json['ts']);
}
}

View File

@ -0,0 +1,63 @@
// ignore_for_file: hash_and_equals
import 'package:tetra_stats/data_objects/leaderboard_position.dart';
class PlayerLeaderboardPosition{
late LeaderboardPosition? apm;
late LeaderboardPosition? pps;
late LeaderboardPosition? vs;
late LeaderboardPosition? gamesPlayed;
late LeaderboardPosition? gamesWon;
late LeaderboardPosition? winrate;
late LeaderboardPosition? app;
late LeaderboardPosition? vsapm;
late LeaderboardPosition? dss;
late LeaderboardPosition? dsp;
late LeaderboardPosition? appdsp;
late LeaderboardPosition? cheese;
late LeaderboardPosition? gbe;
late LeaderboardPosition? nyaapp;
late LeaderboardPosition? area;
late LeaderboardPosition? estTr;
late LeaderboardPosition? accOfEst;
PlayerLeaderboardPosition({
required this.apm,
required this.pps,
required this.vs,
required this.gamesPlayed,
required this.gamesWon,
required this.winrate,
required this.app,
required this.vsapm,
required this.dss,
required this.dsp,
required this.appdsp,
required this.cheese,
required this.gbe,
required this.nyaapp,
required this.area,
required this.estTr,
required this.accOfEst
});
PlayerLeaderboardPosition.fromSearchResults(List<LeaderboardPosition?> results){
apm = results[0];
pps = results[1];
vs = results[2];
gamesPlayed = results[3];
gamesWon = results[4];
winrate = results[5];
app = results[6];
vsapm = results[7];
dss = results[8];
dsp = results[9];
appdsp = results[10];
cheese = results[11];
gbe = results[12];
nyaapp = results[13];
area = results[14];
estTr = results[15];
accOfEst = results[16];
}
}

View File

@ -0,0 +1,25 @@
// ignore_for_file: hash_and_equals
import 'dart:math';
class Playstyle {
late double opener;
late double plonk;
late double stride;
late double infds;
Playstyle(double apm, double pps, double app, double vsapm, double dsp, double gbe, double srarea, double statrank) {
double nmapm = ((apm / srarea) / ((0.069 * pow(1.0017, (pow(statrank, 5) / 4700))) + statrank / 360)) - 1;
double nmpps = ((pps / srarea) / (0.0084264 * pow(2.14, (-2 * (statrank / 2.7 + 1.03))) - statrank / 5750 + 0.0067)) - 1;
//double nmvs = ((vs / srarea) / (0.1333 * pow(1.0021, ((pow(statrank, 7) * (statrank / 16.5)) / 1400000)) + statrank / 133)) - 1;
double nmapp = (app / (0.1368803292 * pow(1.0024, (pow(statrank, 5) / 2800)) + statrank / 54)) - 1;
//double nmdss = (dss / (0.01436466667 * pow(4.1, ((statrank - 9.6) / 2.9)) + statrank / 140 + 0.01)) - 1;
double nmdsp = (dsp / (0.02136327583 * pow(14, ((statrank - 14.75) / 3.9)) + statrank / 152 + 0.022)) - 1;
double nmgbe = (gbe / (statrank / 350 + 0.005948424455 * pow(3.8, ((statrank - 6.1) / 4)) + 0.006)) - 1;
double nmvsapm = (vsapm / (-pow(((statrank - 16) / 36), 2) + 2.133)) - 1;
opener = ((nmapm + nmpps * 0.75 + nmvsapm * -10 + nmapp * 0.75 + nmdsp * -0.25) / 3.5) + 0.5;
plonk = ((nmgbe + nmapp + nmdsp * 0.75 + nmpps * -1) / 2.73) + 0.5;
stride = ((nmapm * -0.25 + nmpps + nmapp * -2 + nmdsp * -0.5) * 0.79) + 0.5;
infds = ((nmdsp + nmapp * -0.75 + nmapm * 0.5 + nmvsapm * 1.5 + nmpps * 0.5) * 0.9) + 0.5;
}
}

View File

@ -0,0 +1,15 @@
// ignore_for_file: hash_and_equals
class RecordExtras{
}
class ZenithExtras extends RecordExtras{
List<String> mods = [];
ZenithExtras.fromJson(Map<String, dynamic> json){
for (var mod in json["mods"]) {
mods.add(mod);
}
}
}

View File

@ -0,0 +1,50 @@
// ignore_for_file: hash_and_equals
import 'package:tetra_stats/data_objects/aggregate_stats.dart';
import 'package:tetra_stats/data_objects/record_extras.dart';
import 'package:tetra_stats/data_objects/results_stats.dart';
class RecordSingle {
late String? userId;
late String replayId;
late String ownId;
late String gamemode;
late DateTime timestamp;
late ResultsStats stats;
late int rank;
late int countryRank;
late AggregateStats aggregateStats;
late RecordExtras extras;
RecordSingle({required this.userId, required this.replayId, required this.ownId, required this.timestamp, required this.stats, required this.rank, required this.countryRank, required this.aggregateStats});
RecordSingle.fromJson(Map<String, dynamic> json, int ran, int cran) {
ownId = json['_id'];
gamemode = json['gamemode'];
stats = ResultsStats.fromJson(json['results']['stats']);
replayId = json['replayid'];
timestamp = DateTime.parse(json['ts']);
if (json['user'] != null) userId = json['user']['id'];
rank = ran;
countryRank = cran;
aggregateStats = AggregateStats.fromJson(json['results']['aggregatestats']);
var ex = json['extras'] as Map<String, dynamic>;
switch (ex.keys.firstOrNull){
case "zenith":
extras = ZenithExtras.fromJson(json['extras']['zenith']);
default:
break;
}
}
Map<String, dynamic> toJson() {
final Map<String, dynamic> data = <String, dynamic>{};
data['_id'] = ownId;
data['results']['stats'] = stats.toJson();
data['ismulti'] = false;
data['replayid'] = replayId;
data['ts'] = timestamp;
data['user_id'] = userId;
return data;
}
}

View File

@ -0,0 +1,82 @@
// ignore_for_file: hash_and_equals
import 'package:tetra_stats/data_objects/clears.dart';
import 'package:tetra_stats/data_objects/finesse.dart';
import 'package:tetra_stats/data_objects/zenith_results.dart';
class ResultsStats {
late int topBtB;
late int topCombo;
late int holds;
late int inputs;
late int level;
late int piecesPlaced;
late int lines;
late int score;
double? seed;
late Duration finalTime;
late int tSpins;
late Clears clears;
late int kills;
Finesse? finesse;
ZenithResults? zenith;
double get pps => piecesPlaced / (finalTime.inMicroseconds / 1000000);
double get kpp => inputs / piecesPlaced;
double get spp => score / piecesPlaced;
double get kps => inputs / (finalTime.inMicroseconds / 1000000);
double get finessePercentage => finesse != null ? finesse!.perfectPieces / piecesPlaced : 0;
double get cps => zenith != null ? zenith!.avgrankpts / (finalTime.inMilliseconds / 1000 * 60) : 0;
ResultsStats(
{
required this.topBtB,
required this.topCombo,
required this.holds,
required this.inputs,
required this.level,
required this.piecesPlaced,
required this.lines,
required this.score,
required this.seed,
required this.finalTime,
required this.tSpins,
required this.clears,
required this.finesse});
ResultsStats.fromJson(Map<String, dynamic> json) {
seed = json['seed']?.toDouble();
lines = json['lines'];
inputs = json['inputs'];
holds = json['holds'] ?? 0;
finalTime = Duration(microseconds: (json['finaltime'].toDouble() * 1000).floor());
score = json['score'];
level = json['level'];
topCombo = json['topcombo'];
topBtB = json['topbtb'];
tSpins = json['tspins'];
piecesPlaced = json['piecesplaced'];
clears = Clears.fromJson(json['clears']);
kills = json['kills'];
if (json.containsKey("finesse")) finesse = Finesse.fromJson(json['finesse']);
if (json.containsKey("zenith")) zenith = ZenithResults.fromJson(json['zenith']);
}
Map<String, dynamic> toJson() {
final Map<String, dynamic> data = <String, dynamic>{};
data['seed'] = seed;
data['lines'] = lines;
data['inputs'] = inputs;
data['holds'] = holds;
data['score'] = score;
data['level'] = level;
data['topcombo'] = topCombo;
data['topbtb'] = topBtB;
data['tspins'] = tSpins;
data['piecesplaced'] = piecesPlaced;
data['clears'] = clears.toJson();
if (finesse != null) data['finesse'] = finesse!.toJson();
data['finalTime'] = finalTime;
return data;
}
}

View File

@ -0,0 +1,18 @@
// ignore_for_file: hash_and_equals
import 'package:tetra_stats/data_objects/record_single.dart';
class SingleplayerStream{
late String userId;
late String type;
late List<RecordSingle> records;
SingleplayerStream({required this.userId, required this.records, required this.type});
SingleplayerStream.fromJson(List<dynamic> json, String userID, String tp) {
userId = userID;
type = tp;
records = [];
for (var value in json) {records.add(RecordSingle.fromJson(value, -1, -1));}
}
}

View File

@ -0,0 +1,39 @@
// ignore_for_file: hash_and_equals
import 'package:tetra_stats/data_objects/achievement.dart';
import 'package:tetra_stats/data_objects/record_single.dart';
import 'package:tetra_stats/data_objects/tetra_league.dart';
import 'package:tetra_stats/data_objects/tetrio_constants.dart';
import 'package:tetra_stats/data_objects/tetrio_zen.dart';
class Summaries{
late String id;
RecordSingle? sprint;
RecordSingle? blitz;
RecordSingle? zenith;
RecordSingle? zenithCareerBest; // leaderboard best, not overall
RecordSingle? zenithEx;
RecordSingle? zenithExCareerBest; // leaderboard best, not overall
late List<Achievement> achievements;
late TetraLeague league;
Map<int, TetraLeague> pastLeague = {};
late TetrioZen zen;
Summaries(this.id, this.league, this.zen);
Summaries.fromJson(Map<String, dynamic> json, String i){
id = i;
if (json['40l']['record'] != null) sprint = RecordSingle.fromJson(json['40l']['record'], json['40l']['rank'], json['40l']['rank_local']);
if (json['blitz']['record'] != null) blitz = RecordSingle.fromJson(json['blitz']['record'], json['blitz']['rank'], json['40l']['rank_local']);
if (json['zenith']['record'] != null) zenith = RecordSingle.fromJson(json['zenith']['record'], json['zenith']['rank'], json['zenith']['rank_local']);
if (json['zenith']['best']['record'] != null) zenithCareerBest = RecordSingle.fromJson(json['zenith']['best']['record'], json['zenith']['best']['rank'], -1);
if (json['zenithex']['record'] != null) zenithEx = RecordSingle.fromJson(json['zenithex']['record'], json['zenithex']['rank'], json['zenithex']['rank_local']);
if (json['zenithex']['best']['record'] != null) zenithCareerBest = RecordSingle.fromJson(json['zenithex']['best']['record'], json['zenith']['best']['rank'], -1);
achievements = [for (var achievement in json['achievements']) Achievement.fromJson(achievement)];
league = TetraLeague.fromJson(json['league'], DateTime.now(), currentSeason, i);
if (json['league']['past'].isNotEmpty) for (var key in json['league']['past'].keys){
pastLeague[int.parse(key)] = TetraLeague.fromJson(json['league']['past'][key], DateTime(1970), int.parse(json['league']['past'][key]['season']), i);
}
zen = TetrioZen.fromJson(json['zen']);
}
}

View File

@ -0,0 +1,139 @@
// ignore_for_file: hash_and_equals
import 'package:tetra_stats/data_objects/est_tr.dart';
import 'package:tetra_stats/data_objects/nerd_stats.dart';
import 'package:tetra_stats/data_objects/playstyle.dart';
import 'package:tetra_stats/data_objects/tetrio_constants.dart';
import 'package:tetra_stats/data_objects/tetrio_player_from_leaderboard.dart';
class TetraLeague {
late String id;
late DateTime timestamp;
late int gamesPlayed;
late int gamesWon;
late String bestRank;
late bool decaying;
late double tr;
late double gxe;
late String rank;
double? glicko;
double? rd;
late String percentileRank;
late double percentile;
late int standing;
late int standingLocal;
String? nextRank;
late int nextAt;
String? prevRank;
late int prevAt;
double? apm;
double? pps;
double? vs;
NerdStats? nerdStats;
EstTr? estTr;
Playstyle? playstyle;
late int season;
TetraLeague(
{required this.id,
required this.timestamp,
required this.gamesPlayed,
required this.gamesWon,
required this.bestRank,
required this.decaying,
required this.tr,
required this.gxe,
required this.rank,
this.glicko,
this.rd,
required this.percentileRank,
required this.percentile,
required this.standing,
required this.standingLocal,
this.nextRank,
required this.nextAt,
this.prevRank,
required this.prevAt,
this.apm,
this.pps,
this.vs,
required this.season}){
nerdStats = (apm != null && pps != null && vs != null) ? NerdStats(apm!, pps!, vs!) : null;
estTr = (nerdStats != null) ? EstTr(apm!, pps!, vs!, nerdStats!.app, nerdStats!.dss, nerdStats!.dsp, nerdStats!.gbe) : null;
playstyle =(nerdStats != null) ? Playstyle(apm!, pps!, nerdStats!.app, nerdStats!.vsapm, nerdStats!.dsp, nerdStats!.gbe, estTr!.srarea, estTr!.statrank) : null;
}
double get winrate => gamesWon / gamesPlayed;
double get s1tr => gxe * 250;
TetraLeague.fromJson(Map<String, dynamic> json, ts, int s, String i) {
timestamp = ts;
season = s;
id = i;
gamesPlayed = json['gamesplayed'] ?? 0;
gamesWon = json['gameswon'] ?? 0;
tr = json['tr'] != null ? json['tr'].toDouble() : json['rating'] != null ? json['rating'].toDouble() : -1;
glicko = json['glicko']?.toDouble();
rd = json['rd'] != null ? json['rd']!.toDouble() : noTrRd;
gxe = json['gxe'] != null ? json['gxe'].toDouble() : -1;
rank = json['rank'] != null ? json['rank']!.toString() : 'z';
bestRank = json['bestrank'] != null ? json['bestrank']!.toString() : 'z';
apm = json['apm']?.toDouble();
pps = json['pps']?.toDouble();
vs = json['vs']?.toDouble();
decaying = switch(json['decaying'].runtimeType){
int => json['decaying'] == 1,
bool => json['decaying'],
_ => false
};
standing = json['standing'] ?? json['placement'] ?? -1;
percentile = json['percentile'] != null ? json['percentile'].toDouble() : rankCutoffs[rank];
standingLocal = json['standing_local'] ?? -1;
prevRank = json['prev_rank'];
prevAt = json['prev_at'] ?? -1;
nextRank = json['next_rank'];
nextAt = json['next_at'] ?? -1;
percentileRank = json['percentile_rank'] ?? rank;
nerdStats = (apm != null && pps != null && vs != null) ? NerdStats(apm!, pps!, vs!) : null;
estTr = (nerdStats != null) ? EstTr(apm!, pps!, vs!, nerdStats!.app, nerdStats!.dss, nerdStats!.dsp, nerdStats!.gbe) : null;
playstyle = (nerdStats != null) ? Playstyle(apm!, pps!, nerdStats!.app, nerdStats!.vsapm, nerdStats!.dsp, nerdStats!.gbe, estTr!.srarea, estTr!.statrank) : null;
}
@override
bool operator ==(covariant TetraLeague other) => gamesPlayed == other.gamesPlayed && rd == other.rd;
bool lessStrictCheck (covariant TetraLeague other) => gamesPlayed == other.gamesPlayed && glicko == other.glicko;
double? get esttracc => (estTr != null) ? estTr!.esttr - tr : null;
TetrioPlayerFromLeaderboard convertToPlayerFromLeaderboard(String id) => TetrioPlayerFromLeaderboard(
id, "", "user", -1, null, timestamp, gamesPlayed, gamesWon,
tr, gxe, glicko??0, rd??noTrRd, rank, bestRank, apm??0, pps??0, vs??0, decaying);
Map<String, dynamic> toJson() {
final Map<String, dynamic> data = <String, dynamic>{};
data['id'] = id+timestamp.millisecondsSinceEpoch.toRadixString(16);
if (gamesPlayed > 0) data['gamesplayed'] = gamesPlayed;
if (gamesWon > 0) data['gameswon'] = gamesWon;
if (tr >= 0) data['tr'] = tr;
if (glicko != null) data['glicko'] = glicko;
if (gxe != -1) data['gxe'] = gxe;
if (rd != null && rd != noTrRd) data['rd'] = rd;
if (rank != 'z') data['rank'] = rank;
if (bestRank != 'z') data['bestrank'] = bestRank;
if (apm != null) data['apm'] = apm;
if (pps != null) data['pps'] = pps;
if (vs != null) data['vs'] = vs;
if (decaying) data['decaying'] = decaying ? 1 : 0;
if (standing >= 0) data['standing'] = standing;
data['percentile'] = percentile;
if (standingLocal >= 0) data['standing_local'] = standingLocal;
if (prevRank != null) data['prev_rank'] = prevRank;
if (prevAt >= 0) data['prev_at'] = prevAt;
if (nextRank != null) data['next_rank'] = nextRank;
if (nextAt >= 0) data['next_at'] = nextAt;
data['percentile_rank'] = percentileRank;
data['season'] = season;
return data;
}
}

View File

@ -0,0 +1,39 @@
// ignore_for_file: hash_and_equals
import 'package:tetra_stats/data_objects/end_context_multi.dart';
class TetraLeagueAlphaRecord{
late String replayId;
late String ownId;
late DateTime timestamp;
late bool replayAvalable;
late List<EndContextMulti> endContext;
TetraLeagueAlphaRecord({required this.replayId, required this.ownId, required this.timestamp, required this.endContext, required this.replayAvalable});
TetraLeagueAlphaRecord.fromJson(Map<String, dynamic> json) {
endContext = [EndContextMulti.fromJson(json['endcontext'][0]), EndContextMulti.fromJson(json['endcontext'][1])];
replayId = json['replayid'];
ownId = json['_id']??replayId;
timestamp = DateTime.parse(json['ts']);
replayAvalable = ownId != replayId;
}
Map<String, dynamic> toJson() {
final Map<String, dynamic> data = <String, dynamic>{};
data['_id'] = ownId;
data['endcontext'][0] = endContext[0].toJson();
data['endcontext'][1] = endContext[1].toJson();
data['replayid'] = replayId;
data['ts'] = timestamp;
return data;
}
@override
bool operator ==(covariant TetraLeagueAlphaRecord other) => (ownId == other.ownId) || (replayId == other.replayId);
@override
String toString() {
return "TetraLeagueAlphaRecord: ${endContext.first.userId} vs ${endContext.last.userId}";
}
}

View File

@ -0,0 +1,16 @@
// ignore_for_file: hash_and_equals
import 'package:tetra_stats/data_objects/tetra_league_alpha_record.dart';
class TetraLeagueAlphaStream{
late String userId;
late List<TetraLeagueAlphaRecord> records;
TetraLeagueAlphaStream({required this.userId, required this.records});
TetraLeagueAlphaStream.fromJson(List<dynamic> json, String userID) {
userId = userID;
records = [];
for (var value in json) {records.add(TetraLeagueAlphaRecord.fromJson(value));}
}
}

View File

@ -0,0 +1,111 @@
// ignore_for_file: hash_and_equals
import 'package:tetra_stats/data_objects/beta_league_leaderboard_entry.dart';
import 'package:tetra_stats/data_objects/beta_league_results.dart';
import 'package:tetra_stats/data_objects/beta_league_round.dart';
import 'package:tetra_stats/data_objects/beta_league_stats.dart';
import 'package:tetra_stats/data_objects/beta_record.dart';
import 'package:tetra_stats/data_objects/tetra_league_alpha_record.dart';
class TetraLeagueBetaStream{
late String id;
List<BetaRecord> records = [];
TetraLeagueBetaStream({required this.id, required this.records});
TetraLeagueBetaStream.fromJson(List<dynamic> json, String userID) {
id = userID;
for (var entry in json) {
records.add(BetaRecord.fromJson(entry));
}
}
addFromAlphaStream(List<TetraLeagueAlphaRecord> r){
for (var entry in r) {
records.add(
BetaRecord(
id: entry.ownId,
replayID: entry.replayId,
ts: entry.timestamp,
enemyID: entry.endContext[1].userId,
enemyUsername: entry.endContext[1].username,
gamemode: "oldleague",
results: BetaLeagueResults(
leaderboard: [
BetaLeagueLeaderboardEntry(
id: entry.endContext[0].userId,
username: entry.endContext[0].username,
naturalorder: entry.endContext[0].naturalOrder,
wins: entry.endContext[0].points,
stats: BetaLeagueStats(
apm: entry.endContext[0].secondary,
pps: entry.endContext[0].tertiary,
vs: entry.endContext[0].extra,
garbageSent: -1,
garbageReceived: -1,
kills: entry.endContext[0].points,
altitude: 0.0,
rank: -1
)
),
BetaLeagueLeaderboardEntry(
id: entry.endContext[1].userId,
username: entry.endContext[1].username,
naturalorder: entry.endContext[1].naturalOrder,
wins: entry.endContext[1].points,
stats: BetaLeagueStats(
apm: entry.endContext[1].secondary,
pps: entry.endContext[1].tertiary,
vs: entry.endContext[1].extra,
garbageSent: -1,
garbageReceived: -1,
kills: entry.endContext[1].points,
altitude: 0.0,
rank: -1
)
)
],
rounds: [
for (int i=0; i<entry.endContext[0].secondaryTracking.length; i++)
[BetaLeagueRound(
id: entry.endContext[0].userId,
username: entry.endContext[0].username,
naturalorder: entry.endContext[0].naturalOrder,
active: false,
alive: false,
lifetime: const Duration(milliseconds: -1),
stats: BetaLeagueStats(
apm: entry.endContext[0].secondaryTracking[i],
pps: entry.endContext[0].tertiaryTracking[i],
vs: entry.endContext[0].extraTracking[i],
garbageSent: -1,
garbageReceived: -1,
kills: 0,
altitude: 0.0,
rank: -1
)
),BetaLeagueRound(
id: entry.endContext[1].userId,
username: entry.endContext[1].username,
naturalorder: entry.endContext[1].naturalOrder,
active: false,
alive: false,
lifetime: const Duration(milliseconds: -1),
stats: BetaLeagueStats(
apm: entry.endContext[1].secondaryTracking[i],
pps: entry.endContext[1].tertiaryTracking[i],
vs: entry.endContext[1].extraTracking[i],
garbageSent: -1,
garbageReceived: -1,
kills: 0,
altitude: 0.0,
rank: -1
)
)]
]
)
)
);
}
}
}

File diff suppressed because it is too large Load Diff

View File

@ -0,0 +1,188 @@
import 'package:flutter/material.dart';
const int currentSeason = 2;
const double noTrRd = 60.9;
const double apmWeight = 1;
const double ppsWeight = 45;
const double vsWeight = 0.444;
const double appWeight = 185;
const double dssWeight = 175;
const double dspWeight = 450;
const double appdspWeight = 140;
const double vsapmWeight = 60;
const double cheeseWeight = 1.25;
const double gbeWeight = 315;
const List<String> ranks = [
"d", "d+", "c-", "c", "c+", "b-", "b", "b+", "a-", "a", "a+", "s-", "s", "s+", "ss", "u", "x", "x+"
];
const Map<String, double> rankCutoffs = {
"x+": 0.002,
"x": 0.01,
"u": 0.05,
"ss": 0.11,
"s+": 0.17,
"s": 0.23,
"s-": 0.3,
"a+": 0.38,
"a": 0.46,
"a-": 0.54,
"b+": 0.62,
"b": 0.7,
"b-": 0.78,
"c+": 0.84,
"c": 0.9,
"c-": 0.95,
"d+": 0.975,
"d": 1,
"z": -1,
"": 0.5
};
const Map<String, double> rankTargets = {
"x+": 24000.00,
"x": 22500.00,
"u": 20000.00,
"ss": 18000.00,
"s+": 16500.00,
"s": 15200.00,
"s-": 13800.00,
"a+": 12000.00,
"a": 10500.00,
"a-": 9000.00,
"b+": 7400.00,
"b": 5700.00,
"b-": 4200.00,
"c+": 3000.00,
"c": 2000.00,
"c-": 1300.00,
"d+": 800.00,
"d": 0.00,
};
// DateTime seasonStart = DateTime.utc(2024, 08, 16, 18);
//DateTime seasonEnd = DateTime.utc(2024, 07, 26, 15);
enum Stats {
tr,
glicko,
gxe,
s1tr,
rd,
gp,
gw,
wr,
apm,
pps,
vs,
app,
dss,
dsp,
appdsp,
vsapm,
cheese,
gbe,
nyaapp,
area,
eTR,
acceTR,
acceTRabs,
opener,
plonk,
infDS,
stride,
stridemMinusPlonk,
openerMinusInfDS
}
const Map<Stats, String> chartsShortTitles = {
Stats.tr: "TR",
Stats.gxe: "Glixare",
Stats.s1tr: "S1 TR",
Stats.glicko: "Glicko",
Stats.rd: "RD",
Stats.gp: "GP",
Stats.gw: "GW",
Stats.wr: "WR%",
Stats.apm: "APM",
Stats.pps: "PPS",
Stats.vs: "VS",
Stats.app: "APP",
Stats.dss: "DS/S",
Stats.dsp: "DS/P",
Stats.appdsp: "APP + DS/P",
Stats.vsapm: "VS/APM",
Stats.cheese: "Cheese",
Stats.gbe: "GbE",
Stats.nyaapp: "wAPP",
Stats.area: "Area",
Stats.eTR: "eTR",
Stats.acceTR: "±eTR",
Stats.acceTRabs: "+eTR absolute",
Stats.opener: "Opener",
Stats.plonk: "Plonk",
Stats.infDS: "Inf. DS",
Stats.stride: "Stride",
Stats.stridemMinusPlonk: "Stride - Plonk",
Stats.openerMinusInfDS: "Opener - Inf. DS"
};
const Map<String, Color> rankColors = { // thanks osk for const rankColors at https://ch.tetr.io/res/js/base.js:458
'x+': Color(0xFF643C8D),
'x': Color(0xFFFF45FF),
'u': Color(0xFFFF3813),
'ss': Color(0xFFDB8B1F),
's+': Color(0xFFD8AF0E),
's': Color(0xFFE0A71B),
's-': Color(0xFFB2972B),
'a+': Color(0xFF1FA834),
'a': Color(0xFF46AD51),
'a-': Color(0xFF3BB687),
'b+': Color(0xFF4F99C0),
'b': Color(0xFF4F64C9),
'b-': Color(0xFF5650C7),
'c+': Color(0xFF552883),
'c': Color(0xFF733E8F),
'c-': Color(0xFF79558C),
'd+': Color(0xFF8E6091),
'd': Color(0xFF907591),
'z': Color(0xFF375433)
};
const Map<String, Duration> sprintAverages = { // based on https://discord.com/channels/673303546107658242/674421736162197515/1244287342965952562
'x': Duration(seconds: 25, milliseconds: 144),
'u': Duration(seconds: 36, milliseconds: 115),
'ss': Duration(seconds: 46, milliseconds: 396),
's+': Duration(seconds: 55, milliseconds: 056),
's': Duration(seconds: 61, milliseconds: 892),
's-': Duration(seconds: 68, milliseconds: 918),
'a+': Duration(seconds: 76, milliseconds: 187),
'a': Duration(seconds: 83, milliseconds: 529),
'a-': Duration(seconds: 88, milliseconds: 608),
'b+': Duration(seconds: 97, milliseconds: 626),
'b': Duration(seconds: 104, milliseconds: 687),
'b-': Duration(seconds: 113, milliseconds: 372),
'c+': Duration(seconds: 123, milliseconds: 461),
'c': Duration(seconds: 135, milliseconds: 326),
'c-': Duration(seconds: 147, milliseconds: 056),
'd+': Duration(seconds: 156, milliseconds: 757),
'd': Duration(seconds: 167, milliseconds: 393),
//'z': Duration(seconds: 66, milliseconds: 802)
};
const Map<String, int> blitzAverages = {
'x': 600715,
'u': 379418,
'ss': 233740,
's+': 158295,
's': 125164,
's-': 100933,
'a+': 83593,
'a': 68613,
'a-': 60219,
'b+': 51197,
'b': 44171,
'b-': 39045,
'c+': 34130,
'c': 28931,
'c-': 25095,
'd+': 22944,
'd': 20728,
//'z': 72084
};

View File

@ -1,7 +1,12 @@
import 'dart:math'; import 'dart:math';
import 'dart:typed_data'; import 'dart:typed_data';
import 'tetrio.dart'; import 'package:tetra_stats/data_objects/clears.dart';
import 'package:tetra_stats/data_objects/end_context_multi.dart';
import 'package:tetra_stats/data_objects/est_tr.dart';
import 'package:tetra_stats/data_objects/finesse.dart';
import 'package:tetra_stats/data_objects/nerd_stats.dart';
import 'package:tetra_stats/data_objects/playstyle.dart';
// I want to implement those fancy TWC stats // I want to implement those fancy TWC stats
// So, i'm going to read replay for things // So, i'm going to read replay for things

View File

@ -0,0 +1,150 @@
// ignore_for_file: hash_and_equals
import 'dart:math';
import 'package:flutter/foundation.dart';
import 'package:tetra_stats/data_objects/badge.dart';
import 'package:tetra_stats/data_objects/connections.dart';
import 'package:tetra_stats/data_objects/distinguishment.dart';
import 'package:tetra_stats/data_objects/tetrio_zen.dart';
class TetrioPlayer {
late String userId;
late String username;
late DateTime state;
late String role;
int? avatarRevision;
int? bannerRevision;
DateTime? registrationTime;
List<Badge> badges = [];
String? bio;
String? country;
late int friendCount;
late int gamesPlayed;
late int gamesWon;
late Duration gameTime;
late double xp;
late int supporterTier;
late bool verified;
bool? badstanding;
String? botmaster;
Connections? connections;
TetrioZen? zen;
Distinguishment? distinguishment;
DateTime? cachedUntil;
TetrioPlayer({
required this.userId,
required this.username,
required this.role,
required this.state,
this.avatarRevision,
this.bannerRevision,
this.registrationTime,
required this.badges,
this.bio,
this.country,
required this.friendCount,
required this.gamesPlayed,
required this.gamesWon,
required this.gameTime,
required this.xp,
required this.supporterTier,
required this.verified,
this.badstanding,
this.botmaster,
required this.connections,
this.zen,
this.distinguishment,
this.cachedUntil
});
double get level => pow((xp / 500), 0.6) + (xp / (5000 + (max(0, xp - 4 * pow(10, 6)) / 5000))) + 1;
TetrioPlayer.fromJson(Map<String, dynamic> json, DateTime stateTime, String id, String nick, [DateTime? cUntil]) {
//developer.log("TetrioPlayer.fromJson $stateTime: $json", name: "data_objects/tetrio");
userId = id;
username = nick;
state = stateTime;
role = json['role'];
registrationTime = json['ts'] != null ? DateTime.parse(json['ts']) : DateTime.fromMillisecondsSinceEpoch(int.parse(id.substring(0, 8), radix: 16) * 1000);
if (json['badges'] != null) {
json['badges'].forEach((v) {
badges.add(Badge.fromJson(v));
});
}
xp = json['xp'] != null ? json['xp'].toDouble() : -1;
gamesPlayed = json['gamesplayed'] ?? -1;
gamesWon = json['gameswon'] ?? -1;
gameTime = json['gametime'] != null && json['gametime'] != -1 ? Duration(microseconds: (json['gametime'].toDouble() * 1000000).floor()) : const Duration(seconds: -1);
country = json['country'];
supporterTier = json['supporter_tier'] ?? 0;
verified = json['verified'] ?? false;
avatarRevision = json['avatar_revision'];
bannerRevision = json['banner_revision'];
bio = json['bio'];
if (json['connections'] != null && json['connections'].isNotEmpty) connections = Connections.fromJson(json['connections']);
distinguishment = json['distinguishment'] != null ? Distinguishment.fromJson(json['distinguishment']) : null;
friendCount = json['friend_count'] ?? 0;
badstanding = json['badstanding'];
botmaster = json['botmaster'];
cachedUntil = cUntil;
}
Map<String, dynamic> toJson() {
final Map<String, dynamic> data = <String, dynamic>{};
// data['_id'] = userId;
// data['username'] = username;
data['role'] = role;
if (registrationTime != null) data['ts'] = registrationTime?.toString();
if (badges.isNotEmpty) data['badges'] = badges.map((v) => v.toJson()).toList();
if (xp >= 0) data['xp'] = xp;
if (gamesPlayed >= 0) data['gamesplayed'] = gamesPlayed;
if (gamesWon >= 0) data['gameswon'] = gamesWon;
if (!gameTime.isNegative) data['gametime'] = gameTime.inMicroseconds / 1000000;
if (country != null) data['country'] = country;
if (supporterTier > 0) data['supporter_tier'] = supporterTier;
if (verified) data['verified'] = verified;
if (distinguishment != null) data['distinguishment'] = distinguishment?.toJson();
if (avatarRevision != null) data['avatar_revision'] = avatarRevision;
if (bannerRevision != null) data['banner_revision'] = bannerRevision;
if (bio != null) data['bio'] = bio;
if (connections != null) data['connections'] = connections!.toJson();
if (friendCount > 0) data['friend_count'] = friendCount;
if (badstanding != null) data['badstanding'] = badstanding;
if (botmaster != null) data['botmaster'] = botmaster;
//developer.log("TetrioPlayer.toJson: $data", name: "data_objects/tetrio");
return data;
}
bool isSameState(covariant TetrioPlayer other) {
if (userId != other.userId) return false;
if (username != other.username) return false;
if (role != other.role) return false;
if (listEquals(badges, other.badges) == false) return false;
//if (bio != other.bio) return false;
if (country != other.country) return false;
if (friendCount != other.friendCount) return false;
if (gamesPlayed != other.gamesPlayed) return false;
if (gamesWon != other.gamesWon) return false;
if (gameTime != other.gameTime) return false;
if (xp != other.xp) return false;
if (supporterTier != other.supporterTier) return false;
if (verified != other.verified) return false;
if (badstanding != other.badstanding) return false;
if (botmaster != other.botmaster) return false;
if (connections != other.connections) return false;
if (distinguishment != other.distinguishment) return false;
return true;
}
@override
String toString() {
return "$username ($state)";
}
@override
int get hashCode => state.hashCode;
@override
bool operator ==(covariant TetrioPlayer other) => isSameState(other) && state.isAtSameMomentAs(other.state);
}

View File

@ -0,0 +1,145 @@
// ignore_for_file: hash_and_equals
import 'package:tetra_stats/data_objects/est_tr.dart';
import 'package:tetra_stats/data_objects/nerd_stats.dart';
import 'package:tetra_stats/data_objects/playstyle.dart';
import 'package:tetra_stats/data_objects/tetrio_constants.dart';
class TetrioPlayerFromLeaderboard {
late String userId;
late String username;
late String role;
late double xp;
String? country;
late DateTime timestamp;
late int gamesPlayed;
late int gamesWon;
late double tr;
late double gxe;
late double? glicko;
late double? rd;
late String rank;
late String? bestRank;
late double apm;
late double pps;
late double vs;
late bool decaying;
late NerdStats nerdStats;
late EstTr estTr;
late Playstyle playstyle;
TetrioPlayerFromLeaderboard(
this.userId,
this.username,
this.role,
this.xp,
this.country,
this.timestamp,
this.gamesPlayed,
this.gamesWon,
this.tr,
this.gxe,
this.glicko,
this.rd,
this.rank,
this.bestRank,
this.apm,
this.pps,
this.vs,
this.decaying){
nerdStats = NerdStats(apm, pps, vs);
estTr = EstTr(apm, pps, vs, nerdStats.app, nerdStats.dss, nerdStats.dsp, nerdStats.gbe);
playstyle = Playstyle(apm, pps, nerdStats.app, nerdStats.vsapm, nerdStats.dsp, nerdStats.gbe, estTr.srarea, estTr.statrank);
}
double get winrate => gamesWon / gamesPlayed;
double get esttracc => estTr.esttr - tr;
double get s1tr => gxe * 250;
TetrioPlayerFromLeaderboard.fromJson(Map<String, dynamic> json, DateTime ts) {
userId = json['_id'];
username = json['username'];
role = json['role'];
xp = json['xp'].toDouble();
country = json['country'];
timestamp = ts;
gamesPlayed = json['league']['gamesplayed'] as int;
gamesWon = json['league']['gameswon'] as int;
tr = json['league']['tr'] != null ? json['league']['tr'].toDouble() : 0;
gxe = json['league']['gxe']??-1;
glicko = json['league']['glicko']?.toDouble();
rd = json['league']['rd']?.toDouble();
rank = json['league']['rank'];
bestRank = json['league']['bestrank'];
apm = json['league']['apm'] != null ? json['league']['apm'].toDouble() : 0.00;
pps = json['league']['pps'] != null ? json['league']['pps'].toDouble() : 0.00;
vs = json['league']['vs'] != null ? json['league']['vs'].toDouble(): 0.00;
decaying = json['league']['decaying'];
nerdStats = NerdStats(apm, pps, vs);
estTr = EstTr(apm, pps, vs, nerdStats.app, nerdStats.dss, nerdStats.dsp, nerdStats.gbe);
playstyle = Playstyle(apm, pps, nerdStats.app, nerdStats.vsapm, nerdStats.dsp, nerdStats.gbe, estTr.srarea, estTr.statrank);
}
num getStatByEnum(Stats stat){
switch (stat) {
case Stats.tr:
return tr;
case Stats.glicko:
return glicko??-1;
case Stats.gxe:
return gxe;
case Stats.s1tr:
return s1tr;
case Stats.rd:
return rd??-1;
case Stats.gp:
return gamesPlayed;
case Stats.gw:
return gamesWon;
case Stats.wr:
return winrate*100;
case Stats.apm:
return apm;
case Stats.pps:
return pps;
case Stats.vs:
return vs;
case Stats.app:
return nerdStats.app;
case Stats.dss:
return nerdStats.dss;
case Stats.dsp:
return nerdStats.dsp;
case Stats.appdsp:
return nerdStats.appdsp;
case Stats.vsapm:
return nerdStats.vsapm;
case Stats.cheese:
return nerdStats.cheese;
case Stats.gbe:
return nerdStats.gbe;
case Stats.nyaapp:
return nerdStats.nyaapp;
case Stats.area:
return nerdStats.area;
case Stats.eTR:
return estTr.esttr;
case Stats.acceTR:
return esttracc;
case Stats.acceTRabs:
return esttracc.abs();
case Stats.opener:
return playstyle.opener;
case Stats.plonk:
return playstyle.plonk;
case Stats.infDS:
return playstyle.infds;
case Stats.stride:
return playstyle.stride;
case Stats.stridemMinusPlonk:
return playstyle.stride - playstyle.plonk;
case Stats.openerMinusInfDS:
return playstyle.opener - playstyle.infds;
}
}
}

View File

@ -0,0 +1,759 @@
// ignore_for_file: hash_and_equals
import 'dart:math';
import 'package:tetra_stats/data_objects/leaderboard_position.dart';
import 'package:tetra_stats/data_objects/player_leaderboard_position.dart';
import 'package:tetra_stats/data_objects/tetra_league.dart';
import 'package:tetra_stats/data_objects/tetrio_constants.dart';
import 'package:tetra_stats/data_objects/tetrio_player_from_leaderboard.dart';
class TetrioPlayersLeaderboard {
late String type;
late DateTime timestamp;
late List<TetrioPlayerFromLeaderboard> leaderboard;
TetrioPlayersLeaderboard(this.type, this.leaderboard);
@override
String toString(){
return "$type leaderboard: ${leaderboard.length} players";
}
List<TetrioPlayerFromLeaderboard> getStatRanking(List<TetrioPlayerFromLeaderboard> leaderboard, Stats stat, {bool reversed = false, String country = ""}){
List<TetrioPlayerFromLeaderboard> lb = List.from(leaderboard);
if (country.isNotEmpty){
lb.removeWhere((element) => element.country != country);
}
lb.sort(((a, b) {
if (a.getStatByEnum(stat).isNaN) return 1;
if (b.getStatByEnum(stat).isNaN) return -1;
if (a.getStatByEnum(stat) > b.getStatByEnum(stat)){
return reversed ? 1 : -1;
}else if (a.getStatByEnum(stat) == b.getStatByEnum(stat)){
return 0;
}else{
return reversed ? -1 : 1;
}
}));
return lb;
}
List<dynamic> getAverageOfRank(String rank){ // i tried to refactor it and that's was terrible
if (rank.isNotEmpty && !rankCutoffs.keys.contains(rank)) throw Exception("Invalid rank");
List<TetrioPlayerFromLeaderboard> filtredLeaderboard = List.from(leaderboard);
if (rank.isNotEmpty) {
filtredLeaderboard.removeWhere((element) => element.rank != rank);
}
if (filtredLeaderboard.isNotEmpty){
double avgAPM = 0,
avgPPS = 0,
avgVS = 0,
avgTR = 0,
avgGlixare = 0,
avgGlicko = 0,
avgRD = 0,
avgAPP = 0,
avgVSAPM = 0,
avgDSS = 0,
avgDSP = 0,
avgAPPDSP = 0,
avgCheese = 0,
avgGBE = 0,
avgNyaAPP = 0,
avgArea = 0,
avgEstTR = 0,
avgEstAcc = 0,
avgOpener = 0,
avgPlonk = 0,
avgStride = 0,
avgInfDS = 0,
lowestTR = 25000,
lowestGlixare = double.infinity,
lowestGlicko = double.infinity,
lowestRD = double.infinity,
lowestWinrate = double.infinity,
lowestAPM = double.infinity,
lowestPPS = double.infinity,
lowestVS = double.infinity,
lowestAPP = double.infinity,
lowestVSAPM = double.infinity,
lowestDSS = double.infinity,
lowestDSP = double.infinity,
lowestAPPDSP = double.infinity,
lowestCheese = double.infinity,
lowestGBE = double.infinity,
lowestNyaAPP = double.infinity,
lowestArea = double.infinity,
lowestEstTR = double.infinity,
lowestEstAcc = double.infinity,
lowestOpener = double.infinity,
lowestPlonk = double.infinity,
lowestStride = double.infinity,
lowestInfDS = double.infinity,
highestTR = double.negativeInfinity,
highestGlixare = double.negativeInfinity,
highestGlicko = double.negativeInfinity,
highestRD = double.negativeInfinity,
highestWinrate = double.negativeInfinity,
highestAPM = double.negativeInfinity,
highestPPS = double.negativeInfinity,
highestVS = double.negativeInfinity,
highestAPP = double.negativeInfinity,
highestVSAPM = double.negativeInfinity,
highestDSS = double.negativeInfinity,
highestDSP = double.negativeInfinity,
highestAPPDSP = double.negativeInfinity,
highestCheese = double.negativeInfinity,
highestGBE = double.negativeInfinity,
highestNyaAPP = double.negativeInfinity,
highestArea = double.negativeInfinity,
highestEstTR = double.negativeInfinity,
highestEstAcc = double.negativeInfinity,
highestOpener = double.negativeInfinity,
highestPlonk = double.negativeInfinity,
highestStride = double.negativeInfinity,
highestInfDS = double.negativeInfinity;
int avgGamesPlayed = 0,
avgGamesWon = 0,
totalGamesPlayed = 0,
totalGamesWon = 0,
lowestGamesPlayed = pow(2, 53) as int,
lowestGamesWon = pow(2, 53) as int,
highestGamesPlayed = 0,
highestGamesWon = 0;
String lowestTRid = "", lowestTRnick = "",
lowestGlixareID = "", lowestGlixareNick = "",
lowestGlickoID = "", lowestGlickoNick = "",
lowestRdID = "", lowestRdNick = "",
lowestGamesPlayedID = "", lowestGamesPlayedNick = "",
lowestGamesWonID = "", lowestGamesWonNick = "",
lowestWinrateID = "", lowestWinrateNick = "",
lowestAPMid = "", lowestAPMnick = "",
lowestPPSid = "", lowestPPSnick = "",
lowestVSid = "", lowestVSnick = "",
lowestAPPid = "", lowestAPPnick = "",
lowestVSAPMid = "", lowestVSAPMnick = "",
lowestDSSid = "", lowestDSSnick = "",
lowestDSPid = "", lowestDSPnick = "",
lowestAPPDSPid = "", lowestAPPDSPnick = "",
lowestCheeseID = "", lowestCheeseNick = "",
lowestGBEid = "", lowestGBEnick = "",
lowestNyaAPPid = "", lowestNyaAPPnick = "",
lowestAreaID = "", lowestAreaNick = "",
lowestEstTRid = "", lowestEstTRnick = "",
lowestEstAccID = "", lowestEstAccNick = "",
lowestOpenerID = "", lowestOpenerNick = "",
lowestPlonkID = "", lowestPlonkNick = "",
lowestStrideID = "", lowestStrideNick = "",
lowestInfDSid = "", lowestInfDSnick = "",
highestTRid = "", highestTRnick = "",
highestGlixareID = "", highestGlixareNick = "",
highestGlickoID = "", highestGlickoNick = "",
highestRdID = "", highestRdNick = "",
highestGamesPlayedID = "", highestGamesPlayedNick = "",
highestGamesWonID = "", highestGamesWonNick = "",
highestWinrateID = "", highestWinrateNick = "",
highestAPMid = "", highestAPMnick = "",
highestPPSid = "", highestPPSnick = "",
highestVSid = "", highestVSnick = "",
highestAPPid = "", highestAPPnick = "",
highestVSAPMid = "", highestVSAPMnick = "",
highestDSSid = "", highestDSSnick = "",
highestDSPid = "", highestDSPnick = "",
highestAPPDSPid = "", highestAPPDSPnick = "",
highestCheeseID = "", highestCheeseNick = "",
highestGBEid = "", highestGBEnick = "",
highestNyaAPPid = "", highestNyaAPPnick = "",
highestAreaID = "", highestAreaNick = "",
highestEstTRid = "", highestEstTRnick = "",
highestEstAccID = "", highestEstAccNick = "",
highestOpenerID = "", highestOpenerNick = "",
highestPlonkID = "", highestPlonkNick = "",
highestStrideID = "", highestStrideNick = "",
highestInfDSid = "", highestInfDSnick = "";
for (var entry in filtredLeaderboard){
avgAPM += entry.apm;
avgPPS += entry.pps;
avgVS += entry.vs;
avgTR += entry.tr;
avgGlixare += entry.gxe;
if (entry.glicko != null) avgGlicko += entry.glicko!;
if (entry.rd != null) avgRD += entry.rd!;
avgAPP += entry.nerdStats.app;
avgVSAPM += entry.nerdStats.vsapm;
avgDSS += entry.nerdStats.dss;
avgDSP += entry.nerdStats.dsp;
avgAPPDSP += entry.nerdStats.appdsp;
avgCheese += entry.nerdStats.cheese;
avgGBE += entry.nerdStats.gbe;
avgNyaAPP += entry.nerdStats.nyaapp;
avgArea += entry.nerdStats.area;
avgEstTR += entry.estTr.esttr;
avgEstAcc += entry.esttracc;
avgOpener += entry.playstyle.opener;
avgPlonk += entry.playstyle.plonk;
avgStride += entry.playstyle.stride;
avgInfDS += entry.playstyle.infds;
totalGamesPlayed += entry.gamesPlayed;
totalGamesWon += entry.gamesWon;
if (entry.tr < lowestTR){
lowestTR = entry.tr;
lowestTRid = entry.userId;
lowestTRnick = entry.username;
}
if (entry.gxe < lowestGlixare){
lowestGlixare = entry.gxe;
lowestGlixareID = entry.userId;
lowestGlixareNick = entry.username;
}
if (entry.glicko != null && entry.glicko! < lowestGlicko){
lowestGlicko = entry.glicko!;
lowestGlickoID = entry.userId;
lowestGlickoNick = entry.username;
}
if (entry.rd != null && entry.rd! < lowestRD){
lowestRD = entry.rd!;
lowestRdID = entry.userId;
lowestRdNick = entry.username;
}
if (entry.gamesPlayed < lowestGamesPlayed){
lowestGamesPlayed = entry.gamesPlayed;
lowestGamesPlayedID = entry.userId;
lowestGamesPlayedNick = entry.username;
}
if (entry.gamesWon < lowestGamesWon){
lowestGamesWon = entry.gamesWon;
lowestGamesWonID = entry.userId;
lowestGamesWonNick = entry.username;
}
if (entry.winrate < lowestWinrate){
lowestWinrate = entry.winrate;
lowestWinrateID = entry.userId;
lowestWinrateNick = entry.username;
}
if (entry.apm < lowestAPM){
lowestAPM = entry.apm;
lowestAPMid = entry.userId;
lowestAPMnick = entry.username;
}
if (entry.pps < lowestPPS){
lowestPPS = entry.pps;
lowestPPSid = entry.userId;
lowestPPSnick = entry.username;
}
if (entry.vs < lowestVS){
lowestVS = entry.vs;
lowestVSid = entry.userId;
lowestVSnick = entry.username;
}
if (entry.nerdStats.app < lowestAPP){
lowestAPP = entry.nerdStats.app;
lowestAPPid = entry.userId;
lowestAPPnick = entry.username;
}
if (entry.nerdStats.vsapm < lowestVSAPM){
lowestVSAPM = entry.nerdStats.vsapm;
lowestVSAPMid = entry.userId;
lowestVSAPMnick = entry.username;
}
if (entry.nerdStats.dss < lowestDSS){
lowestDSS = entry.nerdStats.dss;
lowestDSSid = entry.userId;
lowestDSSnick = entry.username;
}
if (entry.nerdStats.dsp < lowestDSP){
lowestDSP = entry.nerdStats.dsp;
lowestDSPid = entry.userId;
lowestDSPnick = entry.username;
}
if (entry.nerdStats.appdsp < lowestAPPDSP){
lowestAPPDSP = entry.nerdStats.appdsp;
lowestAPPDSPid = entry.userId;
lowestAPPDSPnick = entry.username;
}
if (entry.nerdStats.cheese < lowestCheese){
lowestCheese = entry.nerdStats.cheese;
lowestCheeseID = entry.userId;
lowestCheeseNick = entry.username;
}
if (entry.nerdStats.gbe < lowestGBE){
lowestGBE = entry.nerdStats.gbe;
lowestGBEid = entry.userId;
lowestGBEnick = entry.username;
}
if (entry.nerdStats.nyaapp < lowestNyaAPP){
lowestNyaAPP = entry.nerdStats.nyaapp;
lowestNyaAPPid = entry.userId;
lowestNyaAPPnick = entry.username;
}
if (entry.nerdStats.area < lowestArea){
lowestArea = entry.nerdStats.area;
lowestAreaID = entry.userId;
lowestAreaNick = entry.username;
}
if (entry.estTr.esttr < lowestEstTR){
lowestEstTR = entry.estTr.esttr;
lowestEstTRid = entry.userId;
lowestEstTRnick = entry.username;
}
if (entry.esttracc < lowestEstAcc){
lowestEstAcc = entry.esttracc;
lowestEstAccID = entry.userId;
lowestEstAccNick = entry.username;
}
if (entry.playstyle.opener < lowestOpener){
lowestOpener = entry.playstyle.opener;
lowestOpenerID = entry.userId;
lowestOpenerNick = entry.username;
}
if (entry.playstyle.plonk < lowestPlonk){
lowestPlonk = entry.playstyle.plonk;
lowestPlonkID = entry.userId;
lowestPlonkNick = entry.username;
}
if (entry.playstyle.stride < lowestStride){
lowestStride = entry.playstyle.stride;
lowestStrideID = entry.userId;
lowestStrideNick = entry.username;
}
if (entry.playstyle.infds < lowestInfDS){
lowestInfDS = entry.playstyle.infds;
lowestInfDSid = entry.userId;
lowestInfDSnick = entry.username;
}
if (entry.tr > highestTR){
highestTR = entry.tr;
highestTRid = entry.userId;
highestTRnick = entry.username;
}
if (entry.gxe > highestGlixare){
highestGlixare = entry.gxe;
highestGlixareID = entry.userId;
highestGlixareNick = entry.username;
}
if (entry.glicko != null && entry.glicko! > highestGlicko){
highestGlicko = entry.glicko!;
highestGlickoID = entry.userId;
highestGlickoNick = entry.username;
}
if (entry.rd != null && entry.rd! > highestRD){
highestRD = entry.rd!;
highestRdID = entry.userId;
highestRdNick = entry.username;
}
if (entry.gamesPlayed > highestGamesPlayed){
highestGamesPlayed = entry.gamesPlayed;
highestGamesPlayedID = entry.userId;
highestGamesPlayedNick = entry.username;
}
if (entry.gamesWon > highestGamesWon){
highestGamesWon = entry.gamesWon;
highestGamesWonID = entry.userId;
highestGamesWonNick = entry.username;
}
if (entry.winrate > highestWinrate){
highestWinrate = entry.winrate;
highestWinrateID = entry.userId;
highestWinrateNick = entry.username;
}
if (entry.apm > highestAPM){
highestAPM = entry.apm;
highestAPMid = entry.userId;
highestAPMnick = entry.username;
}
if (entry.pps > highestPPS){
highestPPS = entry.pps;
highestPPSid = entry.userId;
highestPPSnick = entry.username;
}
if (entry.vs > highestVS){
highestVS = entry.vs;
highestVSid = entry.userId;
highestVSnick = entry.username;
}
if (entry.nerdStats.app > highestAPP){
highestAPP = entry.nerdStats.app;
highestAPPid = entry.userId;
highestAPPnick = entry.username;
}
if (entry.nerdStats.vsapm > highestVSAPM){
highestVSAPM = entry.nerdStats.vsapm;
highestVSAPMid = entry.userId;
highestVSAPMnick = entry.username;
}
if (entry.nerdStats.dss > highestDSS){
highestDSS = entry.nerdStats.dss;
highestDSSid = entry.userId;
highestDSSnick = entry.username;
}
if (entry.nerdStats.dsp > highestDSP){
highestDSP = entry.nerdStats.dsp;
highestDSPid = entry.userId;
highestDSPnick = entry.username;
}
if (entry.nerdStats.appdsp > highestAPPDSP){
highestAPPDSP = entry.nerdStats.appdsp;
highestAPPDSPid = entry.userId;
highestAPPDSPnick = entry.username;
}
if (entry.nerdStats.cheese > highestCheese){
highestCheese = entry.nerdStats.cheese;
highestCheeseID = entry.userId;
highestCheeseNick = entry.username;
}
if (entry.nerdStats.gbe > highestGBE){
highestGBE = entry.nerdStats.gbe;
highestGBEid = entry.userId;
highestGBEnick = entry.username;
}
if (entry.nerdStats.nyaapp > highestNyaAPP){
highestNyaAPP = entry.nerdStats.nyaapp;
highestNyaAPPid = entry.userId;
highestNyaAPPnick = entry.username;
}
if (entry.nerdStats.area > highestArea){
highestArea = entry.nerdStats.area;
highestAreaID = entry.userId;
highestAreaNick = entry.username;
}
if (entry.estTr.esttr > highestEstTR){
highestEstTR = entry.estTr.esttr;
highestEstTRid = entry.userId;
highestEstTRnick = entry.username;
}
if (entry.esttracc > highestEstAcc){
highestEstAcc = entry.esttracc;
highestEstAccID = entry.userId;
highestEstAccNick = entry.username;
}
if (entry.playstyle.opener > highestOpener){
highestOpener = entry.playstyle.opener;
highestOpenerID = entry.userId;
highestOpenerNick = entry.username;
}
if (entry.playstyle.plonk > highestPlonk){
highestPlonk = entry.playstyle.plonk;
highestPlonkID = entry.userId;
highestPlonkNick = entry.username;
}
if (entry.playstyle.stride > highestStride){
highestStride = entry.playstyle.stride;
highestStrideID = entry.userId;
highestStrideNick = entry.username;
}
if (entry.playstyle.infds > highestInfDS){
highestInfDS = entry.playstyle.infds;
highestInfDSid = entry.userId;
highestInfDSnick = entry.username;
}
}
avgAPM /= filtredLeaderboard.length;
avgPPS /= filtredLeaderboard.length;
avgVS /= filtredLeaderboard.length;
avgTR /= filtredLeaderboard.length;
avgGlixare /= filtredLeaderboard.length;
avgGlicko /= filtredLeaderboard.length;
avgRD /= filtredLeaderboard.length;
avgAPP /= filtredLeaderboard.length;
avgVSAPM /= filtredLeaderboard.length;
avgDSS /= filtredLeaderboard.length;
avgDSP /= filtredLeaderboard.length;
avgAPPDSP /= leaderboard.length;
avgCheese /= filtredLeaderboard.length;
avgGBE /= filtredLeaderboard.length;
avgNyaAPP /= filtredLeaderboard.length;
avgArea /= filtredLeaderboard.length;
avgEstTR /= filtredLeaderboard.length;
avgEstAcc /= filtredLeaderboard.length;
avgOpener /= filtredLeaderboard.length;
avgPlonk /= filtredLeaderboard.length;
avgStride /= filtredLeaderboard.length;
avgInfDS /= filtredLeaderboard.length;
avgGamesPlayed = (totalGamesPlayed / filtredLeaderboard.length).floor();
avgGamesWon = (totalGamesWon / filtredLeaderboard.length).floor();
return [TetraLeague(id: "", timestamp: DateTime.now(), apm: avgAPM, pps: avgPPS, vs: avgVS, gxe: avgGlixare, glicko: avgGlicko, rd: avgRD, gamesPlayed: avgGamesPlayed, gamesWon: avgGamesWon, bestRank: rank, decaying: false, tr: avgTR, rank: rank == "" ? "z" : rank, percentileRank: rank, percentile: rankCutoffs[rank]!, standing: -1, standingLocal: -1, nextAt: -1, prevAt: -1, season: currentSeason),
{
"everyone": rank == "",
"totalGamesPlayed": totalGamesPlayed,
"totalGamesWon": totalGamesWon,
"players": filtredLeaderboard.length,
"lowestTR": lowestTR,
"lowestTRid": lowestTRid,
"lowestTRnick": lowestTRnick,
"lowestGlixare": lowestGlixare,
"lowestGlixareID": lowestGlixareID,
"lowestGlixareNick": lowestGlixareNick,
"lowestS1tr": lowestGlixare * 250,
"lowestS1trID": lowestGlixareID,
"lowestS1trNick": lowestGlixareNick,
"lowestGlicko": lowestGlicko,
"lowestGlickoID": lowestGlickoID,
"lowestGlickoNick": lowestGlickoNick,
"lowestRD": lowestRD,
"lowestRdID": lowestRdID,
"lowestRdNick": lowestRdNick,
"lowestGamesPlayed": lowestGamesPlayed,
"lowestGamesPlayedID": lowestGamesPlayedID,
"lowestGamesPlayedNick": lowestGamesPlayedNick,
"lowestGamesWon": lowestGamesWon,
"lowestGamesWonID": lowestGamesWonID,
"lowestGamesWonNick": lowestGamesWonNick,
"lowestWinrate": lowestWinrate,
"lowestWinrateID": lowestWinrateID,
"lowestWinrateNick": lowestWinrateNick,
"lowestAPM": lowestAPM,
"lowestAPMid": lowestAPMid,
"lowestAPMnick": lowestAPMnick,
"lowestPPS": lowestPPS,
"lowestPPSid": lowestPPSid,
"lowestPPSnick": lowestPPSnick,
"lowestVS": lowestVS,
"lowestVSid": lowestVSid,
"lowestVSnick": lowestVSnick,
"lowestAPP": lowestAPP,
"lowestAPPid": lowestAPPid,
"lowestAPPnick": lowestAPPnick,
"lowestVSAPM": lowestVSAPM,
"lowestVSAPMid": lowestVSAPMid,
"lowestVSAPMnick": lowestVSAPMnick,
"lowestDSS": lowestDSS,
"lowestDSSid": lowestDSSid,
"lowestDSSnick": lowestDSSnick,
"lowestDSP": lowestDSP,
"lowestDSPid": lowestDSPid,
"lowestDSPnick": lowestDSPnick,
"lowestAPPDSP": lowestAPPDSP,
"lowestAPPDSPid": lowestAPPDSPid,
"lowestAPPDSPnick": lowestAPPDSPnick,
"lowestCheese": lowestCheese,
"lowestCheeseID": lowestCheeseID,
"lowestCheeseNick": lowestCheeseNick,
"lowestGBE": lowestGBE,
"lowestGBEid": lowestGBEid,
"lowestGBEnick": lowestGBEnick,
"lowestNyaAPP": lowestNyaAPP,
"lowestNyaAPPid": lowestNyaAPPid,
"lowestNyaAPPnick": lowestNyaAPPnick,
"lowestArea": lowestArea,
"lowestAreaID": lowestAreaID,
"lowestAreaNick": lowestAreaNick,
"lowestEstTR": lowestEstTR,
"lowestEstTRid": lowestEstTRid,
"lowestEstTRnick": lowestEstTRnick,
"lowestEstAcc": lowestEstAcc,
"lowestEstAccID": lowestEstAccID,
"lowestEstAccNick": lowestEstAccNick,
"lowestOpener": lowestOpener,
"lowestOpenerID": lowestOpenerID,
"lowestOpenerNick": lowestOpenerNick,
"lowestPlonk": lowestPlonk,
"lowestPlonkID": lowestPlonkID,
"lowestPlonkNick": lowestPlonkNick,
"lowestStride": lowestStride,
"lowestStrideID": lowestStrideID,
"lowestStrideNick": lowestStrideNick,
"lowestInfDS": lowestInfDS,
"lowestInfDSid": lowestInfDSid,
"lowestInfDSnick": lowestInfDSnick,
"highestTR": highestTR,
"highestTRid": highestTRid,
"highestTRnick": highestTRnick,
"highestGlixare": highestGlixare,
"highestGlixareID": highestGlixareID,
"highestGlixareNick": highestGlixareNick,
"highestS1tr": highestGlixare * 250,
"highestS1trID": highestGlixareID,
"highestS1trNick": highestGlixareNick,
"highestGlicko": highestGlicko,
"highestGlickoID": highestGlickoID,
"highestGlickoNick": highestGlickoNick,
"highestRD": highestRD,
"highestRdID": highestRdID,
"highestRdNick": highestRdNick,
"highestGamesPlayed": highestGamesPlayed,
"highestGamesPlayedID": highestGamesPlayedID,
"highestGamesPlayedNick": highestGamesPlayedNick,
"highestGamesWon": highestGamesWon,
"highestGamesWonID": highestGamesWonID,
"highestGamesWonNick": highestGamesWonNick,
"highestWinrate": highestWinrate,
"highestWinrateID": highestWinrateID,
"highestWinrateNick": highestWinrateNick,
"highestAPM": highestAPM,
"highestAPMid": highestAPMid,
"highestAPMnick": highestAPMnick,
"highestPPS": highestPPS,
"highestPPSid": highestPPSid,
"highestPPSnick": highestPPSnick,
"highestVS": highestVS,
"highestVSid": highestVSid,
"highestVSnick": highestVSnick,
"highestAPP": highestAPP,
"highestAPPid": highestAPPid,
"highestAPPnick": highestAPPnick,
"highestVSAPM": highestVSAPM,
"highestVSAPMid": highestVSAPMid,
"highestVSAPMnick": highestVSAPMnick,
"highestDSS": highestDSS,
"highestDSSid": highestDSSid,
"highestDSSnick": highestDSSnick,
"highestDSP": highestDSP,
"highestDSPid": highestDSPid,
"highestDSPnick": highestDSPnick,
"highestAPPDSP": highestAPPDSP,
"highestAPPDSPid": highestAPPDSPid,
"highestAPPDSPnick": highestAPPDSPnick,
"highestCheese": highestCheese,
"highestCheeseID": highestCheeseID,
"highestCheeseNick": highestCheeseNick,
"highestGBE": highestGBE,
"highestGBEid": highestGBEid,
"highestGBEnick": highestGBEnick,
"highestNyaAPP": highestNyaAPP,
"highestNyaAPPid": highestNyaAPPid,
"highestNyaAPPnick": highestNyaAPPnick,
"highestArea": highestArea,
"highestAreaID": highestAreaID,
"highestAreaNick": highestAreaNick,
"highestEstTR": highestEstTR,
"highestEstTRid": highestEstTRid,
"highestEstTRnick": highestEstTRnick,
"highestEstAcc": highestEstAcc,
"highestEstAccID": highestEstAccID,
"highestEstAccNick": highestEstAccNick,
"highestOpener": highestOpener,
"highestOpenerID": highestOpenerID,
"highestOpenerNick": highestOpenerNick,
"highestPlonk": highestPlonk,
"highestPlonkID": highestPlonkID,
"highestPlonkNick": highestPlonkNick,
"highestStride": highestStride,
"highestStrideID": highestStrideID,
"highestStrideNick": highestStrideNick,
"highestInfDS": highestInfDS,
"highestInfDSid": highestInfDSid,
"highestInfDSnick": highestInfDSnick,
"avgAPP": avgAPP,
"avgVSAPM": avgVSAPM,
"avgDSS": avgDSS,
"avgDSP": avgDSP,
"avgAPPDSP": avgAPPDSP,
"avgCheese": avgCheese,
"avgGBE": avgGBE,
"avgNyaAPP": avgNyaAPP,
"avgArea": avgArea,
"avgEstTR": avgEstTR,
"avgEstAcc": avgEstAcc,
"avgOpener": avgOpener,
"avgPlonk": avgPlonk,
"avgStride": avgStride,
"avgInfDS": avgInfDS,
"toEnterTR": rank.toLowerCase() != "z" ? leaderboard[(leaderboard.length * rankCutoffs[rank]!).floor()-1].tr : lowestTR,
"toEnterGlicko": rank.toLowerCase() != "z" ? leaderboard[(leaderboard.length * rankCutoffs[rank]!).floor()-1].glicko : 0,
"entries": filtredLeaderboard
}];
}else{
return [TetraLeague(id: "", timestamp: DateTime.now(), apm: 0, pps: 0, vs: 0, glicko: 0, rd: noTrRd, gamesPlayed: 0, gamesWon: 0, bestRank: rank, decaying: false, tr: 0, rank: rank, percentileRank: rank, gxe: -1, percentile: rankCutoffs[rank]!, standing: -1, standingLocal: -1, nextAt: -1, prevAt: -1, season: currentSeason),
{"players": filtredLeaderboard.length, "lowestTR": 0, "toEnterTR": 0, "toEnterGlicko": 0}];
}
}
PlayerLeaderboardPosition? getLeaderboardPosition(Map<String, TetraLeague>league) {
if (league.values.first.gamesPlayed == 0) return null;
bool fakePositions = false;
late List<TetrioPlayerFromLeaderboard> copyOfLeaderboard;
if (leaderboard.indexWhere((element) => element.userId == league.keys.first) == -1){
fakePositions =true;
copyOfLeaderboard = List.of(leaderboard);
copyOfLeaderboard.add(league.values.first.convertToPlayerFromLeaderboard(league.keys.first));
}
List<Stats> stats = [Stats.apm, Stats.pps, Stats.vs, Stats.gp, Stats.gw, Stats.wr,
Stats.app, Stats.vsapm, Stats.dss, Stats.dsp, Stats.appdsp, Stats.cheese, Stats.gbe, Stats.nyaapp, Stats.area, Stats.eTR, Stats.acceTR];
List<LeaderboardPosition?> results = [];
for (Stats stat in stats) {
List<TetrioPlayerFromLeaderboard> sortedLeaderboard = getStatRanking(fakePositions ? copyOfLeaderboard : leaderboard, stat, reversed: stat == Stats.cheese ? true : false);
int position = sortedLeaderboard.indexWhere((element) => element.userId == league.keys.first) + 1;
if (position == 0) {
results.add(null);
} else {
results.add(LeaderboardPosition(fakePositions ? 1001 : position, position / sortedLeaderboard.length));
}
}
return PlayerLeaderboardPosition.fromSearchResults(results);
}
Map<String, List<dynamic>> get averages => {
'x+': getAverageOfRank("x+"),
'x': getAverageOfRank("x"),
'u': getAverageOfRank("u"),
'ss': getAverageOfRank("ss"),
's+': getAverageOfRank("s+"),
's': getAverageOfRank("s"),
's-': getAverageOfRank("s-"),
'a+': getAverageOfRank("a+"),
'a': getAverageOfRank("a"),
'a-': getAverageOfRank("a-"),
'b+': getAverageOfRank("b+"),
'b': getAverageOfRank("b"),
'b-': getAverageOfRank("b-"),
'c+': getAverageOfRank("c+"),
'c': getAverageOfRank("c"),
'c-': getAverageOfRank("c-"),
'd+': getAverageOfRank("d+"),
'd': getAverageOfRank("d"),
'z': getAverageOfRank("z")
};
Map<String, double> get cutoffs => {
'x': getAverageOfRank("x")[1]["toEnterTR"],
'u': getAverageOfRank("u")[1]["toEnterTR"],
'ss': getAverageOfRank("ss")[1]["toEnterTR"],
's+': getAverageOfRank("s+")[1]["toEnterTR"],
's': getAverageOfRank("s")[1]["toEnterTR"],
's-': getAverageOfRank("s-")[1]["toEnterTR"],
'a+': getAverageOfRank("a+")[1]["toEnterTR"],
'a': getAverageOfRank("a")[1]["toEnterTR"],
'a-': getAverageOfRank("a-")[1]["toEnterTR"],
'b+': getAverageOfRank("b+")[1]["toEnterTR"],
'b': getAverageOfRank("b")[1]["toEnterTR"],
'b-': getAverageOfRank("b-")[1]["toEnterTR"],
'c+': getAverageOfRank("c+")[1]["toEnterTR"],
'c': getAverageOfRank("c")[1]["toEnterTR"],
'c-': getAverageOfRank("c-")[1]["toEnterTR"],
'd+': getAverageOfRank("d+")[1]["toEnterTR"],
'd': getAverageOfRank("d")[1]["toEnterTR"]
};
Map<String, double> get cutoffsGlicko => {
'x': getAverageOfRank("x")[1]["toEnterGlicko"],
'u': getAverageOfRank("u")[1]["toEnterGlicko"],
'ss': getAverageOfRank("ss")[1]["toEnterGlicko"],
's+': getAverageOfRank("s+")[1]["toEnterGlicko"],
's': getAverageOfRank("s")[1]["toEnterGlicko"],
's-': getAverageOfRank("s-")[1]["toEnterGlicko"],
'a+': getAverageOfRank("a+")[1]["toEnterGlicko"],
'a': getAverageOfRank("a")[1]["toEnterGlicko"],
'a-': getAverageOfRank("a-")[1]["toEnterGlicko"],
'b+': getAverageOfRank("b+")[1]["toEnterGlicko"],
'b': getAverageOfRank("b")[1]["toEnterGlicko"],
'b-': getAverageOfRank("b-")[1]["toEnterGlicko"],
'c+': getAverageOfRank("c+")[1]["toEnterGlicko"],
'c': getAverageOfRank("c")[1]["toEnterGlicko"],
'c-': getAverageOfRank("c-")[1]["toEnterGlicko"],
'd+': getAverageOfRank("d+")[1]["toEnterGlicko"],
'd': getAverageOfRank("d")[1]["toEnterGlicko"]
};
TetrioPlayersLeaderboard.fromJson(List<dynamic> json, String t, DateTime ts) {
type = t;
timestamp = ts;
leaderboard = [];
for (Map<String, dynamic> entry in json) {
leaderboard.add(TetrioPlayerFromLeaderboard.fromJson(entry, ts));
}
}
addPlayers(List<TetrioPlayerFromLeaderboard> list){
leaderboard.addAll(list);
}
}

View File

@ -0,0 +1,24 @@
// ignore_for_file: hash_and_equals
import 'dart:math';
class TetrioZen {
late int level;
late int score;
TetrioZen({required this.level, required this.score});
double get scoreRequirement => (10000 + 10000 * ((log(level + 1) / log(2)) - 1));
TetrioZen.fromJson(Map<String, dynamic> json) {
level = json['level'];
score = json['score'];
}
Map<String, dynamic> toJson() {
final Map<String, dynamic> data = <String, dynamic>{};
data['level'] = level;
data['score'] = score;
return data;
}
}

View File

@ -0,0 +1,13 @@
// ignore_for_file: hash_and_equals
import 'package:tetra_stats/data_objects/record_single.dart';
import 'package:tetra_stats/data_objects/tetrio_zen.dart';
class UserRecords{
String id;
RecordSingle? sprint;
RecordSingle? blitz;
TetrioZen zen;
UserRecords(this.id, this.sprint, this.blitz, this.zen);
}

View File

@ -0,0 +1,36 @@
// ignore_for_file: hash_and_equals
class ZenithResults{
late double altitude;
late double rank;
late double peakrank;
late double avgrankpts;
late int floor;
late double targetingfactor;
late double targetinggrace;
late double totalbonus;
late int revives;
late int revivesTotal;
late bool speedrun;
late bool speedrunSeen;
late List<Duration> splits;
ZenithResults.fromJson(Map<String, dynamic> json){
altitude = json['altitude'].toDouble();
rank = json['rank'].toDouble();
peakrank = json['peakrank'].toDouble();
avgrankpts = json['avgrankpts'].toDouble();
floor = json['floor'];
targetingfactor = json['targetingfactor'].toDouble();
targetinggrace = json['targetinggrace'].toDouble();
totalbonus = json['totalbonus'].toDouble();
revives = json['revives'];
revivesTotal = json['revivesTotal'];
speedrun = json['speedrun'];
speedrunSeen = json['speedrun_seen'];
splits = [];
for (int ms in json['splits']) {
splits.add(Duration(milliseconds: ms));
}
}
}

View File

@ -16,7 +16,7 @@ import 'package:sqflite_common_ffi/sqflite_ffi.dart';
import 'package:sqflite_common_ffi_web/sqflite_ffi_web.dart'; import 'package:sqflite_common_ffi_web/sqflite_ffi_web.dart';
import 'package:tetra_stats/gen/strings.g.dart'; import 'package:tetra_stats/gen/strings.g.dart';
import 'package:flutter_localizations/flutter_localizations.dart'; import 'package:flutter_localizations/flutter_localizations.dart';
import 'package:tetra_stats/views/main_view.dart'; import 'package:tetra_stats/views/main_view_tiles.dart';
import 'package:tetra_stats/views/settings_view.dart'; import 'package:tetra_stats/views/settings_view.dart';
import 'package:tetra_stats/views/tracked_players_view.dart'; import 'package:tetra_stats/views/tracked_players_view.dart';
import 'package:tetra_stats/views/calc_view.dart'; import 'package:tetra_stats/views/calc_view.dart';

View File

@ -5,17 +5,32 @@ import 'dart:convert';
import 'dart:developer' as developer; import 'dart:developer' as developer;
import 'dart:io'; import 'dart:io';
import 'package:path_provider/path_provider.dart'; import 'package:path_provider/path_provider.dart';
import 'package:sqflite/sql.dart';
import 'package:sqflite_common_ffi/sqflite_ffi.dart'; import 'package:sqflite_common_ffi/sqflite_ffi.dart';
import 'package:tetra_stats/data_objects/tetra_stats.dart'; import 'package:tetra_stats/data_objects/cutoff_tetrio.dart';
import 'package:tetra_stats/data_objects/end_context_multi.dart';
import 'package:tetra_stats/data_objects/news.dart';
import 'package:tetra_stats/data_objects/p1nkl0bst3r.dart';
import 'package:tetra_stats/data_objects/player_leaderboard_position.dart';
import 'package:tetra_stats/data_objects/record_single.dart';
import 'package:tetra_stats/data_objects/singleplayer_stream.dart';
import 'package:tetra_stats/data_objects/summaries.dart';
import 'package:tetra_stats/data_objects/tetra_league.dart';
import 'package:tetra_stats/data_objects/tetra_league_alpha_record.dart';
import 'package:tetra_stats/data_objects/tetra_league_alpha_stream.dart';
import 'package:tetra_stats/data_objects/tetra_league_beta_stream.dart';
import 'package:tetra_stats/data_objects/tetrio_constants.dart';
import 'package:tetra_stats/data_objects/tetrio_multiplayer_replay.dart'; import 'package:tetra_stats/data_objects/tetrio_multiplayer_replay.dart';
import 'package:tetra_stats/data_objects/tetrio_player.dart';
import 'package:tetra_stats/data_objects/tetrio_player_from_leaderboard.dart';
import 'package:tetra_stats/data_objects/tetrio_players_leaderboard.dart';
import 'package:tetra_stats/data_objects/tetrio_zen.dart';
import 'package:tetra_stats/data_objects/user_records.dart';
import 'package:tetra_stats/main.dart' show packageInfo; import 'package:tetra_stats/main.dart' show packageInfo;
import 'package:flutter/foundation.dart'; import 'package:flutter/foundation.dart';
import 'package:tetra_stats/services/custom_http_client.dart'; import 'package:tetra_stats/services/custom_http_client.dart';
import 'package:http/http.dart' as http; import 'package:http/http.dart' as http;
import 'package:tetra_stats/services/crud_exceptions.dart'; import 'package:tetra_stats/services/crud_exceptions.dart';
import 'package:tetra_stats/services/sqlite_db_controller.dart'; import 'package:tetra_stats/services/sqlite_db_controller.dart';
import 'package:tetra_stats/data_objects/tetrio.dart';
import 'package:csv/csv.dart'; import 'package:csv/csv.dart';
const String dbName = "TetraStats.db"; const String dbName = "TetraStats.db";

View File

@ -2,7 +2,9 @@ import 'dart:io';
import 'package:flutter/foundation.dart'; import 'package:flutter/foundation.dart';
import 'package:flutter/material.dart'; import 'package:flutter/material.dart';
import 'package:intl/intl.dart'; import 'package:intl/intl.dart';
import 'package:tetra_stats/data_objects/tetrio.dart'; import 'package:tetra_stats/data_objects/est_tr.dart';
import 'package:tetra_stats/data_objects/nerd_stats.dart';
import 'package:tetra_stats/data_objects/playstyle.dart';
import 'package:tetra_stats/gen/strings.g.dart'; import 'package:tetra_stats/gen/strings.g.dart';
import 'package:tetra_stats/widgets/graphs.dart'; import 'package:tetra_stats/widgets/graphs.dart';
import 'package:window_manager/window_manager.dart'; import 'package:window_manager/window_manager.dart';

View File

@ -5,7 +5,10 @@ import 'dart:math';
import 'package:flutter/foundation.dart'; import 'package:flutter/foundation.dart';
import 'package:flutter/material.dart'; import 'package:flutter/material.dart';
import 'package:intl/intl.dart'; import 'package:intl/intl.dart';
import 'package:tetra_stats/data_objects/tetrio.dart'; import 'package:tetra_stats/data_objects/summaries.dart';
import 'package:tetra_stats/data_objects/tetra_league.dart';
import 'package:tetra_stats/data_objects/tetrio_constants.dart';
import 'package:tetra_stats/data_objects/tetrio_zen.dart';
import 'package:tetra_stats/gen/strings.g.dart'; import 'package:tetra_stats/gen/strings.g.dart';
import 'package:tetra_stats/main.dart' show teto; import 'package:tetra_stats/main.dart' show teto;
import 'package:tetra_stats/utils/relative_timestamps.dart'; import 'package:tetra_stats/utils/relative_timestamps.dart';

View File

@ -11,8 +11,25 @@ import 'package:intl/intl.dart';
import 'package:shared_preferences/shared_preferences.dart'; import 'package:shared_preferences/shared_preferences.dart';
import 'package:flutter/services.dart'; import 'package:flutter/services.dart';
import 'package:syncfusion_flutter_charts/charts.dart'; import 'package:syncfusion_flutter_charts/charts.dart';
import 'package:tetra_stats/data_objects/tetra_stats.dart'; import 'package:tetra_stats/data_objects/beta_record.dart';
import 'package:tetra_stats/data_objects/tetrio.dart'; import 'package:tetra_stats/data_objects/distinguishment.dart';
import 'package:tetra_stats/data_objects/news.dart';
import 'package:tetra_stats/data_objects/news_entry.dart';
import 'package:tetra_stats/data_objects/player_leaderboard_position.dart';
import 'package:tetra_stats/data_objects/record_extras.dart';
import 'package:tetra_stats/data_objects/record_single.dart';
import 'package:tetra_stats/data_objects/singleplayer_stream.dart';
import 'package:tetra_stats/data_objects/summaries.dart';
import 'package:tetra_stats/data_objects/tetra_league.dart';
import 'package:tetra_stats/data_objects/tetra_league_alpha_record.dart';
import 'package:tetra_stats/data_objects/tetra_league_alpha_stream.dart';
import 'package:tetra_stats/data_objects/tetra_league_beta_stream.dart';
import 'package:tetra_stats/data_objects/p1nkl0bst3r.dart';
import 'package:tetra_stats/data_objects/tetrio_constants.dart';
import 'package:tetra_stats/data_objects/tetrio_player.dart';
import 'package:tetra_stats/data_objects/tetrio_player_from_leaderboard.dart';
import 'package:tetra_stats/data_objects/tetrio_players_leaderboard.dart';
import 'package:tetra_stats/data_objects/tetrio_zen.dart';
import 'package:tetra_stats/gen/strings.g.dart'; import 'package:tetra_stats/gen/strings.g.dart';
import 'package:tetra_stats/main.dart' show prefs, teto; import 'package:tetra_stats/main.dart' show prefs, teto;
import 'package:tetra_stats/services/crud_exceptions.dart'; import 'package:tetra_stats/services/crud_exceptions.dart';
@ -338,7 +355,7 @@ class _MainState extends State<MainView> with TickerProviderStateMixin {
appBar: AppBar( appBar: AppBar(
title: _showSearchBar ? SearchBox(onSubmit: changePlayer, bigScreen: MediaQuery.of(context).size.width > 768) : Text(title, style: const TextStyle(shadows: textShadow)), title: _showSearchBar ? SearchBox(onSubmit: changePlayer, bigScreen: MediaQuery.of(context).size.width > 768) : Text(title, style: const TextStyle(shadows: textShadow)),
backgroundColor: Colors.black, backgroundColor: Colors.black,
actions: widget.player == null ? [ // search bar and PopupMenuButton hidden if player provided TODO: Subject to change actions: widget.player == null ? [ // search bar and PopupMenuButton hidden if player provided
_showSearchBar _showSearchBar
? IconButton( ? IconButton(
onPressed: () { onPressed: () {
@ -1555,7 +1572,7 @@ class _OtherThingy extends StatelessWidget {
child: Column( child: Column(
children: [ children: [
Text(t.bio, style: TextStyle(fontFamily: "Eurostile Round Extended",fontSize: bigScreen ? 42 : 28)), Text(t.bio, style: TextStyle(fontFamily: "Eurostile Round Extended",fontSize: bigScreen ? 42 : 28)),
MarkdownBody(data: bio!, styleSheet: MarkdownStyleSheet(textScaleFactor: 1.5, textAlign: WrapAlignment.center)) // Text(bio!, style: const TextStyle(fontSize: 18)), MarkdownBody(data: bio!, styleSheet: MarkdownStyleSheet(textScaler: TextScaler.linear(1.5), textAlign: WrapAlignment.center)) // Text(bio!, style: const TextStyle(fontSize: 18)),
], ],
), ),
), ),

View File

@ -6,7 +6,23 @@ import 'package:flutter_svg/flutter_svg.dart';
import 'package:intl/intl.dart'; import 'package:intl/intl.dart';
import 'package:syncfusion_flutter_charts/charts.dart'; import 'package:syncfusion_flutter_charts/charts.dart';
import 'package:syncfusion_flutter_gauges/gauges.dart'; import 'package:syncfusion_flutter_gauges/gauges.dart';
import 'package:tetra_stats/data_objects/tetra_stats.dart'; import 'package:tetra_stats/data_objects/badge.dart';
import 'package:tetra_stats/data_objects/beta_record.dart';
import 'package:tetra_stats/data_objects/distinguishment.dart';
import 'package:tetra_stats/data_objects/est_tr.dart';
import 'package:tetra_stats/data_objects/nerd_stats.dart';
import 'package:tetra_stats/data_objects/news.dart';
import 'package:tetra_stats/data_objects/news_entry.dart';
import 'package:tetra_stats/data_objects/p1nkl0bst3r.dart';
import 'package:tetra_stats/data_objects/playstyle.dart';
import 'package:tetra_stats/data_objects/record_extras.dart';
import 'package:tetra_stats/data_objects/record_single.dart';
import 'package:tetra_stats/data_objects/singleplayer_stream.dart';
import 'package:tetra_stats/data_objects/summaries.dart';
import 'package:tetra_stats/data_objects/tetra_league.dart';
import 'package:tetra_stats/data_objects/tetra_league_beta_stream.dart';
import 'package:tetra_stats/data_objects/tetrio_constants.dart';
import 'package:tetra_stats/data_objects/tetrio_player.dart';
import 'package:tetra_stats/gen/strings.g.dart'; import 'package:tetra_stats/gen/strings.g.dart';
import 'package:tetra_stats/services/crud_exceptions.dart'; import 'package:tetra_stats/services/crud_exceptions.dart';
import 'package:tetra_stats/utils/colors_functions.dart'; import 'package:tetra_stats/utils/colors_functions.dart';
@ -20,9 +36,7 @@ import 'package:tetra_stats/widgets/graphs.dart';
import 'package:tetra_stats/widgets/lineclears_thingy.dart'; import 'package:tetra_stats/widgets/lineclears_thingy.dart';
import 'package:tetra_stats/widgets/list_tile_trailing_stats.dart'; import 'package:tetra_stats/widgets/list_tile_trailing_stats.dart';
import 'package:tetra_stats/widgets/sp_trailing_stats.dart'; import 'package:tetra_stats/widgets/sp_trailing_stats.dart';
import 'package:tetra_stats/widgets/stat_sell_num.dart';
import 'package:tetra_stats/widgets/text_timestamp.dart'; import 'package:tetra_stats/widgets/text_timestamp.dart';
import 'package:tetra_stats/data_objects/tetrio.dart';
import 'package:tetra_stats/main.dart'; import 'package:tetra_stats/main.dart';
import 'package:tetra_stats/widgets/tl_progress_bar.dart'; import 'package:tetra_stats/widgets/tl_progress_bar.dart';
import 'package:tetra_stats/widgets/user_thingy.dart'; import 'package:tetra_stats/widgets/user_thingy.dart';
@ -594,6 +608,35 @@ class RecordSummary extends StatelessWidget{
} }
class LeagueCard extends StatelessWidget{
final TetraLeague league;
final bool showSeasonNumber;
const LeagueCard({super.key, required this.league, this.showSeasonNumber = false});
@override
Widget build(BuildContext context) {
return Card(
child: Padding(
padding: const EdgeInsets.fromLTRB(20.0, 8.0, 20.0, 12.0),
child: Center(
child: Column(
crossAxisAlignment: CrossAxisAlignment.center,
children: [
Text(showSeasonNumber ? "Season ${league.season}" : "Tetra League", style: TextStyle(fontFamily: "Eurostile Round Extended", fontSize: 28, height: 0.9)),
const Divider(color: Color.fromARGB(50, 158, 158, 158)),
TLRatingThingy(userID: "", tlData: league, showPositions: true),
const Divider(color: Color.fromARGB(50, 158, 158, 158)),
Text("${league.apm != null ? f2.format(league.apm) : "-.--"} APM • ${league.pps != null ? f2.format(league.pps) : "-.--"} PPS • ${league.vs != null ? f2.format(league.vs) : "-.--"} VS • ${league.nerdStats != null ? f2.format(league.nerdStats!.app) : "-.--"} APP • ${league.nerdStats != null ? f2.format(league.nerdStats!.vsapm) : "-.--"} VS/APM", style: const TextStyle(color: Colors.grey))
],
),
),
),
);
}
}
class _DestinationHomeState extends State<DestinationHome> { class _DestinationHomeState extends State<DestinationHome> {
Cards rightCard = Cards.overview; Cards rightCard = Cards.overview;
CardMod cardMod = CardMod.info; CardMod cardMod = CardMod.info;
@ -645,23 +688,7 @@ class _DestinationHomeState extends State<DestinationHome> {
), ),
), ),
), ),
Card( LeagueCard(league: summaries.league),
child: Padding(
padding: const EdgeInsets.fromLTRB(20.0, 8.0, 20.0, 12.0),
child: Center(
child: Column(
crossAxisAlignment: CrossAxisAlignment.center,
children: [
const Text("Tetra League", style: TextStyle(fontFamily: "Eurostile Round Extended", fontSize: 28, height: 0.9)),
const Divider(color: Color.fromARGB(50, 158, 158, 158)),
TLRatingThingy(userID: "", tlData: summaries.league, showPositions: true),
const Divider(color: Color.fromARGB(50, 158, 158, 158)),
Text("${summaries.league.apm != null ? f2.format(summaries.league.apm) : "-.--"} APM • ${summaries.league.pps != null ? f2.format(summaries.league.pps) : "-.--"} PPS • ${summaries.league.vs != null ? f2.format(summaries.league.vs) : "-.--"} VS • ${summaries.league.nerdStats != null ? f2.format(summaries.league.nerdStats!.app) : "-.--"} APP • ${summaries.league.nerdStats != null ? f2.format(summaries.league.nerdStats!.vsapm) : "-.--"} VS/APM", style: const TextStyle(color: Colors.grey))
],
),
),
),
),
Row( Row(
crossAxisAlignment: CrossAxisAlignment.start, crossAxisAlignment: CrossAxisAlignment.start,
children: [ children: [
@ -840,6 +867,7 @@ class _DestinationHomeState extends State<DestinationHome> {
return Column( return Column(
children: [ children: [
Card( Card(
//surfaceTintColor: rankColors[data.rank],
child: Padding( child: Padding(
padding: const EdgeInsets.only(bottom: 4.0), padding: const EdgeInsets.only(bottom: 4.0),
child: Center( child: Center(
@ -856,6 +884,7 @@ class _DestinationHomeState extends State<DestinationHome> {
), ),
TetraLeagueThingy(league: data, cutoffs: cutoffs), TetraLeagueThingy(league: data, cutoffs: cutoffs),
if (data.nerdStats != null) Card( if (data.nerdStats != null) Card(
//surfaceTintColor: rankColors[data.rank],
child: Row( child: Row(
mainAxisSize: MainAxisSize.min, mainAxisSize: MainAxisSize.min,
children: [ children: [
@ -871,6 +900,31 @@ class _DestinationHomeState extends State<DestinationHome> {
); );
} }
Widget getPreviousSeasonsList(Map<int, TetraLeague> pastLeague){
return Column(
children: [
Card(
child: Padding(
padding: const EdgeInsets.only(bottom: 4.0),
child: Center(
child: Column(
mainAxisSize: MainAxisSize.min,
crossAxisAlignment: CrossAxisAlignment.center,
children: [
Text("Previous Seasons", style: const TextStyle(fontFamily: "Eurostile Round Extended", fontSize: 42)),
//Text("${t.seasonStarts} ${countdown(postSeasonLeft)}", textAlign: TextAlign.center)
],
),
),
),
),
for (var key in pastLeague.keys) Card(
child: LeagueCard(league: pastLeague[key]!, showSeasonNumber: true),
)
],
);
}
Widget getListOfRecords(String recentStream, String topStream, BoxConstraints constraints){ Widget getListOfRecords(String recentStream, String topStream, BoxConstraints constraints){
return Column( return Column(
children: [ children: [
@ -1373,6 +1427,10 @@ class _DestinationHomeState extends State<DestinationHome> {
value: CardMod.info, value: CardMod.info,
label: Text('Standing'), label: Text('Standing'),
), ),
const ButtonSegment<CardMod>(
value: CardMod.ex, // yeah i misusing my own Enum shut the fuck up
label: Text('Previous Seasons'),
),
const ButtonSegment<CardMod>( const ButtonSegment<CardMod>(
value: CardMod.records, value: CardMod.records,
label: Text('Recent Matches'), label: Text('Recent Matches'),
@ -1436,10 +1494,10 @@ class _DestinationHomeState extends State<DestinationHome> {
Column( Column(
mainAxisSize: MainAxisSize.min, mainAxisSize: MainAxisSize.min,
children: [ children: [
Text(t.errors.noSuchUser, style: const TextStyle(fontFamily: "Eurostile Round", fontSize: 42, fontWeight: FontWeight.bold), textAlign: TextAlign.center), Text(snapshot.error.toString(), style: const TextStyle(fontFamily: "Eurostile Round", fontSize: 42, fontWeight: FontWeight.bold), textAlign: TextAlign.center),
Padding( Padding(
padding: const EdgeInsets.only(top: 8.0), padding: const EdgeInsets.only(top: 8.0),
child: Text(t.errors.noSuchUserSub, textAlign: TextAlign.center), child: Text(snapshot.stackTrace.toString(), textAlign: TextAlign.center),
), ),
], ],
) )
@ -1524,6 +1582,7 @@ class _DestinationHomeState extends State<DestinationHome> {
Cards.overview => getOverviewCard(snapshot.data!.summaries!), Cards.overview => getOverviewCard(snapshot.data!.summaries!),
Cards.tetraLeague => switch (cardMod){ Cards.tetraLeague => switch (cardMod){
CardMod.info => getTetraLeagueCard(snapshot.data!.summaries!.league, snapshot.data!.cutoffs), CardMod.info => getTetraLeagueCard(snapshot.data!.summaries!.league, snapshot.data!.cutoffs),
CardMod.ex => getPreviousSeasonsList(snapshot.data!.summaries!.pastLeague),
CardMod.records => getRecentTLrecords(widget.constraints), CardMod.records => getRecentTLrecords(widget.constraints),
_ => const Center(child: Text("huh?")) _ => const Center(child: Text("huh?"))
}, },
@ -1532,7 +1591,6 @@ class _DestinationHomeState extends State<DestinationHome> {
CardMod.records => getListOfRecords("zenith/recent", "zenith/top", widget.constraints), CardMod.records => getListOfRecords("zenith/recent", "zenith/top", widget.constraints),
CardMod.ex => getZenithCard(snapshot.data?.summaries!.zenithEx), CardMod.ex => getZenithCard(snapshot.data?.summaries!.zenithEx),
CardMod.exRecords => getListOfRecords("zenithex/recent", "zenithex/top", widget.constraints), CardMod.exRecords => getListOfRecords("zenithex/recent", "zenithex/top", widget.constraints),
_ => const Center(child: Text("huh?"))
}, },
Cards.sprint => switch (cardMod){ Cards.sprint => switch (cardMod){
CardMod.info => getRecordCard(snapshot.data?.summaries!.sprint, sprintBetterThanRankAverage, closestAverageSprint, sprintBetterThanClosestAverage, snapshot.data!.summaries!.league.rank), CardMod.info => getRecordCard(snapshot.data?.summaries!.sprint, sprintBetterThanRankAverage, closestAverageSprint, sprintBetterThanClosestAverage, snapshot.data!.summaries!.league.rank),
@ -2356,6 +2414,7 @@ class TetraLeagueThingy extends StatelessWidget{
@override @override
Widget build(BuildContext context) { Widget build(BuildContext context) {
return Card( return Card(
//surfaceTintColor: rankColors[league.rank],
child: Column( child: Column(
children: [ children: [
TLRatingThingy(userID: "w", tlData: league), TLRatingThingy(userID: "w", tlData: league),

View File

@ -3,7 +3,9 @@ import 'package:flutter/foundation.dart';
import 'package:flutter/gestures.dart'; import 'package:flutter/gestures.dart';
import 'package:flutter/material.dart'; import 'package:flutter/material.dart';
import 'package:intl/intl.dart'; import 'package:intl/intl.dart';
import 'package:tetra_stats/data_objects/tetrio.dart'; import 'package:tetra_stats/data_objects/tetrio_constants.dart';
import 'package:tetra_stats/data_objects/tetrio_player_from_leaderboard.dart';
import 'package:tetra_stats/data_objects/tetrio_players_leaderboard.dart';
import 'package:tetra_stats/gen/strings.g.dart'; import 'package:tetra_stats/gen/strings.g.dart';
import 'package:tetra_stats/views/main_view.dart' show MainView; import 'package:tetra_stats/views/main_view.dart' show MainView;
import 'package:window_manager/window_manager.dart'; import 'package:window_manager/window_manager.dart';

View File

@ -1,7 +1,8 @@
import 'dart:io'; import 'dart:io';
import 'package:flutter/foundation.dart'; import 'package:flutter/foundation.dart';
import 'package:flutter/material.dart'; import 'package:flutter/material.dart';
import 'package:tetra_stats/data_objects/tetrio.dart'; import 'package:tetra_stats/data_objects/cutoff_tetrio.dart';
import 'package:tetra_stats/data_objects/tetrio_constants.dart';
import 'package:tetra_stats/gen/strings.g.dart'; import 'package:tetra_stats/gen/strings.g.dart';
import 'package:tetra_stats/utils/numers_formats.dart'; import 'package:tetra_stats/utils/numers_formats.dart';
import 'package:tetra_stats/utils/text_shadow.dart'; import 'package:tetra_stats/utils/text_shadow.dart';

View File

@ -1,6 +1,6 @@
import 'dart:io'; import 'dart:io';
import 'package:go_router/go_router.dart'; import 'package:go_router/go_router.dart';
import 'package:tetra_stats/data_objects/tetrio.dart'; import 'package:tetra_stats/data_objects/tetrio_player.dart';
import 'package:tetra_stats/main.dart' show packageInfo, teto, prefs; import 'package:tetra_stats/main.dart' show packageInfo, teto, prefs;
import 'package:file_selector/file_selector.dart'; import 'package:file_selector/file_selector.dart';
import 'package:file_picker/file_picker.dart'; import 'package:file_picker/file_picker.dart';

View File

@ -1,5 +1,5 @@
import 'package:flutter/material.dart'; import 'package:flutter/material.dart';
import 'package:tetra_stats/data_objects/tetrio.dart'; import 'package:tetra_stats/data_objects/record_single.dart';
import 'package:tetra_stats/gen/strings.g.dart'; import 'package:tetra_stats/gen/strings.g.dart';
import 'package:tetra_stats/widgets/singleplayer_record.dart'; import 'package:tetra_stats/widgets/singleplayer_record.dart';
import 'package:tetra_stats/widgets/text_timestamp.dart'; import 'package:tetra_stats/widgets/text_timestamp.dart';

View File

@ -2,7 +2,7 @@ import 'dart:io';
import 'package:flutter/foundation.dart'; import 'package:flutter/foundation.dart';
import 'package:flutter/material.dart'; import 'package:flutter/material.dart';
import 'package:intl/intl.dart'; import 'package:intl/intl.dart';
import 'package:tetra_stats/data_objects/tetrio.dart'; import 'package:tetra_stats/data_objects/tetrio_constants.dart';
import 'package:tetra_stats/gen/strings.g.dart'; import 'package:tetra_stats/gen/strings.g.dart';
import 'package:tetra_stats/utils/relative_timestamps.dart'; import 'package:tetra_stats/utils/relative_timestamps.dart';
import 'package:tetra_stats/utils/text_shadow.dart'; import 'package:tetra_stats/utils/text_shadow.dart';

View File

@ -2,11 +2,10 @@ import 'dart:io';
import 'package:flutter/foundation.dart'; import 'package:flutter/foundation.dart';
import 'package:flutter/material.dart'; import 'package:flutter/material.dart';
import 'package:intl/intl.dart'; import 'package:intl/intl.dart';
import 'package:tetra_stats/data_objects/tetrio.dart'; import 'package:tetra_stats/data_objects/tetra_league.dart';
import 'package:tetra_stats/gen/strings.g.dart'; import 'package:tetra_stats/gen/strings.g.dart';
import 'package:tetra_stats/widgets/text_timestamp.dart'; import 'package:tetra_stats/widgets/text_timestamp.dart';
import 'package:tetra_stats/widgets/tl_thingy.dart'; import 'package:tetra_stats/widgets/tl_thingy.dart';
import 'package:tetra_stats/widgets/user_thingy.dart';
import 'package:window_manager/window_manager.dart'; import 'package:window_manager/window_manager.dart';
final DateFormat dateFormat = DateFormat.yMMMd(LocaleSettings.currentLocale.languageCode).add_Hms(); final DateFormat dateFormat = DateFormat.yMMMd(LocaleSettings.currentLocale.languageCode).add_Hms();
@ -41,13 +40,9 @@ class StateState extends State<StateView> {
super.dispose(); super.dispose();
} }
void _justUpdate() {
setState(() {});
}
@override @override
Widget build(BuildContext context) { Widget build(BuildContext context) {
final t = Translations.of(context); //final t = Translations.of(context);
return Scaffold( return Scaffold(
appBar: AppBar( appBar: AppBar(
title: Text("State from ${timestamp(widget.state.timestamp)}"), title: Text("State from ${timestamp(widget.state.timestamp)}"),

View File

@ -1,7 +1,7 @@
import 'dart:io'; import 'dart:io';
import 'package:flutter/foundation.dart'; import 'package:flutter/foundation.dart';
import 'package:flutter/material.dart'; import 'package:flutter/material.dart';
import 'package:tetra_stats/data_objects/tetrio.dart'; import 'package:tetra_stats/data_objects/tetra_league.dart';
import 'package:tetra_stats/gen/strings.g.dart'; import 'package:tetra_stats/gen/strings.g.dart';
import 'package:tetra_stats/main.dart' show teto; import 'package:tetra_stats/main.dart' show teto;
import 'package:tetra_stats/utils/numers_formats.dart'; import 'package:tetra_stats/utils/numers_formats.dart';

View File

@ -2,7 +2,7 @@ import 'dart:io';
import 'package:flutter/foundation.dart'; import 'package:flutter/foundation.dart';
import 'package:flutter/material.dart'; import 'package:flutter/material.dart';
import 'package:intl/intl.dart'; import 'package:intl/intl.dart';
import 'package:tetra_stats/data_objects/tetrio.dart'; import 'package:tetra_stats/data_objects/tetrio_constants.dart';
import 'package:tetra_stats/gen/strings.g.dart'; import 'package:tetra_stats/gen/strings.g.dart';
import 'package:tetra_stats/main.dart'; import 'package:tetra_stats/main.dart';
import 'package:tetra_stats/views/main_view.dart'; import 'package:tetra_stats/views/main_view.dart';

View File

@ -1,6 +1,9 @@
// ignore_for_file: use_build_context_synchronously, type_literal_in_constant_pattern // ignore_for_file: use_build_context_synchronously, type_literal_in_constant_pattern
import 'dart:io'; import 'dart:io';
import 'package:tetra_stats/data_objects/beta_league_round.dart';
import 'package:tetra_stats/data_objects/beta_league_stats.dart';
import 'package:tetra_stats/data_objects/beta_record.dart';
import 'package:tetra_stats/data_objects/tetrio_multiplayer_replay.dart'; import 'package:tetra_stats/data_objects/tetrio_multiplayer_replay.dart';
import 'package:tetra_stats/utils/relative_timestamps.dart'; import 'package:tetra_stats/utils/relative_timestamps.dart';
import 'package:tetra_stats/views/compare_view.dart' show CompareThingy; import 'package:tetra_stats/views/compare_view.dart' show CompareThingy;
@ -10,7 +13,6 @@ import 'package:tetra_stats/widgets/vs_graphs.dart';
import 'package:flutter/foundation.dart'; import 'package:flutter/foundation.dart';
import 'package:flutter/material.dart'; import 'package:flutter/material.dart';
import 'package:intl/intl.dart'; import 'package:intl/intl.dart';
import 'package:tetra_stats/data_objects/tetrio.dart';
import 'package:tetra_stats/gen/strings.g.dart'; import 'package:tetra_stats/gen/strings.g.dart';
import 'package:tetra_stats/utils/open_in_browser.dart'; import 'package:tetra_stats/utils/open_in_browser.dart';
import 'package:window_manager/window_manager.dart'; import 'package:window_manager/window_manager.dart';

View File

@ -2,12 +2,10 @@ import 'dart:io';
import 'package:flutter/foundation.dart'; import 'package:flutter/foundation.dart';
import 'package:flutter/material.dart'; import 'package:flutter/material.dart';
import 'package:intl/intl.dart'; import 'package:intl/intl.dart';
import 'package:tetra_stats/data_objects/tetrio.dart';
import 'package:tetra_stats/gen/strings.g.dart'; import 'package:tetra_stats/gen/strings.g.dart';
import 'package:tetra_stats/main.dart' show teto; import 'package:tetra_stats/main.dart' show teto;
import 'package:tetra_stats/utils/filesizes_converter.dart'; import 'package:tetra_stats/utils/filesizes_converter.dart';
import 'package:tetra_stats/views/states_view.dart'; import 'package:tetra_stats/views/states_view.dart';
import 'package:tetra_stats/widgets/text_timestamp.dart';
import 'package:window_manager/window_manager.dart'; import 'package:window_manager/window_manager.dart';
late String oldWindowTitle; late String oldWindowTitle;

View File

@ -1,5 +1,5 @@
import 'package:flutter/material.dart'; import 'package:flutter/material.dart';
import 'package:tetra_stats/data_objects/tetrio.dart'; import 'package:tetra_stats/data_objects/record_single.dart';
import 'package:tetra_stats/gen/strings.g.dart'; import 'package:tetra_stats/gen/strings.g.dart';
import 'package:tetra_stats/widgets/text_timestamp.dart'; import 'package:tetra_stats/widgets/text_timestamp.dart';
import 'package:tetra_stats/widgets/zenith_thingy.dart'; import 'package:tetra_stats/widgets/zenith_thingy.dart';

View File

@ -1,7 +1,7 @@
// ignore_for_file: curly_braces_in_flow_control_structures // ignore_for_file: curly_braces_in_flow_control_structures
import 'package:flutter/material.dart'; import 'package:flutter/material.dart';
import 'package:tetra_stats/data_objects/tetrio.dart'; import 'package:tetra_stats/data_objects/finesse.dart';
import 'package:tetra_stats/utils/numers_formats.dart'; import 'package:tetra_stats/utils/numers_formats.dart';
import 'package:tetra_stats/utils/text_shadow.dart'; import 'package:tetra_stats/utils/text_shadow.dart';

View File

@ -2,7 +2,7 @@
import 'package:flutter/material.dart'; import 'package:flutter/material.dart';
import 'package:syncfusion_flutter_gauges/gauges.dart'; import 'package:syncfusion_flutter_gauges/gauges.dart';
import 'package:tetra_stats/data_objects/tetrio.dart'; import 'package:tetra_stats/data_objects/leaderboard_position.dart';
import 'package:tetra_stats/gen/strings.g.dart'; import 'package:tetra_stats/gen/strings.g.dart';
import 'package:tetra_stats/utils/colors_functions.dart'; import 'package:tetra_stats/utils/colors_functions.dart';
import 'package:tetra_stats/utils/numers_formats.dart'; import 'package:tetra_stats/utils/numers_formats.dart';

View File

@ -8,9 +8,11 @@ import 'package:fl_chart/src/chart/radar_chart/radar_chart_renderer.dart';
import 'package:fl_chart/src/chart/base/base_chart/base_chart_painter.dart'; import 'package:fl_chart/src/chart/base/base_chart/base_chart_painter.dart';
import 'package:fl_chart/src/utils/canvas_wrapper.dart'; import 'package:fl_chart/src/utils/canvas_wrapper.dart';
import 'package:fl_chart/src/utils/utils.dart'; import 'package:fl_chart/src/utils/utils.dart';
import 'package:tetra_stats/data_objects/nerd_stats.dart';
import 'package:tetra_stats/data_objects/playstyle.dart';
import 'package:tetra_stats/data_objects/tetrio_constants.dart';
import 'package:tetra_stats/main.dart' show prefs; import 'package:tetra_stats/main.dart' show prefs;
import 'package:flutter/material.dart'; import 'package:flutter/material.dart';
import 'package:tetra_stats/data_objects/tetrio.dart';
import 'package:tetra_stats/gen/strings.g.dart'; import 'package:tetra_stats/gen/strings.g.dart';
import 'package:tetra_stats/utils/numers_formats.dart'; import 'package:tetra_stats/utils/numers_formats.dart';

View File

@ -1,5 +1,5 @@
import 'package:flutter/material.dart'; import 'package:flutter/material.dart';
import 'package:tetra_stats/data_objects/tetrio.dart'; import 'package:tetra_stats/data_objects/clears.dart';
import 'package:tetra_stats/gen/strings.g.dart'; import 'package:tetra_stats/gen/strings.g.dart';
class LineclearsThingy extends StatelessWidget{ class LineclearsThingy extends StatelessWidget{

View File

@ -1,6 +1,7 @@
import 'package:flutter/material.dart'; import 'package:flutter/material.dart';
import 'package:intl/intl.dart'; import 'package:intl/intl.dart';
import 'package:tetra_stats/data_objects/tetrio.dart'; import 'package:tetra_stats/data_objects/record_single.dart';
import 'package:tetra_stats/data_objects/singleplayer_stream.dart';
import 'package:tetra_stats/gen/strings.g.dart'; import 'package:tetra_stats/gen/strings.g.dart';
import 'package:tetra_stats/utils/relative_timestamps.dart'; import 'package:tetra_stats/utils/relative_timestamps.dart';
import 'package:tetra_stats/utils/text_shadow.dart'; import 'package:tetra_stats/utils/text_shadow.dart';

View File

@ -1,6 +1,8 @@
import 'package:flutter/material.dart'; import 'package:flutter/material.dart';
import 'package:intl/intl.dart'; import 'package:intl/intl.dart';
import 'package:tetra_stats/data_objects/tetrio.dart'; import 'package:tetra_stats/data_objects/record_single.dart';
import 'package:tetra_stats/data_objects/singleplayer_stream.dart';
import 'package:tetra_stats/data_objects/tetrio_constants.dart';
import 'package:tetra_stats/gen/strings.g.dart'; import 'package:tetra_stats/gen/strings.g.dart';
import 'package:tetra_stats/utils/colors_functions.dart'; import 'package:tetra_stats/utils/colors_functions.dart';
import 'package:tetra_stats/utils/numers_formats.dart'; import 'package:tetra_stats/utils/numers_formats.dart';

View File

@ -1,5 +1,5 @@
import 'package:flutter/material.dart'; import 'package:flutter/material.dart';
import 'package:tetra_stats/data_objects/tetrio.dart'; import 'package:tetra_stats/data_objects/record_single.dart';
import 'package:tetra_stats/utils/numers_formats.dart'; import 'package:tetra_stats/utils/numers_formats.dart';
import 'package:tetra_stats/utils/relative_timestamps.dart'; import 'package:tetra_stats/utils/relative_timestamps.dart';

View File

@ -1,6 +1,6 @@
import 'package:flutter/material.dart'; import 'package:flutter/material.dart';
import 'package:intl/intl.dart'; import 'package:intl/intl.dart';
import 'package:tetra_stats/data_objects/tetrio.dart'; import 'package:tetra_stats/data_objects/leaderboard_position.dart';
import 'package:tetra_stats/gen/strings.g.dart'; import 'package:tetra_stats/gen/strings.g.dart';
import 'package:tetra_stats/utils/colors_functions.dart'; import 'package:tetra_stats/utils/colors_functions.dart';
import 'package:tetra_stats/utils/numers_formats.dart'; import 'package:tetra_stats/utils/numers_formats.dart';

View File

@ -4,7 +4,7 @@ import 'package:flutter/material.dart';
import 'package:intl/intl.dart'; import 'package:intl/intl.dart';
import 'package:syncfusion_flutter_gauges/gauges.dart'; import 'package:syncfusion_flutter_gauges/gauges.dart';
import 'package:tetra_stats/data_objects/glicko.dart'; import 'package:tetra_stats/data_objects/glicko.dart';
import 'package:tetra_stats/data_objects/tetrio.dart'; import 'package:tetra_stats/data_objects/tetra_league.dart';
import 'package:tetra_stats/gen/strings.g.dart'; import 'package:tetra_stats/gen/strings.g.dart';
import 'package:tetra_stats/utils/numers_formats.dart'; import 'package:tetra_stats/utils/numers_formats.dart';

View File

@ -1,7 +1,7 @@
import 'package:flutter/material.dart'; import 'package:flutter/material.dart';
import 'package:intl/intl.dart'; import 'package:intl/intl.dart';
import 'package:tetra_stats/data_objects/tetrio.dart'; import 'package:tetra_stats/data_objects/tetra_league.dart';
import 'package:tetra_stats/gen/strings.g.dart'; import 'package:tetra_stats/gen/strings.g.dart';
import 'package:tetra_stats/main.dart' show prefs; import 'package:tetra_stats/main.dart' show prefs;
import 'package:tetra_stats/utils/numers_formats.dart'; import 'package:tetra_stats/utils/numers_formats.dart';

View File

@ -1,14 +1,11 @@
import 'dart:async';
import 'package:flutter/material.dart'; import 'package:flutter/material.dart';
import 'package:intl/intl.dart'; import 'package:intl/intl.dart';
import 'package:tetra_stats/data_objects/tetrio.dart'; import 'package:tetra_stats/data_objects/player_leaderboard_position.dart';
import 'package:tetra_stats/data_objects/tetra_league.dart';
import 'package:syncfusion_flutter_gauges/gauges.dart'; import 'package:syncfusion_flutter_gauges/gauges.dart';
import 'package:tetra_stats/gen/strings.g.dart'; import 'package:tetra_stats/gen/strings.g.dart';
import 'package:tetra_stats/main.dart';
import 'package:tetra_stats/utils/colors_functions.dart'; import 'package:tetra_stats/utils/colors_functions.dart';
import 'package:tetra_stats/utils/numers_formats.dart'; import 'package:tetra_stats/utils/numers_formats.dart';
import 'package:tetra_stats/utils/relative_timestamps.dart';
import 'package:tetra_stats/widgets/gauget_num.dart'; import 'package:tetra_stats/widgets/gauget_num.dart';
import 'package:tetra_stats/widgets/graphs.dart'; import 'package:tetra_stats/widgets/graphs.dart';
import 'package:tetra_stats/widgets/stat_sell_num.dart'; import 'package:tetra_stats/widgets/stat_sell_num.dart';
@ -80,8 +77,6 @@ class _TLThingyState extends State<TLThingy> with TickerProviderStateMixin {
return Column( return Column(
children: [ children: [
if (widget.showTitle) Text(t.tetraLeague, style: TextStyle(fontFamily: "Eurostile Round Extended", fontSize: bigScreen ? 42 : 28)), if (widget.showTitle) Text(t.tetraLeague, style: TextStyle(fontFamily: "Eurostile Round Extended", fontSize: bigScreen ? 42 : 28)),
//if (DateTime.now().isBefore(seasonEnd)) Text(t.seasonEnds(countdown: countdown(seasonLeft)))
//else Text(t.seasonEnded),
if (oldTl != null) Text(t.comparingWith(newDate: timestamp(currentTl.timestamp), oldDate: timestamp(oldTl!.timestamp)), if (oldTl != null) Text(t.comparingWith(newDate: timestamp(currentTl.timestamp), oldDate: timestamp(oldTl!.timestamp)),
textAlign: TextAlign.center,), textAlign: TextAlign.center,),
if (oldTl != null) RangeSlider(values: _currentRangeValues, max: widget.states.length.toDouble(), if (oldTl != null) RangeSlider(values: _currentRangeValues, max: widget.states.length.toDouble(),
@ -95,7 +90,7 @@ class _TLThingyState extends State<TLThingy> with TickerProviderStateMixin {
if (values.start.round() == 0){ if (values.start.round() == 0){
currentTl = widget.tl; currentTl = widget.tl;
}else{ }else{
currentTl = sortedStates[values.start.round()-1]!; currentTl = sortedStates[values.start.round()-1];
} }
if (values.end.round() == 0){ if (values.end.round() == 0){
oldTl = widget.tl; oldTl = widget.tl;
@ -207,7 +202,6 @@ class _TLThingyState extends State<TLThingy> with TickerProviderStateMixin {
oldPlayerStat: oldTl?.nerdStats?.appdsp,), oldPlayerStat: oldTl?.nerdStats?.appdsp,),
StatCellNum(playerStat: currentTl.nerdStats!.cheese, isScreenBig: bigScreen, fractionDigits: 2, playerStatLabel: t.statCellNum.cheese, StatCellNum(playerStat: currentTl.nerdStats!.cheese, isScreenBig: bigScreen, fractionDigits: 2, playerStatLabel: t.statCellNum.cheese,
pos: widget.lbPositions?.cheese, pos: widget.lbPositions?.cheese,
//averageStat: rankAverages?.nerdStats?.cheese, TODO: questonable
alertWidgets: [Text(t.statCellNum.cheeseDescription), alertWidgets: [Text(t.statCellNum.cheeseDescription),
Text("${t.formula}: (DS/P * 150) + ((VS/APM - 2) * 50) + (0.6 - APP) * 125"), Text("${t.formula}: (DS/P * 150) + ((VS/APM - 2) * 50) + (0.6 - APP) * 125"),
Text("${t.exactValue}: ${currentTl.nerdStats!.cheese}"),], Text("${t.exactValue}: ${currentTl.nerdStats!.cheese}"),],

View File

@ -2,7 +2,7 @@ import 'package:flutter/foundation.dart';
import 'package:flutter/material.dart'; import 'package:flutter/material.dart';
import 'package:flutter/services.dart'; import 'package:flutter/services.dart';
import 'package:syncfusion_flutter_gauges/gauges.dart'; import 'package:syncfusion_flutter_gauges/gauges.dart';
import 'package:tetra_stats/data_objects/tetrio.dart'; import 'package:tetra_stats/data_objects/tetrio_player.dart';
import 'package:tetra_stats/gen/strings.g.dart'; import 'package:tetra_stats/gen/strings.g.dart';
import 'package:tetra_stats/main.dart' show teto; import 'package:tetra_stats/main.dart' show teto;
import 'package:tetra_stats/views/compare_view.dart'; import 'package:tetra_stats/views/compare_view.dart';

View File

@ -1,7 +1,9 @@
import 'package:fl_chart/fl_chart.dart'; import 'package:fl_chart/fl_chart.dart';
import 'package:flutter/material.dart'; import 'package:flutter/material.dart';
import 'package:tetra_stats/data_objects/nerd_stats.dart';
import 'package:tetra_stats/data_objects/playstyle.dart';
import 'package:tetra_stats/data_objects/tetrio_constants.dart';
import 'package:tetra_stats/widgets/graphs.dart' show MyRadarChart; import 'package:tetra_stats/widgets/graphs.dart' show MyRadarChart;
import 'package:tetra_stats/data_objects/tetrio.dart';
import 'package:tetra_stats/gen/strings.g.dart'; import 'package:tetra_stats/gen/strings.g.dart';
class VsGraphs extends StatelessWidget{ class VsGraphs extends StatelessWidget{

View File

@ -1,6 +1,7 @@
import 'package:flutter/material.dart'; import 'package:flutter/material.dart';
import 'package:syncfusion_flutter_gauges/gauges.dart'; import 'package:syncfusion_flutter_gauges/gauges.dart';
import 'package:tetra_stats/data_objects/tetrio.dart'; import 'package:tetra_stats/data_objects/record_extras.dart';
import 'package:tetra_stats/data_objects/record_single.dart';
import 'package:tetra_stats/gen/strings.g.dart'; import 'package:tetra_stats/gen/strings.g.dart';
import 'package:tetra_stats/utils/colors_functions.dart'; import 'package:tetra_stats/utils/colors_functions.dart';
import 'package:tetra_stats/utils/numers_formats.dart'; import 'package:tetra_stats/utils/numers_formats.dart';