Fetching old Tetra League matches

Also changed behavior of main view fetch function
This commit is contained in:
dan63047 2024-02-03 16:02:58 +03:00
parent 769a53bd69
commit 07929ca6f7
8 changed files with 218 additions and 75 deletions

View File

@ -830,7 +830,14 @@ class EndContextMulti {
required this.tertiaryTracking, required this.tertiaryTracking,
required this.extra, required this.extra,
required this.extraTracking, required this.extraTracking,
required this.success}); 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) { EndContextMulti.fromJson(Map<String, dynamic> json) {
userId = json['id'] ?? json['user']['_id']; userId = json['id'] ?? json['user']['_id'];

View File

@ -4,9 +4,9 @@
/// To regenerate, run: `dart run slang` /// To regenerate, run: `dart run slang`
/// ///
/// Locales: 2 /// Locales: 2
/// Strings: 1008 (504 per locale) /// Strings: 1016 (508 per locale)
/// ///
/// Built on 2024-01-22 at 19:27 UTC /// Built on 2024-02-03 at 12:49 UTC
// coverage:ignore-file // coverage:ignore-file
// ignore_for_file: type=lint // ignore_for_file: type=lint
@ -167,6 +167,9 @@ class Translations implements BaseTranslations<AppLocale, Translations> {
String get closeSearch => 'Close search'; String get closeSearch => 'Close search';
String get refresh => 'Refresh'; String get refresh => 'Refresh';
String get fetchAndsaveTLHistory => 'Get player history'; String get fetchAndsaveTLHistory => 'Get player history';
String get fetchAndSaveOldTLmatches => 'Get Tetra League matches history';
String fetchAndsaveTLHistoryResult({required Object number}) => '${number} states was found';
String fetchAndSaveOldTLmatchesResult({required Object number}) => '${number} matches was found';
String get showStoredData => 'Show stored data'; String get showStoredData => 'Show stored data';
String get statsCalc => 'Stats Calculator'; String get statsCalc => 'Stats Calculator';
String get settings => 'Settings'; String get settings => 'Settings';
@ -697,6 +700,7 @@ class _StringsErrorsEn {
String connection({required Object code, required Object message}) => 'Some issue with connection: ${code} ${message}'; String connection({required Object code, required Object message}) => 'Some issue with connection: ${code} ${message}';
String get noSuchUser => 'No such user'; String get noSuchUser => 'No such user';
String get history => 'History for that player is missing'; String get history => 'History for that player is missing';
String get p1nkl0bst3rTLmatches => 'No Tetra League matches was found';
String get clientException => 'No internet connection'; String get clientException => 'No internet connection';
String get forbidden => 'Your IP address is blocked.\nChange IP address or reach out to osk'; String get forbidden => 'Your IP address is blocked.\nChange IP address or reach out to osk';
String get tooManyRequests => 'You have been rate limited. Try again later'; String get tooManyRequests => 'You have been rate limited. Try again later';
@ -755,6 +759,9 @@ class _StringsRu implements Translations {
@override String get closeSearch => 'Закрыть поиск'; @override String get closeSearch => 'Закрыть поиск';
@override String get refresh => 'Обновить'; @override String get refresh => 'Обновить';
@override String get fetchAndsaveTLHistory => 'Получить историю игрока'; @override String get fetchAndsaveTLHistory => 'Получить историю игрока';
@override String get fetchAndSaveOldTLmatches => 'Получить старые матчи Тетра Лиги';
@override String fetchAndsaveTLHistoryResult({required Object number}) => '${number} состояний было найдено';
@override String fetchAndSaveOldTLmatchesResult({required Object number}) => '${number} старых матчей было найдено';
@override String get showStoredData => 'Показать сохранённые данные'; @override String get showStoredData => 'Показать сохранённые данные';
@override String get statsCalc => 'Калькулятор статистики'; @override String get statsCalc => 'Калькулятор статистики';
@override String get settings => 'Настройки'; @override String get settings => 'Настройки';
@ -1285,6 +1292,7 @@ class _StringsErrorsRu implements _StringsErrorsEn {
@override String connection({required Object code, required Object message}) => 'Проблема с подключением: ${code} ${message}'; @override String connection({required Object code, required Object message}) => 'Проблема с подключением: ${code} ${message}';
@override String get noSuchUser => 'Нет такого пользователя'; @override String get noSuchUser => 'Нет такого пользователя';
@override String get history => 'История данного игрока отсутствует'; @override String get history => 'История данного игрока отсутствует';
@override String get p1nkl0bst3rTLmatches => 'Старых матчей Тетра Лиги не было найдено';
@override String get clientException => 'Нет соединения с интернетом'; @override String get clientException => 'Нет соединения с интернетом';
@override String get forbidden => 'Ваш IP адрес заблокирован.\nСмените IP адрес или свяжитесь с osk-ом'; @override String get forbidden => 'Ваш IP адрес заблокирован.\nСмените IP адрес или свяжитесь с osk-ом';
@override String get tooManyRequests => 'Слишком много запросов. Попробуйте позже'; @override String get tooManyRequests => 'Слишком много запросов. Попробуйте позже';
@ -1335,6 +1343,9 @@ extension on Translations {
case 'closeSearch': return 'Close search'; case 'closeSearch': return 'Close search';
case 'refresh': return 'Refresh'; case 'refresh': return 'Refresh';
case 'fetchAndsaveTLHistory': return 'Get player history'; case 'fetchAndsaveTLHistory': return 'Get player history';
case 'fetchAndSaveOldTLmatches': return 'Get Tetra League matches history';
case 'fetchAndsaveTLHistoryResult': return ({required Object number}) => '${number} states was found';
case 'fetchAndSaveOldTLmatchesResult': return ({required Object number}) => '${number} matches was found';
case 'showStoredData': return 'Show stored data'; case 'showStoredData': return 'Show stored data';
case 'statsCalc': return 'Stats Calculator'; case 'statsCalc': return 'Stats Calculator';
case 'settings': return 'Settings'; case 'settings': return 'Settings';
@ -1540,6 +1551,7 @@ extension on Translations {
case 'errors.connection': return ({required Object code, required Object message}) => 'Some issue with connection: ${code} ${message}'; case 'errors.connection': return ({required Object code, required Object message}) => 'Some issue with connection: ${code} ${message}';
case 'errors.noSuchUser': return 'No such user'; case 'errors.noSuchUser': return 'No such user';
case 'errors.history': return 'History for that player is missing'; case 'errors.history': return 'History for that player is missing';
case 'errors.p1nkl0bst3rTLmatches': return 'No Tetra League matches was found';
case 'errors.clientException': return 'No internet connection'; case 'errors.clientException': return 'No internet connection';
case 'errors.forbidden': return 'Your IP address is blocked.\nChange IP address or reach out to osk'; case 'errors.forbidden': return 'Your IP address is blocked.\nChange IP address or reach out to osk';
case 'errors.tooManyRequests': return 'You have been rate limited. Try again later'; case 'errors.tooManyRequests': return 'You have been rate limited. Try again later';
@ -1849,6 +1861,9 @@ extension on _StringsRu {
case 'closeSearch': return 'Закрыть поиск'; case 'closeSearch': return 'Закрыть поиск';
case 'refresh': return 'Обновить'; case 'refresh': return 'Обновить';
case 'fetchAndsaveTLHistory': return 'Получить историю игрока'; case 'fetchAndsaveTLHistory': return 'Получить историю игрока';
case 'fetchAndSaveOldTLmatches': return 'Получить старые матчи Тетра Лиги';
case 'fetchAndsaveTLHistoryResult': return ({required Object number}) => '${number} состояний было найдено';
case 'fetchAndSaveOldTLmatchesResult': return ({required Object number}) => '${number} старых матчей было найдено';
case 'showStoredData': return 'Показать сохранённые данные'; case 'showStoredData': return 'Показать сохранённые данные';
case 'statsCalc': return 'Калькулятор статистики'; case 'statsCalc': return 'Калькулятор статистики';
case 'settings': return 'Настройки'; case 'settings': return 'Настройки';
@ -2054,6 +2069,7 @@ extension on _StringsRu {
case 'errors.connection': return ({required Object code, required Object message}) => 'Проблема с подключением: ${code} ${message}'; case 'errors.connection': return ({required Object code, required Object message}) => 'Проблема с подключением: ${code} ${message}';
case 'errors.noSuchUser': return 'Нет такого пользователя'; case 'errors.noSuchUser': return 'Нет такого пользователя';
case 'errors.history': return 'История данного игрока отсутствует'; case 'errors.history': return 'История данного игрока отсутствует';
case 'errors.p1nkl0bst3rTLmatches': return 'Старых матчей Тетра Лиги не было найдено';
case 'errors.clientException': return 'Нет соединения с интернетом'; case 'errors.clientException': return 'Нет соединения с интернетом';
case 'errors.forbidden': return 'Ваш IP адрес заблокирован.\nСмените IP адрес или свяжитесь с osk-ом'; case 'errors.forbidden': return 'Ваш IP адрес заблокирован.\nСмените IP адрес или свяжитесь с osk-ом';
case 'errors.tooManyRequests': return 'Слишком много запросов. Попробуйте позже'; case 'errors.tooManyRequests': return 'Слишком много запросов. Попробуйте позже';

View File

@ -393,6 +393,100 @@ class TetrioService extends DB {
} }
} }
/// Docs later
Future<List<TetraLeagueAlphaRecord>> fetchAndSaveOldTLmatches(String userID) async {
Uri url;
if (kIsWeb) {
url = Uri.https('ts.dan63.by', 'oskware_bridge.php', {"endpoint": "TLMatches", "user": userID});
} else {
url = Uri.https('api.p1nkl0bst3r.xyz', 'tlmatches/$userID');
}
try{
final response = await client.get(url);
switch (response.statusCode) {
case 200:
// that one api returns csv instead of json
List<List<dynamic>> csv = const CsvToListConverter().convert(response.body)..removeAt(0);
List<TetraLeagueAlphaRecord> matches = [];
// parsing data into TetraLeagueAlphaRecord objects
for (var entry in csv){
TetraLeagueAlphaRecord match = TetraLeagueAlphaRecord(
replayId: entry[0],
ownId: entry[0], // i gonna disting p1nkl0bst3r entries with it
timestamp: DateTime.parse(entry[1]),
endContext: [
EndContextMulti(
userId: entry[2],
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],
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:
developer.log("fetchAndSaveOldTLmatches: Probably, history doesn't exist", name: "services/tetrio_crud", error: response.statusCode);
throw TetrioHistoryNotExist();
case 403:
throw P1nkl0bst3rForbidden();
case 429:
throw P1nkl0bst3rTooManyRequests();
case 418:
throw TetrioOskwareBridgeProblem();
case 500:
case 502:
case 503:
case 504:
throw P1nkl0bst3rInternalProblem();
default:
developer.log("fetchAndSaveOldTLmatches: Failed to fetch history", name: "services/tetrio_crud", error: response.statusCode);
throw ConnectionIssue(response.statusCode, response.reasonPhrase??"No reason");
}
} on http.ClientException catch (e, s) {
developer.log("$e, $s");
throw http.ClientException(e.message, e.uri);
}
}
/// Retrieves full Tetra League leaderboard from Tetra Channel api. Returns a leaderboard object. Throws an exception if fails to retrieve. /// Retrieves full Tetra League leaderboard from Tetra Channel api. Returns a leaderboard object. Throws an exception if fails to retrieve.
Future<TetrioPlayersLeaderboard> fetchTLLeaderboard() async { Future<TetrioPlayersLeaderboard> fetchTLLeaderboard() async {
try{ try{

View File

@ -1,5 +1,3 @@
// ignore_for_file: use_build_context_synchronously
import 'dart:io'; import 'dart:io';
import 'dart:math'; import 'dart:math';
import 'package:flutter/foundation.dart'; import 'package:flutter/foundation.dart';
@ -70,8 +68,7 @@ class CompareState extends State<CompareView> {
theRedSide = [null, null, average]; theRedSide = [null, null, average];
return setState(() {}); return setState(() {});
}on Exception { }on Exception {
ScaffoldMessenger.of(context) if (context.mounted) ScaffoldMessenger.of(context).showSnackBar(SnackBar(content: Text(t.compareViewWrongValue(value: user))));
.showSnackBar(SnackBar(content: Text(t.compareViewWrongValue(value: user))));
return; return;
} }
} }
@ -126,8 +123,7 @@ class CompareState extends State<CompareView> {
} }
theRedSide = [player, dStates, player.tlSeason1]; theRedSide = [player, dStates, player.tlSeason1];
} on Exception { } on Exception {
ScaffoldMessenger.of(context) if (context.mounted) ScaffoldMessenger.of(context).showSnackBar(SnackBar(content: Text(t.compareViewWrongValue(value: user))));
.showSnackBar(SnackBar(content: Text(t.compareViewWrongValue(value: user))));
} }
_justUpdate(); _justUpdate();
} }
@ -146,8 +142,7 @@ class CompareState extends State<CompareView> {
theGreenSide = [null, null, average]; theGreenSide = [null, null, average];
return setState(() {}); return setState(() {});
}on Exception { }on Exception {
ScaffoldMessenger.of(context) if (context.mounted) ScaffoldMessenger.of(context).showSnackBar(SnackBar(content: Text("Falied to assign $user")));
.showSnackBar(SnackBar(content: Text("Falied to assign $user")));
return; return;
} }
} }
@ -202,8 +197,7 @@ class CompareState extends State<CompareView> {
} }
theGreenSide = [player, dStates, player.tlSeason1]; theGreenSide = [player, dStates, player.tlSeason1];
} on Exception { } on Exception {
ScaffoldMessenger.of(context) if (context.mounted) ScaffoldMessenger.of(context).showSnackBar(SnackBar(content: Text("Falied to assign $user")));
.showSnackBar(SnackBar(content: Text("Falied to assign $user")));
} }
_justUpdate(); _justUpdate();
} }
@ -213,19 +207,16 @@ class CompareState extends State<CompareView> {
theGreenSide[2] = user.tlSeason1;}); theGreenSide[2] = user.tlSeason1;});
} }
double getWinrateByTR(double yourGlicko, double yourRD, double notyourGlicko, double getWinrateByTR(double yourGlicko, double yourRD, double notyourGlicko,double notyourRD) {
double notyourRD) {
return ((1 / return ((1 /
(1 + (1 + pow(10,
pow( (notyourGlicko - yourGlicko) /
10, (400 * sqrt(1 + (3 * pow(0.0057564273, 2) *
(notyourGlicko - yourGlicko) / (pow(yourRD, 2) + pow(notyourRD, 2)) / pow(pi, 2)
(400 * )))
sqrt(1 + )
(3 * )
pow(0.0057564273, 2) * ));
(pow(yourRD, 2) + pow(notyourRD, 2)) /
pow(pi, 2))))))));
} }
void _justUpdate() { void _justUpdate() {

View File

@ -116,10 +116,10 @@ class _MainState extends State<MainView> with TickerProviderStateMixin {
/// That function initiate search of data about [player]. If [fetchHistory] is true, /// That function initiate search of data about [player]. If [fetchHistory] is true,
/// also attempting to retrieve players history. Can trow an Exception if fails /// also attempting to retrieve players history. Can trow an Exception if fails
void changePlayer(String player, {bool fetchHistory = false}) { void changePlayer(String player, {bool fetchHistory = false, bool fetchTLmatches = false}) {
setState(() { setState(() {
_searchFor = player; _searchFor = player;
me = fetch(_searchFor, fetchHistory: fetchHistory); me = fetch(_searchFor, fetchHistory: fetchHistory, fetchTLmatches: fetchTLmatches);
}); });
} }
@ -128,13 +128,14 @@ class _MainState extends State<MainView> with TickerProviderStateMixin {
} }
/// Retrieves data from 3 different Tetra Channel API endpoints + 1 endpoint from p1nkl0bst3r's API /// Retrieves data from 3 different Tetra Channel API endpoints + 1 endpoint from p1nkl0bst3r's API
/// using [nickOrID] of player. If [fetchHistory] is true, also retrieves players history from p1nkl0bst3r's API. /// using [nickOrID] of player.
/// ///
/// Returns list which contains players object, his TL records, previous states, TL matches, previos TL state, if player tracked (bool), news entries and topTR. /// If [fetchHistory] is true, also retrieves players history from p1nkl0bst3r's API. If [fetchTLmatches] is true, also retrieves players old Tetra League
/// matches from p1nkl0bst3r's API. Returns list which contains [TetrioPlayer], his records, previous states, TL matches, previous TL state,
/// if player tracked (bool), news entries and topTR.
/// ///
/// If at least one request to some endpoint fails, whole function will throw an exception. /// If at least one request to Tetra Channel API fails, whole function will throw an exception.
/// TODO: Change this behavior Future<List> fetch(String nickOrID, {bool fetchHistory = false, bool fetchTLmatches = false}) async {
Future<List> fetch(String nickOrID, {bool fetchHistory = false}) async {
TetrioPlayer me; TetrioPlayer me;
// If user trying to search with discord id // If user trying to search with discord id
@ -173,13 +174,28 @@ class _MainState extends State<MainView> with TickerProviderStateMixin {
TetraLeagueAlpha? compareWith; TetraLeagueAlpha? compareWith;
Set<TetraLeagueAlpha> uniqueTL = {}; Set<TetraLeagueAlpha> uniqueTL = {};
tlMatches = tlStream.records; tlMatches = tlStream.records;
var storedRecords = await teto.getTLMatchesbyPlayerID(me.userId); // get old matches List<TetraLeagueAlphaRecord> storedRecords = await teto.getTLMatchesbyPlayerID(me.userId); // get old matches
if (isTracking){ // if tracked - save data to local DB if (isTracking){ // if tracked - save data to local DB
await teto.storeState(me); await teto.storeState(me);
await teto.saveTLMatchesFromStream(tlStream); await teto.saveTLMatchesFromStream(tlStream);
} }
// building list of TL matches // building list of TL matches
if(fetchTLmatches) {
try{
List<TetraLeagueAlphaRecord> oldMatches = await teto.fetchAndSaveOldTLmatches(_searchFor);
storedRecords.addAll(oldMatches);
if (context.mounted) ScaffoldMessenger.of(context).showSnackBar(SnackBar(content: Text(t.fetchAndSaveOldTLmatchesResult(number: oldMatches.length))));
}on TetrioHistoryNotExist{
if (context.mounted) ScaffoldMessenger.of(context).showSnackBar(SnackBar(content: Text(t.errors.p1nkl0bst3rTLmatches)));
}on P1nkl0bst3rForbidden {
if (context.mounted) ScaffoldMessenger.of(context).showSnackBar(SnackBar(content: Text(t.errors.p1nkl0bst3rForbidden)));
}on P1nkl0bst3rInternalProblem {
if (context.mounted) ScaffoldMessenger.of(context).showSnackBar(SnackBar(content: Text(t.errors.p1nkl0bst3rinternal)));
}on P1nkl0bst3rTooManyRequests{
if (context.mounted) ScaffoldMessenger.of(context).showSnackBar(SnackBar(content: Text(t.errors.p1nkl0bst3rTooManyRequests)));
}
}
for (var match in storedRecords) { for (var match in storedRecords) {
// add stored match to list only if it missing from retrived ones // add stored match to list only if it missing from retrived ones
if (!tlMatches.contains(match)) tlMatches.add(match); if (!tlMatches.contains(match)) tlMatches.add(match);
@ -192,7 +208,21 @@ class _MainState extends State<MainView> with TickerProviderStateMixin {
}); });
// Handling history // Handling history
if(fetchHistory) await teto.fetchAndsaveTLHistory(_searchFor); // Retrieve if needed if(fetchHistory){
try{
var history = await teto.fetchAndsaveTLHistory(_searchFor); // Retrieve if needed
if (context.mounted) ScaffoldMessenger.of(context).showSnackBar(SnackBar(content: Text(t.fetchAndsaveTLHistoryResult(number: history.length))));
}on TetrioHistoryNotExist{
if (context.mounted) ScaffoldMessenger.of(context).showSnackBar(SnackBar(content: Text(t.noHistorySaved)));
}on P1nkl0bst3rForbidden {
if (context.mounted) ScaffoldMessenger.of(context).showSnackBar(SnackBar(content: Text(t.errors.p1nkl0bst3rForbidden)));
}on P1nkl0bst3rInternalProblem {
if (context.mounted) ScaffoldMessenger.of(context).showSnackBar(SnackBar(content: Text(t.errors.p1nkl0bst3rinternal)));
}on P1nkl0bst3rTooManyRequests{
if (context.mounted) ScaffoldMessenger.of(context).showSnackBar(SnackBar(content: Text(t.errors.p1nkl0bst3rTooManyRequests)));
}
}
states.addAll(await teto.getPlayer(me.userId)); states.addAll(await teto.getPlayer(me.userId));
for (var element in states) { // For graphs I need only unique entries for (var element in states) { // For graphs I need only unique entries
if (uniqueTL.isNotEmpty && uniqueTL.last != element.tlSeason1) uniqueTL.add(element.tlSeason1); if (uniqueTL.isNotEmpty && uniqueTL.last != element.tlSeason1) uniqueTL.add(element.tlSeason1);
@ -271,6 +301,10 @@ class _MainState extends State<MainView> with TickerProviderStateMixin {
value: "history", value: "history",
child: Text(t.fetchAndsaveTLHistory), child: Text(t.fetchAndsaveTLHistory),
), ),
PopupMenuItem(
value: "TLmatches",
child: Text(t.fetchAndSaveOldTLmatches),
),
PopupMenuItem( PopupMenuItem(
value: "/states", value: "/states",
child: Text(t.showStoredData), child: Text(t.showStoredData),
@ -292,6 +326,9 @@ class _MainState extends State<MainView> with TickerProviderStateMixin {
case "history": case "history":
changePlayer(_searchFor, fetchHistory: true); changePlayer(_searchFor, fetchHistory: true);
break; break;
case "TLmatches":
changePlayer(_searchFor, fetchTLmatches: true);
break;
default: default:
context.go(value); context.go(value);
} }
@ -373,15 +410,6 @@ class _MainState extends State<MainView> with TickerProviderStateMixin {
var err = snapshot.error as ConnectionIssue; var err = snapshot.error as ConnectionIssue;
errText = t.errors.connection(code: err.code, message: err.message); errText = t.errors.connection(code: err.code, message: err.message);
break; break;
case P1nkl0bst3rForbidden:
errText = t.errors.p1nkl0bst3rForbidden;
break;
case P1nkl0bst3rTooManyRequests:
errText = t.errors.p1nkl0bst3rTooManyRequests;
break;
case P1nkl0bst3rInternalProblem:
errText = kIsWeb ? t.errors.p1nkl0bst3rinternalWebVersion : t.errors.p1nkl0bst3rinternal;
break;
case TetrioHistoryNotExist: case TetrioHistoryNotExist:
errText = t.errors.history; errText = t.errors.history;
break; break;
@ -548,37 +576,33 @@ class _TLRecords extends StatelessWidget {
@override @override
Widget build(BuildContext context) { Widget build(BuildContext context) {
bool bigScreen = MediaQuery.of(context).size.width > 768; bool bigScreen = MediaQuery.of(context).size.width > 768;
return ListView( // TODO: Redo using ListView.builder() if (data.isEmpty) return Center(child: Text(t.noRecords, style: const TextStyle(fontFamily: "Eurostile Round", fontSize: 28)));
physics: const AlwaysScrollableScrollPhysics(), return ListView.builder(
children: (data.isNotEmpty) physics: const AlwaysScrollableScrollPhysics(),
? [for (var value in data) ListTile( itemCount: data.length,
leading: Text("${value.endContext.firstWhere((element) => element.userId == userID).points} : ${value.endContext.firstWhere((element) => element.userId != userID).points}", itemBuilder: (BuildContext context, int index) {
style: bigScreen ? const TextStyle(fontFamily: "Eurostile Round Extended", fontSize: 28) : return ListTile(
const TextStyle(fontSize: 28)), leading: Text("${data[index].endContext.firstWhere((element) => element.userId == userID).points} : ${data[index].endContext.firstWhere((element) => element.userId != userID).points}",
title: Text("vs. ${value.endContext.firstWhere((element) => element.userId != userID).username}"), style: bigScreen ? const TextStyle(fontFamily: "Eurostile Round Extended", fontSize: 28) :
subtitle: Text(_dateFormat.format(value.timestamp)), const TextStyle(fontSize: 28)),
trailing: Table(defaultColumnWidth: const IntrinsicColumnWidth(), title: Text("vs. ${data[index].endContext.firstWhere((element) => element.userId != userID).username}"),
defaultVerticalAlignment: TableCellVerticalAlignment.baseline, subtitle: Text(_dateFormat.format(data[index].timestamp)),
textBaseline: TextBaseline.alphabetic, trailing: Table(defaultColumnWidth: const IntrinsicColumnWidth(),
columnWidths: const { defaultVerticalAlignment: TableCellVerticalAlignment.baseline,
0: FixedColumnWidth(50), textBaseline: TextBaseline.alphabetic,
2: FixedColumnWidth(50), columnWidths: const {
}, 0: FixedColumnWidth(50),
children: [ 2: FixedColumnWidth(50),
TableRow(children: [Text(_f2.format(value.endContext.firstWhere((element) => element.userId == userID).secondary), textAlign: TextAlign.right, style: const TextStyle(height: 1.1)), const Text(" :", style: TextStyle(height: 1.1)), Text(_f2.format(value.endContext.firstWhere((element) => element.userId != userID).secondary), textAlign: TextAlign.right, style: const TextStyle(height: 1.1)), const Text(" APM", textAlign: TextAlign.right, style: TextStyle(height: 1.1))]), },
TableRow(children: [Text(_f2.format(value.endContext.firstWhere((element) => element.userId == userID).tertiary), textAlign: TextAlign.right, style: const TextStyle(height: 1.1)), const Text(" :", style: TextStyle(height: 1.1)), Text(_f2.format(value.endContext.firstWhere((element) => element.userId != userID).tertiary), textAlign: TextAlign.right, style: const TextStyle(height: 1.1)), const Text(" PPS", textAlign: TextAlign.right, style: TextStyle(height: 1.1))]), children: [
TableRow(children: [Text(_f2.format(value.endContext.firstWhere((element) => element.userId == userID).extra), textAlign: TextAlign.right, style: const TextStyle(height: 1.1)), const Text(" :", style: TextStyle(height: 1.1)), Text(_f2.format(value.endContext.firstWhere((element) => element.userId != userID).extra), textAlign: TextAlign.right, style: const TextStyle(height: 1.1)), const Text(" VS", textAlign: TextAlign.right, style: TextStyle(height: 1.1))]), TableRow(children: [Text(_f2.format(data[index].endContext.firstWhere((element) => element.userId == userID).secondary), textAlign: TextAlign.right, style: const TextStyle(height: 1.1)), const Text(" :", style: TextStyle(height: 1.1)), Text(_f2.format(data[index].endContext.firstWhere((element) => element.userId != userID).secondary), textAlign: TextAlign.right, style: const TextStyle(height: 1.1)), const Text(" APM", textAlign: TextAlign.right, style: TextStyle(height: 1.1))]),
],), TableRow(children: [Text(_f2.format(data[index].endContext.firstWhere((element) => element.userId == userID).tertiary), textAlign: TextAlign.right, style: const TextStyle(height: 1.1)), const Text(" :", style: TextStyle(height: 1.1)), Text(_f2.format(data[index].endContext.firstWhere((element) => element.userId != userID).tertiary), textAlign: TextAlign.right, style: const TextStyle(height: 1.1)), const Text(" PPS", textAlign: TextAlign.right, style: TextStyle(height: 1.1))]),
onTap: (){Navigator.push( TableRow(children: [Text(_f2.format(data[index].endContext.firstWhere((element) => element.userId == userID).extra), textAlign: TextAlign.right, style: const TextStyle(height: 1.1)), const Text(" :", style: TextStyle(height: 1.1)), Text(_f2.format(data[index].endContext.firstWhere((element) => element.userId != userID).extra), textAlign: TextAlign.right, style: const TextStyle(height: 1.1)), const Text(" VS", textAlign: TextAlign.right, style: TextStyle(height: 1.1))]),
context, ],),
MaterialPageRoute( onTap: () => Navigator.push(context, MaterialPageRoute(builder: (context) => TlMatchResultView(record: data[index], initPlayerId: userID))),
builder: (context) => TlMatchResultView(record: value, initPlayerId: userID),
),
);},
)]
: [Center(child: Text(t.noRecords, style: const TextStyle(fontFamily: "Eurostile Round", fontSize: 28)))],
); );
});
} }
} }

View File

@ -195,6 +195,9 @@ class TlMatchResultState extends State<TlMatchResultView> {
), ),
), ),
), ),
if (widget.record.ownId == widget.record.replayId) SliverToBoxAdapter(
child: Center(child: Text(t.p1nkl0bst3rAlert, textAlign: TextAlign.center)),
),
SliverToBoxAdapter(child: FutureBuilder(future: replayData, builder: (context, snapshot) { SliverToBoxAdapter(child: FutureBuilder(future: replayData, builder: (context, snapshot) {
switch(snapshot.connectionState){ switch(snapshot.connectionState){
case ConnectionState.none: case ConnectionState.none:
@ -470,8 +473,8 @@ class TlMatchResultState extends State<TlMatchResultView> {
) )
], ],
), ),
const Divider(), if (widget.record.ownId != widget.record.replayId) const Divider(),
Column( if (widget.record.ownId != widget.record.replayId) Column(
children: [ children: [
Padding( Padding(
padding: const EdgeInsets.only(bottom: 16), padding: const EdgeInsets.only(bottom: 16),

View File

@ -32,6 +32,9 @@
"closeSearch": "Close search", "closeSearch": "Close search",
"refresh": "Refresh", "refresh": "Refresh",
"fetchAndsaveTLHistory": "Get player history", "fetchAndsaveTLHistory": "Get player history",
"fetchAndSaveOldTLmatches": "Get Tetra League matches history",
"fetchAndsaveTLHistoryResult": "${number} states was found",
"fetchAndSaveOldTLmatchesResult": "${number} matches was found",
"showStoredData": "Show stored data", "showStoredData": "Show stored data",
"statsCalc": "Stats Calculator", "statsCalc": "Stats Calculator",
"settings": "Settings", "settings": "Settings",
@ -246,6 +249,7 @@
"connection": "Some issue with connection: ${code} ${message}", "connection": "Some issue with connection: ${code} ${message}",
"noSuchUser": "No such user", "noSuchUser": "No such user",
"history": "History for that player is missing", "history": "History for that player is missing",
"p1nkl0bst3rTLmatches": "No Tetra League matches was found",
"clientException": "No internet connection", "clientException": "No internet connection",
"forbidden": "Your IP address is blocked.\nChange IP address or reach out to osk", "forbidden": "Your IP address is blocked.\nChange IP address or reach out to osk",
"tooManyRequests": "You have been rate limited. Try again later", "tooManyRequests": "You have been rate limited. Try again later",

View File

@ -32,6 +32,9 @@
"closeSearch": "Закрыть поиск", "closeSearch": "Закрыть поиск",
"refresh": "Обновить", "refresh": "Обновить",
"fetchAndsaveTLHistory": "Получить историю игрока", "fetchAndsaveTLHistory": "Получить историю игрока",
"fetchAndSaveOldTLmatches": "Получить старые матчи Тетра Лиги",
"fetchAndsaveTLHistoryResult": "${number} состояний было найдено",
"fetchAndSaveOldTLmatchesResult": "${number} старых матчей было найдено",
"showStoredData": "Показать сохранённые данные", "showStoredData": "Показать сохранённые данные",
"statsCalc": "Калькулятор статистики", "statsCalc": "Калькулятор статистики",
"settings": "Настройки", "settings": "Настройки",
@ -246,6 +249,7 @@
"connection": "Проблема с подключением: ${code} ${message}", "connection": "Проблема с подключением: ${code} ${message}",
"noSuchUser": "Нет такого пользователя", "noSuchUser": "Нет такого пользователя",
"history": "История данного игрока отсутствует", "history": "История данного игрока отсутствует",
"p1nkl0bst3rTLmatches": "Старых матчей Тетра Лиги не было найдено",
"clientException": "Нет соединения с интернетом", "clientException": "Нет соединения с интернетом",
"forbidden": "Ваш IP адрес заблокирован.\nСмените IP адрес или свяжитесь с osk-ом", "forbidden": "Ваш IP адрес заблокирован.\nСмените IP адрес или свяжитесь с osk-ом",
"tooManyRequests": "Слишком много запросов. Попробуйте позже", "tooManyRequests": "Слишком много запросов. Попробуйте позже",