From 07929ca6f7c2c151e9d6ee4e4aac8b7bc081b7e8 Mon Sep 17 00:00:00 2001 From: dan63047 Date: Sat, 3 Feb 2024 16:02:58 +0300 Subject: [PATCH] Fetching old Tetra League matches Also changed behavior of main view fetch function --- lib/data_objects/tetrio.dart | 9 ++- lib/gen/strings.g.dart | 20 +++++- lib/services/tetrio_crud.dart | 94 ++++++++++++++++++++++++++ lib/views/compare_view.dart | 35 ++++------ lib/views/main_view.dart | 120 ++++++++++++++++++++-------------- lib/views/tl_match_view.dart | 7 +- res/i18n/strings.i18n.json | 4 ++ res/i18n/strings_ru.i18n.json | 4 ++ 8 files changed, 218 insertions(+), 75 deletions(-) diff --git a/lib/data_objects/tetrio.dart b/lib/data_objects/tetrio.dart index 5e555b8..6df9f83 100644 --- a/lib/data_objects/tetrio.dart +++ b/lib/data_objects/tetrio.dart @@ -830,7 +830,14 @@ class EndContextMulti { required this.tertiaryTracking, required this.extra, 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 json) { userId = json['id'] ?? json['user']['_id']; diff --git a/lib/gen/strings.g.dart b/lib/gen/strings.g.dart index 7b9f9dc..1e105df 100644 --- a/lib/gen/strings.g.dart +++ b/lib/gen/strings.g.dart @@ -4,9 +4,9 @@ /// To regenerate, run: `dart run slang` /// /// Locales: 2 -/// Strings: 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 // ignore_for_file: type=lint @@ -167,6 +167,9 @@ class Translations implements BaseTranslations { String get closeSearch => 'Close search'; String get refresh => 'Refresh'; 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 statsCalc => 'Stats Calculator'; 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 get noSuchUser => 'No such user'; 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 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'; @@ -755,6 +759,9 @@ class _StringsRu implements Translations { @override String get closeSearch => 'Закрыть поиск'; @override String get refresh => 'Обновить'; @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 statsCalc => 'Калькулятор статистики'; @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 get noSuchUser => 'Нет такого пользователя'; @override String get history => 'История данного игрока отсутствует'; + @override String get p1nkl0bst3rTLmatches => 'Старых матчей Тетра Лиги не было найдено'; @override String get clientException => 'Нет соединения с интернетом'; @override String get forbidden => 'Ваш IP адрес заблокирован.\nСмените IP адрес или свяжитесь с osk-ом'; @override String get tooManyRequests => 'Слишком много запросов. Попробуйте позже'; @@ -1335,6 +1343,9 @@ extension on Translations { case 'closeSearch': return 'Close search'; case 'refresh': return 'Refresh'; 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 'statsCalc': return 'Stats Calculator'; 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.noSuchUser': return 'No such user'; 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.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'; @@ -1849,6 +1861,9 @@ extension on _StringsRu { case 'closeSearch': return 'Закрыть поиск'; case 'refresh': 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 'statsCalc': 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.noSuchUser': return 'Нет такого пользователя'; case 'errors.history': return 'История данного игрока отсутствует'; + case 'errors.p1nkl0bst3rTLmatches': return 'Старых матчей Тетра Лиги не было найдено'; case 'errors.clientException': return 'Нет соединения с интернетом'; case 'errors.forbidden': return 'Ваш IP адрес заблокирован.\nСмените IP адрес или свяжитесь с osk-ом'; case 'errors.tooManyRequests': return 'Слишком много запросов. Попробуйте позже'; diff --git a/lib/services/tetrio_crud.dart b/lib/services/tetrio_crud.dart index 5d42d00..7f8843b 100644 --- a/lib/services/tetrio_crud.dart +++ b/lib/services/tetrio_crud.dart @@ -393,6 +393,100 @@ class TetrioService extends DB { } } + /// Docs later + Future> 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> csv = const CsvToListConverter().convert(response.body)..removeAt(0); + List 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. Future fetchTLLeaderboard() async { try{ diff --git a/lib/views/compare_view.dart b/lib/views/compare_view.dart index b22661c..2dd567f 100644 --- a/lib/views/compare_view.dart +++ b/lib/views/compare_view.dart @@ -1,5 +1,3 @@ -// ignore_for_file: use_build_context_synchronously - import 'dart:io'; import 'dart:math'; import 'package:flutter/foundation.dart'; @@ -70,8 +68,7 @@ class CompareState extends State { theRedSide = [null, null, average]; return setState(() {}); }on Exception { - ScaffoldMessenger.of(context) - .showSnackBar(SnackBar(content: Text(t.compareViewWrongValue(value: user)))); + if (context.mounted) ScaffoldMessenger.of(context).showSnackBar(SnackBar(content: Text(t.compareViewWrongValue(value: user)))); return; } } @@ -126,8 +123,7 @@ class CompareState extends State { } theRedSide = [player, dStates, player.tlSeason1]; } on Exception { - ScaffoldMessenger.of(context) - .showSnackBar(SnackBar(content: Text(t.compareViewWrongValue(value: user)))); + if (context.mounted) ScaffoldMessenger.of(context).showSnackBar(SnackBar(content: Text(t.compareViewWrongValue(value: user)))); } _justUpdate(); } @@ -146,8 +142,7 @@ class CompareState extends State { theGreenSide = [null, null, average]; return setState(() {}); }on Exception { - ScaffoldMessenger.of(context) - .showSnackBar(SnackBar(content: Text("Falied to assign $user"))); + if (context.mounted) ScaffoldMessenger.of(context).showSnackBar(SnackBar(content: Text("Falied to assign $user"))); return; } } @@ -202,8 +197,7 @@ class CompareState extends State { } theGreenSide = [player, dStates, player.tlSeason1]; } on Exception { - ScaffoldMessenger.of(context) - .showSnackBar(SnackBar(content: Text("Falied to assign $user"))); + if (context.mounted) ScaffoldMessenger.of(context).showSnackBar(SnackBar(content: Text("Falied to assign $user"))); } _justUpdate(); } @@ -213,19 +207,16 @@ class CompareState extends State { theGreenSide[2] = user.tlSeason1;}); } - double getWinrateByTR(double yourGlicko, double yourRD, double notyourGlicko, - double notyourRD) { + double getWinrateByTR(double yourGlicko, double yourRD, double notyourGlicko,double notyourRD) { return ((1 / - (1 + - pow( - 10, - (notyourGlicko - yourGlicko) / - (400 * - sqrt(1 + - (3 * - pow(0.0057564273, 2) * - (pow(yourRD, 2) + pow(notyourRD, 2)) / - pow(pi, 2)))))))); + (1 + pow(10, + (notyourGlicko - yourGlicko) / + (400 * sqrt(1 + (3 * pow(0.0057564273, 2) * + (pow(yourRD, 2) + pow(notyourRD, 2)) / pow(pi, 2) + ))) + ) + ) + )); } void _justUpdate() { diff --git a/lib/views/main_view.dart b/lib/views/main_view.dart index f82a24e..af5eb19 100644 --- a/lib/views/main_view.dart +++ b/lib/views/main_view.dart @@ -116,10 +116,10 @@ class _MainState extends State with TickerProviderStateMixin { /// That function initiate search of data about [player]. If [fetchHistory] is true, /// 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(() { _searchFor = player; - me = fetch(_searchFor, fetchHistory: fetchHistory); + me = fetch(_searchFor, fetchHistory: fetchHistory, fetchTLmatches: fetchTLmatches); }); } @@ -128,13 +128,14 @@ class _MainState extends State with TickerProviderStateMixin { } /// 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. - /// TODO: Change this behavior - Future fetch(String nickOrID, {bool fetchHistory = false}) async { + /// If at least one request to Tetra Channel API fails, whole function will throw an exception. + Future fetch(String nickOrID, {bool fetchHistory = false, bool fetchTLmatches = false}) async { TetrioPlayer me; // If user trying to search with discord id @@ -173,13 +174,28 @@ class _MainState extends State with TickerProviderStateMixin { TetraLeagueAlpha? compareWith; Set uniqueTL = {}; tlMatches = tlStream.records; - var storedRecords = await teto.getTLMatchesbyPlayerID(me.userId); // get old matches + List storedRecords = await teto.getTLMatchesbyPlayerID(me.userId); // get old matches if (isTracking){ // if tracked - save data to local DB await teto.storeState(me); await teto.saveTLMatchesFromStream(tlStream); } // building list of TL matches + if(fetchTLmatches) { + try{ + List 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) { // add stored match to list only if it missing from retrived ones if (!tlMatches.contains(match)) tlMatches.add(match); @@ -192,7 +208,21 @@ class _MainState extends State with TickerProviderStateMixin { }); // 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)); for (var element in states) { // For graphs I need only unique entries if (uniqueTL.isNotEmpty && uniqueTL.last != element.tlSeason1) uniqueTL.add(element.tlSeason1); @@ -271,6 +301,10 @@ class _MainState extends State with TickerProviderStateMixin { value: "history", child: Text(t.fetchAndsaveTLHistory), ), + PopupMenuItem( + value: "TLmatches", + child: Text(t.fetchAndSaveOldTLmatches), + ), PopupMenuItem( value: "/states", child: Text(t.showStoredData), @@ -292,6 +326,9 @@ class _MainState extends State with TickerProviderStateMixin { case "history": changePlayer(_searchFor, fetchHistory: true); break; + case "TLmatches": + changePlayer(_searchFor, fetchTLmatches: true); + break; default: context.go(value); } @@ -373,15 +410,6 @@ class _MainState extends State with TickerProviderStateMixin { var err = snapshot.error as ConnectionIssue; errText = t.errors.connection(code: err.code, message: err.message); 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: errText = t.errors.history; break; @@ -548,37 +576,33 @@ class _TLRecords extends StatelessWidget { @override Widget build(BuildContext context) { - bool bigScreen = MediaQuery.of(context).size.width > 768; - return ListView( // TODO: Redo using ListView.builder() - physics: const AlwaysScrollableScrollPhysics(), - children: (data.isNotEmpty) - ? [for (var value in data) ListTile( - leading: Text("${value.endContext.firstWhere((element) => element.userId == userID).points} : ${value.endContext.firstWhere((element) => element.userId != userID).points}", - style: bigScreen ? const TextStyle(fontFamily: "Eurostile Round Extended", fontSize: 28) : - const TextStyle(fontSize: 28)), - title: Text("vs. ${value.endContext.firstWhere((element) => element.userId != userID).username}"), - subtitle: Text(_dateFormat.format(value.timestamp)), - trailing: Table(defaultColumnWidth: const IntrinsicColumnWidth(), - defaultVerticalAlignment: TableCellVerticalAlignment.baseline, - textBaseline: TextBaseline.alphabetic, - columnWidths: const { - 0: FixedColumnWidth(50), - 2: FixedColumnWidth(50), - }, - children: [ - 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))]), - 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))]), - ],), - onTap: (){Navigator.push( - context, - MaterialPageRoute( - builder: (context) => TlMatchResultView(record: value, initPlayerId: userID), - ), - );}, - )] - : [Center(child: Text(t.noRecords, style: const TextStyle(fontFamily: "Eurostile Round", fontSize: 28)))], + bool bigScreen = MediaQuery.of(context).size.width > 768; + if (data.isEmpty) return Center(child: Text(t.noRecords, style: const TextStyle(fontFamily: "Eurostile Round", fontSize: 28))); + return ListView.builder( + physics: const AlwaysScrollableScrollPhysics(), + itemCount: data.length, + itemBuilder: (BuildContext context, int index) { + return ListTile( + leading: Text("${data[index].endContext.firstWhere((element) => element.userId == userID).points} : ${data[index].endContext.firstWhere((element) => element.userId != userID).points}", + style: bigScreen ? const TextStyle(fontFamily: "Eurostile Round Extended", fontSize: 28) : + const TextStyle(fontSize: 28)), + title: Text("vs. ${data[index].endContext.firstWhere((element) => element.userId != userID).username}"), + subtitle: Text(_dateFormat.format(data[index].timestamp)), + trailing: Table(defaultColumnWidth: const IntrinsicColumnWidth(), + defaultVerticalAlignment: TableCellVerticalAlignment.baseline, + textBaseline: TextBaseline.alphabetic, + columnWidths: const { + 0: FixedColumnWidth(50), + 2: FixedColumnWidth(50), + }, + children: [ + 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))]), + 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))]), + ],), + onTap: () => Navigator.push(context, MaterialPageRoute(builder: (context) => TlMatchResultView(record: data[index], initPlayerId: userID))), ); + }); } } diff --git a/lib/views/tl_match_view.dart b/lib/views/tl_match_view.dart index b353179..219b725 100644 --- a/lib/views/tl_match_view.dart +++ b/lib/views/tl_match_view.dart @@ -195,6 +195,9 @@ class TlMatchResultState extends State { ), ), ), + 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) { switch(snapshot.connectionState){ case ConnectionState.none: @@ -470,8 +473,8 @@ class TlMatchResultState extends State { ) ], ), - const Divider(), - Column( + if (widget.record.ownId != widget.record.replayId) const Divider(), + if (widget.record.ownId != widget.record.replayId) Column( children: [ Padding( padding: const EdgeInsets.only(bottom: 16), diff --git a/res/i18n/strings.i18n.json b/res/i18n/strings.i18n.json index b186ea9..92042ac 100644 --- a/res/i18n/strings.i18n.json +++ b/res/i18n/strings.i18n.json @@ -32,6 +32,9 @@ "closeSearch": "Close search", "refresh": "Refresh", "fetchAndsaveTLHistory": "Get player history", + "fetchAndSaveOldTLmatches": "Get Tetra League matches history", + "fetchAndsaveTLHistoryResult": "${number} states was found", + "fetchAndSaveOldTLmatchesResult": "${number} matches was found", "showStoredData": "Show stored data", "statsCalc": "Stats Calculator", "settings": "Settings", @@ -246,6 +249,7 @@ "connection": "Some issue with connection: ${code} ${message}", "noSuchUser": "No such user", "history": "History for that player is missing", + "p1nkl0bst3rTLmatches": "No Tetra League matches was found", "clientException": "No internet connection", "forbidden": "Your IP address is blocked.\nChange IP address or reach out to osk", "tooManyRequests": "You have been rate limited. Try again later", diff --git a/res/i18n/strings_ru.i18n.json b/res/i18n/strings_ru.i18n.json index 25f4ffd..ebed9c7 100644 --- a/res/i18n/strings_ru.i18n.json +++ b/res/i18n/strings_ru.i18n.json @@ -32,6 +32,9 @@ "closeSearch": "Закрыть поиск", "refresh": "Обновить", "fetchAndsaveTLHistory": "Получить историю игрока", + "fetchAndSaveOldTLmatches": "Получить старые матчи Тетра Лиги", + "fetchAndsaveTLHistoryResult": "${number} состояний было найдено", + "fetchAndSaveOldTLmatchesResult": "${number} старых матчей было найдено", "showStoredData": "Показать сохранённые данные", "statsCalc": "Калькулятор статистики", "settings": "Настройки", @@ -246,6 +249,7 @@ "connection": "Проблема с подключением: ${code} ${message}", "noSuchUser": "Нет такого пользователя", "history": "История данного игрока отсутствует", + "p1nkl0bst3rTLmatches": "Старых матчей Тетра Лиги не было найдено", "clientException": "Нет соединения с интернетом", "forbidden": "Ваш IP адрес заблокирован.\nСмените IP адрес или свяжитесь с osk-ом", "tooManyRequests": "Слишком много запросов. Попробуйте позже",