Compare commits

..

No commits in common. "54a5cc683ce9b8869663c18999854ed8151931bf" and "d34b072fcd6c7479cbbabb9438523de31e45c154" have entirely different histories.

17 changed files with 1184 additions and 1143 deletions

File diff suppressed because it is too large Load Diff

View File

@ -897,11 +897,11 @@ class TetraLeagueAlphaRecord{
TetraLeagueAlphaRecord({required this.replayId, required this.ownId, required this.timestamp, required this.endContext, required this.replayAvalable}); TetraLeagueAlphaRecord({required this.replayId, required this.ownId, required this.timestamp, required this.endContext, required this.replayAvalable});
TetraLeagueAlphaRecord.fromJson(Map<String, dynamic> json) { TetraLeagueAlphaRecord.fromJson(Map<String, dynamic> json) {
ownId = json['_id'];
endContext = [EndContextMulti.fromJson(json['endcontext'][0]), EndContextMulti.fromJson(json['endcontext'][1])]; endContext = [EndContextMulti.fromJson(json['endcontext'][0]), EndContextMulti.fromJson(json['endcontext'][1])];
replayId = json['replayid']; replayId = json['replayid'];
ownId = json['_id']??replayId;
timestamp = DateTime.parse(json['ts']); timestamp = DateTime.parse(json['ts']);
replayAvalable = ownId != replayId; replayAvalable = true;
} }
Map<String, dynamic> toJson() { Map<String, dynamic> toJson() {
@ -973,19 +973,19 @@ class EndContextMulti {
EndContextMulti.fromJson(Map<String, dynamic> json) { EndContextMulti.fromJson(Map<String, dynamic> json) {
userId = json['id'] ?? json['user']['_id']; userId = json['id'] ?? json['user']['_id'];
username = json['username'] ?? json['user']['username']; 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); handling = Handling.fromJson(json['handling']);
success = json['success']; success = json['success'];
inputs = json['inputs'] ?? -1; inputs = json['inputs'];
piecesPlaced = json['piecesplaced'] ?? -1; piecesPlaced = json['piecesplaced'];
naturalOrder = json['naturalorder']; naturalOrder = json['naturalorder'];
wins = json['wins']; wins = json['wins'];
points = json['points']['primary']; points = json['points']['primary'];
secondary = json['points']['secondary'].toDouble(); secondary = json['points']['secondary'].toDouble();
tertiary = json['points']['tertiary'].toDouble(); tertiary = json['points']['tertiary'].toDouble();
secondaryTracking = json['points']['secondaryAvgTracking'] != null ? json['points']['secondaryAvgTracking'].map((e) => e.toDouble()).toList() : []; secondaryTracking = json['points']['secondaryAvgTracking'].map((e) => e.toDouble()).toList();
tertiaryTracking = json['points']['tertiaryAvgTracking'] != null ? json['points']['tertiaryAvgTracking'].map((e) => e.toDouble()).toList() : []; tertiaryTracking = json['points']['tertiaryAvgTracking'].map((e) => e.toDouble()).toList();
extra = json['points']['extra']['vs'].toDouble(); extra = json['points']['extra']['vs'].toDouble();
extraTracking = json['points']['extraAvgTracking'] != null ? json['points']['extraAvgTracking']['aggregatestats___vsscore'].map((e) => e.toDouble()).toList() : []; extraTracking = json['points']['extraAvgTracking']['aggregatestats___vsscore'].map((e) => e.toDouble()).toList();
nerdStats = NerdStats(secondary, tertiary, extra); nerdStats = NerdStats(secondary, tertiary, extra);
nerdStatsTracking = [for (int i = 0; i < secondaryTracking.length; i++) NerdStats(secondaryTracking[i], tertiaryTracking[i], extraTracking[i])]; 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); estTr = EstTr(secondary, tertiary, extra, nerdStats.app, nerdStats.dss, nerdStats.dsp, nerdStats.gbe);

File diff suppressed because it is too large Load Diff

View File

@ -6,7 +6,7 @@
/// Locales: 2 /// Locales: 2
/// Strings: 1182 (591 per locale) /// Strings: 1182 (591 per locale)
/// ///
/// Built on 2024-07-10 at 15:23 UTC /// Built on 2024-06-16 at 21:03 UTC
// coverage:ignore-file // coverage:ignore-file
// ignore_for_file: type=lint // ignore_for_file: type=lint
@ -321,7 +321,7 @@ class Translations implements BaseTranslations<AppLocale, Translations> {
String get fromBeginning => 'From beginning'; String get fromBeginning => 'From beginning';
String get calc => 'Calc'; String get calc => 'Calc';
String get calcViewNoValues => 'Enter values to calculate the stats'; String get calcViewNoValues => 'Enter values to calculate the stats';
String get rankAveragesViewTitle => 'Ranks cutoffs'; String get rankAveragesViewTitle => 'Ranks cutoff and average stats';
String get sprintAndBlitsViewTitle => '40 lines and Blitz averages'; String get sprintAndBlitsViewTitle => '40 lines and Blitz averages';
String sprintAndBlitsRelevance({required Object date}) => 'Relevance: ${date}'; String sprintAndBlitsRelevance({required Object date}) => 'Relevance: ${date}';
String get rank => 'Rank'; String get rank => 'Rank';
@ -1016,7 +1016,7 @@ class _StringsRu implements Translations {
@override String get fromBeginning => 'С начала'; @override String get fromBeginning => 'С начала';
@override String get calc => 'Считать'; @override String get calc => 'Считать';
@override String get calcViewNoValues => 'Введите значения, чтобы посчитать статистику'; @override String get calcViewNoValues => 'Введите значения, чтобы посчитать статистику';
@override String get rankAveragesViewTitle => 'Требования рангов'; @override String get rankAveragesViewTitle => 'Требования рангов и средние значения';
@override String get sprintAndBlitsViewTitle => 'Средние результаты 40 линий и блица'; @override String get sprintAndBlitsViewTitle => 'Средние результаты 40 линий и блица';
@override String sprintAndBlitsRelevance({required Object date}) => 'Актуальность: ${date}'; @override String sprintAndBlitsRelevance({required Object date}) => 'Актуальность: ${date}';
@override String get rank => 'Ранг'; @override String get rank => 'Ранг';
@ -1703,7 +1703,7 @@ extension on Translations {
case 'fromBeginning': return 'From beginning'; case 'fromBeginning': return 'From beginning';
case 'calc': return 'Calc'; case 'calc': return 'Calc';
case 'calcViewNoValues': return 'Enter values to calculate the stats'; case 'calcViewNoValues': return 'Enter values to calculate the stats';
case 'rankAveragesViewTitle': return 'Ranks cutoffs'; case 'rankAveragesViewTitle': return 'Ranks cutoff and average stats';
case 'sprintAndBlitsViewTitle': return '40 lines and Blitz averages'; case 'sprintAndBlitsViewTitle': return '40 lines and Blitz averages';
case 'sprintAndBlitsRelevance': return ({required Object date}) => 'Relevance: ${date}'; case 'sprintAndBlitsRelevance': return ({required Object date}) => 'Relevance: ${date}';
case 'rank': return 'Rank'; case 'rank': return 'Rank';
@ -2314,7 +2314,7 @@ extension on _StringsRu {
case 'fromBeginning': return 'С начала'; case 'fromBeginning': return 'С начала';
case 'calc': return 'Считать'; case 'calc': return 'Считать';
case 'calcViewNoValues': return 'Введите значения, чтобы посчитать статистику'; case 'calcViewNoValues': return 'Введите значения, чтобы посчитать статистику';
case 'rankAveragesViewTitle': return 'Требования рангов'; case 'rankAveragesViewTitle': return 'Требования рангов и средние значения';
case 'sprintAndBlitsViewTitle': return 'Средние результаты 40 линий и блица'; case 'sprintAndBlitsViewTitle': return 'Средние результаты 40 линий и блица';
case 'sprintAndBlitsRelevance': return ({required Object date}) => 'Актуальность: ${date}'; case 'sprintAndBlitsRelevance': return ({required Object date}) => 'Актуальность: ${date}';
case 'rank': return 'Ранг'; case 'rank': return 'Ранг';

View File

@ -606,7 +606,7 @@ class TetrioService extends DB {
if (kIsWeb) { if (kIsWeb) {
url = Uri.https('ts.dan63.by', 'oskware_bridge.php', {"endpoint": "TLMatches", "user": userID}); url = Uri.https('ts.dan63.by', 'oskware_bridge.php', {"endpoint": "TLMatches", "user": userID});
} else { } else {
url = Uri.https('api.p1nkl0bst3r.xyz', 'tlmatches/$userID', {"before": "0", "count": "9000"}); url = Uri.https('api.p1nkl0bst3r.xyz', 'tlmatches/$userID');
} }
try{ try{
@ -614,9 +614,62 @@ class TetrioService extends DB {
switch (response.statusCode) { switch (response.statusCode) {
case 200: case 200:
TetraLeagueAlphaStream stream = TetraLeagueAlphaStream.fromJson(jsonDecode(response.body)['data']['records'], userID); // that one api returns csv instead of json
saveTLMatchesFromStream(stream); List<List<dynamic>> csv = const CsvToListConverter().convert(response.body)..removeAt(0);
return stream.records; List<TetraLeagueAlphaRecord> matches = [];
// parsing data into TetraLeagueAlphaRecord objects
for (var entry in csv){
TetraLeagueAlphaRecord match = TetraLeagueAlphaRecord(
replayId: entry[0].toString(),
ownId: entry[0].toString(), // i gonna disting p1nkl0bst3r entries with it
timestamp: DateTime.parse(entry[1]),
endContext: [
EndContextMulti(
userId: entry[2].toString(),
username: entry[3].toString(),
naturalOrder: 0,
inputs: -1,
piecesPlaced: -1,
handling: Handling(arr: -1, das: -1, sdf: -1, dcd: 0, cancel: true, safeLock: true),
points: entry[4],
wins: entry[4],
secondary: entry[6],
secondaryTracking: [],
tertiary: entry[5],
tertiaryTracking: [],
extra: entry[7],
extraTracking: [],
success: true
),
EndContextMulti(
userId: entry[8].toString(),
username: entry[9].toString(),
naturalOrder: 1,
inputs: -1,
piecesPlaced: -1,
handling: Handling(arr: -1, das: -1, sdf: -1, dcd: 0, cancel: true, safeLock: true),
points: entry[10],
wins: entry[10],
secondary: entry[12],
secondaryTracking: [],
tertiary: entry[11],
tertiaryTracking: [],
extra: entry[13],
extraTracking: [],
success: false
)
],
replayAvalable: false
);
matches.add(match);
}
// trying to dump it to local DB
TetraLeagueAlphaStream fakeStream = TetraLeagueAlphaStream(userId: userID, records: matches);
saveTLMatchesFromStream(fakeStream);
return matches;
case 404: case 404:
developer.log("fetchAndSaveOldTLmatches: Probably, history doesn't exist", name: "services/tetrio_crud", error: response.statusCode); developer.log("fetchAndSaveOldTLmatches: Probably, history doesn't exist", name: "services/tetrio_crud", error: response.statusCode);
throw TetrioHistoryNotExist(); throw TetrioHistoryNotExist();

View File

@ -306,7 +306,7 @@ class _MainState extends State<MainView> with TickerProviderStateMixin {
}); });
} }
return [me, records, states, tlMatches, compareWith, isTracking, news, topTR, recent, sprint, blitz, tlMatches.elementAtOrNull(0)?.timestamp]; return [me, records, states, tlMatches, compareWith, isTracking, news, topTR, recent, sprint, blitz];
} }
/// Triggers widgets rebuild /// Triggers widgets rebuild
@ -459,7 +459,6 @@ class _MainState extends State<MainView> with TickerProviderStateMixin {
userID: snapshot.data![0].userId, userID: snapshot.data![0].userId,
states: snapshot.data![2], states: snapshot.data![2],
topTR: snapshot.data![7]?.tr, topTR: snapshot.data![7]?.tr,
lastMatchPlayed: snapshot.data![11],
bot: snapshot.data![0].role == "bot", bot: snapshot.data![0].role == "bot",
guest: snapshot.data![0].role == "anon", guest: snapshot.data![0].role == "anon",
thatRankCutoff: thatRankCutoff, thatRankCutoff: thatRankCutoff,
@ -1085,7 +1084,7 @@ class _TwoRecordsThingy extends StatelessWidget {
if (sprint != null) FinesseThingy(sprint?.endContext.finesse, sprint?.endContext.finessePercentage), if (sprint != null) FinesseThingy(sprint?.endContext.finesse, sprint?.endContext.finessePercentage),
if (sprint != null) LineclearsThingy(sprint!.endContext.clears, sprint!.endContext.lines, sprint!.endContext.holds, sprint!.endContext.tSpins), if (sprint != null) LineclearsThingy(sprint!.endContext.clears, sprint!.endContext.lines, sprint!.endContext.holds, sprint!.endContext.tSpins),
if (sprint != null) Text("${sprint!.endContext.inputs} KP • ${f2.format(sprint!.endContext.kps)} KPS"), if (sprint != null) Text("${sprint!.endContext.inputs} KP • ${f2.format(sprint!.endContext.kps)} KPS"),
if (sprint != null) Wrap( Wrap(
alignment: WrapAlignment.spaceBetween, alignment: WrapAlignment.spaceBetween,
crossAxisAlignment: WrapCrossAlignment.start, crossAxisAlignment: WrapCrossAlignment.start,
spacing: 20, spacing: 20,
@ -1171,7 +1170,7 @@ class _TwoRecordsThingy extends StatelessWidget {
if (blitz != null) FinesseThingy(blitz?.endContext.finesse, blitz?.endContext.finessePercentage), if (blitz != null) FinesseThingy(blitz?.endContext.finesse, blitz?.endContext.finessePercentage),
if (blitz != null) LineclearsThingy(blitz!.endContext.clears, blitz!.endContext.lines, blitz!.endContext.holds, blitz!.endContext.tSpins), if (blitz != null) LineclearsThingy(blitz!.endContext.clears, blitz!.endContext.lines, blitz!.endContext.holds, blitz!.endContext.tSpins),
if (blitz != null) Text("${blitz!.endContext.piecesPlaced} P • ${blitz!.endContext.inputs} KP • ${f2.format(blitz!.endContext.kpp)} KPP • ${f2.format(blitz!.endContext.kps)} KPS"), if (blitz != null) Text("${blitz!.endContext.piecesPlaced} P • ${blitz!.endContext.inputs} KP • ${f2.format(blitz!.endContext.kpp)} KPP • ${f2.format(blitz!.endContext.kps)} KPS"),
if (blitz != null) Wrap( Wrap(
alignment: WrapAlignment.spaceBetween, alignment: WrapAlignment.spaceBetween,
crossAxisAlignment: WrapCrossAlignment.start, crossAxisAlignment: WrapCrossAlignment.start,
spacing: 20, spacing: 20,

View File

@ -49,13 +49,14 @@ class RanksAverages extends State<RankAveragesView> {
child: averages.isEmpty ? const Center(child: Text('Fetching...')) : ListView.builder( child: averages.isEmpty ? const Center(child: Text('Fetching...')) : ListView.builder(
itemCount: averages.length, itemCount: averages.length,
itemBuilder: (context, index){ itemBuilder: (context, index){
bool bigScreen = MediaQuery.of(context).size.width > 768;
List<String> keys = averages.keys.toList(); List<String> keys = averages.keys.toList();
return ListTile( return ListTile(
leading: Image.asset("res/tetrio_tl_alpha_ranks/${keys[index]}.png", height: 48), leading: Image.asset("res/tetrio_tl_alpha_ranks/${keys[index]}.png", height: 48),
title: Text(t.players(n: averages[keys[index]]?[1]["players"]), style: const TextStyle(fontFamily: "Eurostile Round Extended")), title: Text(t.players(n: averages[keys[index]]?[1]["players"]), style: const TextStyle(fontFamily: "Eurostile Round Extended")),
subtitle: Text("${f2.format(averages[keys[index]]?[0].apm)} APM, ${f2.format(averages[keys[index]]?[0].pps)} PPS, ${f2.format(averages[keys[index]]?[0].vs)} VS, ${f2.format(averages[keys[index]]?[0].nerdStats.app)} APP, ${f2.format(averages[keys[index]]?[0].nerdStats.vsapm)} VS/APM", subtitle: Text("${f2.format(averages[keys[index]]?[0].apm)} APM, ${f2.format(averages[keys[index]]?[0].pps)} PPS, ${f2.format(averages[keys[index]]?[0].vs)} VS, ${f2.format(averages[keys[index]]?[0].nerdStats.app)} APP, ${f2.format(averages[keys[index]]?[0].nerdStats.vsapm)} VS/APM",
style: const TextStyle(fontFamily: "Eurostile Round Condensed", color: Colors.grey, fontSize: 13)), style: const TextStyle(fontFamily: "Eurostile Round Condensed", color: Colors.grey)),
trailing: Text("${f2.format(averages[keys[index]]?[1]["toEnterTR"])} TR", style: const TextStyle(fontSize: 28, fontFamily: "Eurostile Round")), trailing: Text("${f2.format(averages[keys[index]]?[1]["toEnterTR"])} TR", style: bigScreen ? const TextStyle(fontSize: 28) : null),
onTap: (){ onTap: (){
if (averages[keys[index]]?[1]["players"] > 0) { if (averages[keys[index]]?[1]["players"] > 0) {
Navigator.push( Navigator.push(

View File

@ -288,13 +288,13 @@ class SettingsState extends State<SettingsView> {
subtitle: Text(t.aboutAppText(appName: packageInfo.appName, packageName: packageInfo.packageName, version: packageInfo.version, buildNumber: packageInfo.buildNumber)), subtitle: Text(t.aboutAppText(appName: packageInfo.appName, packageName: packageInfo.packageName, version: packageInfo.version, buildNumber: packageInfo.buildNumber)),
trailing: const Icon(Icons.arrow_right) trailing: const Icon(Icons.arrow_right)
), ),
// Wrap( Wrap(
// alignment: WrapAlignment.center, alignment: WrapAlignment.center,
// spacing: 8, spacing: 8,
// children: [ children: [
// TextButton(child: Text("Donate to me"), onPressed: (){},),TextButton(child: Text("Donate to NOT me"), onPressed: (){},),TextButton(child: Text("Donate to someone else"), onPressed: (){},), TextButton(child: Text("Donate to me"), onPressed: (){},),TextButton(child: Text("Donate to NOT me"), onPressed: (){},),TextButton(child: Text("Donate to someone else"), onPressed: (){},),
// ], ],
// ), ),
], ],
)), )),
); );

View File

@ -58,7 +58,7 @@ class TLLeaderboardState extends State<TLLeaderboardView> {
); );
}, },
icon: const Icon(Icons.compress), icon: const Icon(Icons.compress),
tooltip: t.rankAveragesViewTitle, tooltip: t.averages,
), ),
], ],
), ),
@ -184,12 +184,12 @@ class TLLeaderboardState extends State<TLLeaderboardView> {
style: TextStyle(fontFamily: "Eurostile Round Extended", fontSize: bigScreen ? 28 : 24, height: 0.9) style: TextStyle(fontFamily: "Eurostile Round Extended", fontSize: bigScreen ? 28 : 24, height: 0.9)
), ),
title: Text(allPlayers[index].username, style: TextStyle(fontFamily: bigScreen ? "Eurostile Round Extended" : "Eurostile Round", height: 0.9)), title: Text(allPlayers[index].username, style: TextStyle(fontFamily: bigScreen ? "Eurostile Round Extended" : "Eurostile Round", height: 0.9)),
subtitle: (bigScreen || _sortBy != Stats.tr) ? Text(_sortBy == Stats.tr ? "${f2.format(allPlayers[index].apm)} APM, ${f2.format(allPlayers[index].pps)} PPS, ${f2.format(allPlayers[index].vs)} VS, ${f2.format(allPlayers[index].nerdStats.app)} APP, ${f2.format(allPlayers[index].nerdStats.vsapm)} VS/APM" : "${_f4.format(allPlayers[index].getStatByEnum(_sortBy))} ${chartsShortTitles[_sortBy]}", subtitle: Text(_sortBy == Stats.tr ? "${f2.format(allPlayers[index].apm)} APM, ${f2.format(allPlayers[index].pps)} PPS, ${f2.format(allPlayers[index].vs)} VS, ${f2.format(allPlayers[index].nerdStats.app)} APP, ${f2.format(allPlayers[index].nerdStats.vsapm)} VS/APM" : "${_f4.format(allPlayers[index].getStatByEnum(_sortBy))} ${chartsShortTitles[_sortBy]}",
style: TextStyle(fontFamily: "Eurostile Round Condensed", fontSize: bigScreen ? null : 13, color: _sortBy == Stats.tr ? Colors.grey : null)) : null, style: TextStyle(fontFamily: "Eurostile Round Condensed", fontSize: bigScreen ? null : 12, color: _sortBy == Stats.tr ? Colors.grey : null)),
trailing: Row( trailing: Row(
mainAxisSize: MainAxisSize.min, mainAxisSize: MainAxisSize.min,
children: [ children: [
Text("${f2.format(allPlayers[index].rating)} TR", style: const TextStyle(fontSize: 28)), Text("${f2.format(allPlayers[index].rating)} TR", style: TextStyle(fontSize: bigScreen ? 28 : 22)),
Image.asset("res/tetrio_tl_alpha_ranks/${allPlayers[index].rank}.png", height: bigScreen ? 48 : 36), Image.asset("res/tetrio_tl_alpha_ranks/${allPlayers[index].rank}.png", height: bigScreen ? 48 : 36),
], ],
), ),

View File

@ -269,7 +269,7 @@ class TlMatchResultState extends State<TlMatchResultView> {
label: "Sent", higherIsBetter: true), label: "Sent", higherIsBetter: true),
CompareThingy(greenSide: roundSelector.isNegative ? snapshot.data!.totalStats[greenSidePlayer].garbage.recived : snapshot.data!.stats[roundSelector][greenSidePlayer].garbage.recived, CompareThingy(greenSide: roundSelector.isNegative ? snapshot.data!.totalStats[greenSidePlayer].garbage.recived : snapshot.data!.stats[roundSelector][greenSidePlayer].garbage.recived,
redSide: roundSelector.isNegative ? snapshot.data!.totalStats[redSidePlayer].garbage.recived : snapshot.data!.stats[roundSelector][redSidePlayer].garbage.recived, redSide: roundSelector.isNegative ? snapshot.data!.totalStats[redSidePlayer].garbage.recived : snapshot.data!.stats[roundSelector][redSidePlayer].garbage.recived,
label: "Received", higherIsBetter: true), label: "Recived", higherIsBetter: true),
CompareThingy(greenSide: roundSelector.isNegative ? snapshot.data!.totalStats[greenSidePlayer].garbage.attack : snapshot.data!.stats[roundSelector][greenSidePlayer].garbage.attack, CompareThingy(greenSide: roundSelector.isNegative ? snapshot.data!.totalStats[greenSidePlayer].garbage.attack : snapshot.data!.stats[roundSelector][greenSidePlayer].garbage.attack,
redSide: roundSelector.isNegative ? snapshot.data!.totalStats[redSidePlayer].garbage.attack : snapshot.data!.stats[roundSelector][redSidePlayer].garbage.attack, redSide: roundSelector.isNegative ? snapshot.data!.totalStats[redSidePlayer].garbage.attack : snapshot.data!.stats[roundSelector][redSidePlayer].garbage.attack,
label: "Attack", higherIsBetter: true), label: "Attack", higherIsBetter: true),

View File

@ -126,7 +126,7 @@ class SingleplayerRecord extends StatelessWidget {
LineclearsThingy(record!.endContext.clears, record!.endContext.lines, record!.endContext.holds, record!.endContext.tSpins), LineclearsThingy(record!.endContext.clears, record!.endContext.lines, record!.endContext.holds, record!.endContext.tSpins),
if (record!.endContext.gameType == "40l") Text("${record!.endContext.inputs} KP • ${f2.format(record!.endContext.kps)} KPS"), if (record!.endContext.gameType == "40l") Text("${record!.endContext.inputs} KP • ${f2.format(record!.endContext.kps)} KPS"),
if (record!.endContext.gameType == "blitz") Text("${record!.endContext.piecesPlaced} P • ${record!.endContext.inputs} KP • ${f2.format(record!.endContext.kpp)} KPP • ${f2.format(record!.endContext.kps)} KPS"), if (record!.endContext.gameType == "blitz") Text("${record!.endContext.piecesPlaced} P • ${record!.endContext.inputs} KP • ${f2.format(record!.endContext.kpp)} KPP • ${f2.format(record!.endContext.kps)} KPS"),
if (record != null) Wrap( Wrap(
alignment: WrapAlignment.spaceBetween, alignment: WrapAlignment.spaceBetween,
crossAxisAlignment: WrapCrossAlignment.start, crossAxisAlignment: WrapCrossAlignment.start,
spacing: 20, spacing: 20,

View File

@ -1,5 +1,3 @@
import 'dart:math';
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.dart';
@ -8,16 +6,14 @@ import 'package:tetra_stats/main.dart' show prefs;
import 'package:tetra_stats/utils/numers_formats.dart'; import 'package:tetra_stats/utils/numers_formats.dart';
var fDiff = NumberFormat("+#,###.####;-#,###.####"); var fDiff = NumberFormat("+#,###.####;-#,###.####");
DateTime seasonEnd = DateTime.utc(2024, 07, 26);
class TLRatingThingy extends StatelessWidget{ class TLRatingThingy extends StatelessWidget{
final String userID; final String userID;
final TetraLeagueAlpha tlData; final TetraLeagueAlpha tlData;
final TetraLeagueAlpha? oldTl; final TetraLeagueAlpha? oldTl;
final double? topTR; final double? topTR;
final DateTime? lastMatchPlayed;
const TLRatingThingy({super.key, required this.userID, required this.tlData, this.oldTl, this.topTR, this.lastMatchPlayed}); const TLRatingThingy({super.key, required this.userID, required this.tlData, this.oldTl, this.topTR});
@override @override
Widget build(BuildContext context) { Widget build(BuildContext context) {
@ -27,11 +23,6 @@ class TLRatingThingy extends StatelessWidget{
List<String> formatedTR = f4.format(tlData.rating).split(decimalSeparator); List<String> formatedTR = f4.format(tlData.rating).split(decimalSeparator);
List<String> formatedGlicko = f4.format(tlData.glicko).split(decimalSeparator); List<String> formatedGlicko = f4.format(tlData.glicko).split(decimalSeparator);
List<String> formatedPercentile = f4.format(tlData.percentile * 100).split(decimalSeparator); List<String> formatedPercentile = f4.format(tlData.percentile * 100).split(decimalSeparator);
DateTime now = DateTime.now();
bool beforeS1end = now.isBefore(seasonEnd);
int daysLeft = seasonEnd.difference(now).inDays;
print(max(0, 7 - (lastMatchPlayed != null ? now.difference(lastMatchPlayed!).inDays : 7)));
int safeRD = min(100, (100 + ((tlData.rd! >= 100 && tlData.decaying) ? 7 : max(0, 7 - (lastMatchPlayed != null ? now.difference(lastMatchPlayed!).inDays : 7))) - daysLeft).toInt());
return Wrap( return Wrap(
direction: Axis.horizontal, direction: Axis.horizontal,
alignment: WrapAlignment.spaceAround, alignment: WrapAlignment.spaceAround,
@ -92,8 +83,7 @@ class TLRatingThingy extends StatelessWidget{
if (topTR != null) TextSpan(text: " (${f2.format(topTR)} TR)"), if (topTR != null) TextSpan(text: " (${f2.format(topTR)} TR)"),
TextSpan(text: "${prefs.getInt("ratingMode") == 1 ? "${f2.format(tlData.rating)} TR • RD: " : "Glicko: ${f2.format(tlData.glicko!)}±"}"), TextSpan(text: "${prefs.getInt("ratingMode") == 1 ? "${f2.format(tlData.rating)} TR • RD: " : "Glicko: ${f2.format(tlData.glicko!)}±"}"),
TextSpan(text: f2.format(tlData.rd!), style: tlData.decaying ? TextStyle(color: tlData.rd! > 98 ? Colors.red : Colors.yellow) : null), TextSpan(text: f2.format(tlData.rd!), style: tlData.decaying ? TextStyle(color: tlData.rd! > 98 ? Colors.red : Colors.yellow) : null),
if (tlData.decaying) WidgetSpan(child: Icon(Icons.trending_up, color: tlData.rd! > 98 ? Colors.red : Colors.yellow,), alignment: PlaceholderAlignment.middle, baseline: TextBaseline.alphabetic), if (tlData.decaying) WidgetSpan(child: Icon(Icons.trending_up, color: tlData.rd! > 98 ? Colors.red : Colors.yellow,), alignment: PlaceholderAlignment.middle, baseline: TextBaseline.alphabetic)
if (beforeS1end) tlData.rd! <= safeRD ? TextSpan(text: " (Safe)", style: TextStyle(color: Colors.greenAccent)) : TextSpan(text: " (> ${safeRD} RD !!!)", style: TextStyle(color: Colors.redAccent))
], ],
), ),
), ),

View File

@ -31,8 +31,7 @@ class TLThingy extends StatefulWidget {
final double? nextRankCutoff; final double? nextRankCutoff;
final double? nextRankCutoffGlicko; final double? nextRankCutoffGlicko;
final double? nextRankTarget; final double? nextRankTarget;
final DateTime? lastMatchPlayed; const TLThingy({super.key, required this.tl, required this.userID, required this.states, this.showTitle = true, this.bot=false, this.guest=false, this.topTR, this.lbPositions, this.averages, this.nextRankCutoff, this.thatRankCutoff, this.thatRankCutoffGlicko, this.nextRankCutoffGlicko, this.nextRankTarget, this.thatRankTarget});
const TLThingy({super.key, required this.tl, required this.userID, required this.states, this.showTitle = true, this.bot=false, this.guest=false, this.topTR, this.lbPositions, this.averages, this.nextRankCutoff, this.thatRankCutoff, this.thatRankCutoffGlicko, this.nextRankCutoffGlicko, this.nextRankTarget, this.thatRankTarget, this.lastMatchPlayed});
@override @override
State<TLThingy> createState() => _TLThingyState(); State<TLThingy> createState() => _TLThingyState();
@ -93,7 +92,7 @@ class _TLThingyState extends State<TLThingy> {
}); });
}, },
), ),
if (currentTl.gamesPlayed > 9) TLRatingThingy(userID: widget.userID, tlData: currentTl, oldTl: oldTl, topTR: widget.topTR, lastMatchPlayed: widget.lastMatchPlayed), if (currentTl.gamesPlayed >= 10) TLRatingThingy(userID: widget.userID, tlData: currentTl, oldTl: oldTl, topTR: widget.topTR),
if (currentTl.gamesPlayed > 9) TLProgress( if (currentTl.gamesPlayed > 9) TLProgress(
tlData: currentTl, tlData: currentTl,
previousRankTRcutoff: widget.thatRankCutoff, previousRankTRcutoff: widget.thatRankCutoff,

View File

@ -2,7 +2,7 @@ name: tetra_stats
description: Track your and other player stats in TETR.IO description: Track your and other player stats in TETR.IO
publish_to: 'none' publish_to: 'none'
version: 1.6.1+21 version: 1.6.0+20
environment: environment:
sdk: '>=3.0.0' sdk: '>=3.0.0'

View File

@ -186,7 +186,7 @@
"fromBeginning": "From beginning", "fromBeginning": "From beginning",
"calc": "Calc", "calc": "Calc",
"calcViewNoValues": "Enter values to calculate the stats", "calcViewNoValues": "Enter values to calculate the stats",
"rankAveragesViewTitle": "Ranks cutoffs", "rankAveragesViewTitle": "Ranks cutoff and average stats",
"sprintAndBlitsViewTitle": "40 lines and Blitz averages", "sprintAndBlitsViewTitle": "40 lines and Blitz averages",
"sprintAndBlitsRelevance": "Relevance: ${date}", "sprintAndBlitsRelevance": "Relevance: ${date}",
"rank": "Rank", "rank": "Rank",

View File

@ -186,7 +186,7 @@
"fromBeginning": "С начала", "fromBeginning": "С начала",
"calc": "Считать", "calc": "Считать",
"calcViewNoValues": "Введите значения, чтобы посчитать статистику", "calcViewNoValues": "Введите значения, чтобы посчитать статистику",
"rankAveragesViewTitle": "Требования рангов", "rankAveragesViewTitle": "Требования рангов и средние значения",
"sprintAndBlitsViewTitle": "Средние результаты 40 линий и блица", "sprintAndBlitsViewTitle": "Средние результаты 40 линий и блица",
"sprintAndBlitsRelevance": "Актуальность: ${date}", "sprintAndBlitsRelevance": "Актуальность: ${date}",
"rank": "Ранг", "rank": "Ранг",

View File

@ -150,7 +150,7 @@
let tip = document.querySelector("#tip"); let tip = document.querySelector("#tip");
const tips = [ const tips = [
// Promoting Tetra Stats "native" // Promoting Tetra Stats "native"
"Want a better perfomance?<br><a href=\"https://github.com/dan63047/TetraStats/releases\">Try out Tetra Stats \"Native\"</a>", "Want a better perfomance?<br><a href=\"ya.ru\">Try out Tetra Stats Native</a>",
"Imagine a world, where Tetra Stats was written in JS", "Imagine a world, where Tetra Stats was written in JS",
"Welcome to fullscreen canvas", "Welcome to fullscreen canvas",
@ -172,7 +172,6 @@
let appRunner = await engineInitializer.initializeEngine(); let appRunner = await engineInitializer.initializeEngine();
await appRunner.runApp(); await appRunner.runApp();
preloader.classList.add("hidden"); preloader.classList.add("hidden");
tip.classList.add("hidden");
} }
}); });
} catch (e){ } catch (e){