A lot of things, 2.0.3 is ready to release
- Can fetch S2 history - New averages - Damage calculator fix - Icon for linux runner - We can build .deb now
This commit is contained in:
parent
0ee2b83bd7
commit
ee3bbe6369
|
@ -62,6 +62,8 @@ jobs:
|
|||
type: 'zip'
|
||||
filename: TetraStats-${{github.ref_name}}-linux.zip
|
||||
directory: build/linux/x64/release/bundle
|
||||
- name: Build .deb package
|
||||
run: dart run flutter_to_debian
|
||||
- name: Push to Releases
|
||||
uses: ncipollo/release-action@v1
|
||||
with:
|
||||
|
@ -69,7 +71,7 @@ jobs:
|
|||
allowUpdates: true
|
||||
replacesArtifacts: false
|
||||
discussionCategory: autobuilded-releases
|
||||
artifacts: "build/linux/x64/release/bundle/TetraStats-${{github.ref_name}}-linux.zip"
|
||||
artifacts: "build/linux/x64/release/bundle/TetraStats-${{github.ref_name}}-linux.zip,build/linux/x64/release/debian/*"
|
||||
tag: Auto-${{ github.run_number }}
|
||||
body: Build with GitHub Action workflow
|
||||
token: ${{ secrets.TOKEN }}
|
||||
|
|
34
.metadata
34
.metadata
|
@ -1,11 +1,11 @@
|
|||
# This file tracks properties of this Flutter project.
|
||||
# Used by Flutter tool to assess capabilities and perform upgrades etc.
|
||||
#
|
||||
# This file should be version controlled.
|
||||
# This file should be version controlled and should not be manually edited.
|
||||
|
||||
version:
|
||||
revision: 4d9e56e694b656610ab87fcf2efbcd226e0ed8cf
|
||||
channel: stable
|
||||
revision: "b0850beeb25f6d5b10426284f506557f66181b36"
|
||||
channel: "stable"
|
||||
|
||||
project_type: app
|
||||
|
||||
|
@ -13,26 +13,26 @@ project_type: app
|
|||
migration:
|
||||
platforms:
|
||||
- platform: root
|
||||
create_revision: 4d9e56e694b656610ab87fcf2efbcd226e0ed8cf
|
||||
base_revision: 4d9e56e694b656610ab87fcf2efbcd226e0ed8cf
|
||||
create_revision: b0850beeb25f6d5b10426284f506557f66181b36
|
||||
base_revision: b0850beeb25f6d5b10426284f506557f66181b36
|
||||
- platform: android
|
||||
create_revision: 4d9e56e694b656610ab87fcf2efbcd226e0ed8cf
|
||||
base_revision: 4d9e56e694b656610ab87fcf2efbcd226e0ed8cf
|
||||
create_revision: b0850beeb25f6d5b10426284f506557f66181b36
|
||||
base_revision: b0850beeb25f6d5b10426284f506557f66181b36
|
||||
- platform: ios
|
||||
create_revision: 4d9e56e694b656610ab87fcf2efbcd226e0ed8cf
|
||||
base_revision: 4d9e56e694b656610ab87fcf2efbcd226e0ed8cf
|
||||
create_revision: b0850beeb25f6d5b10426284f506557f66181b36
|
||||
base_revision: b0850beeb25f6d5b10426284f506557f66181b36
|
||||
- platform: linux
|
||||
create_revision: 4d9e56e694b656610ab87fcf2efbcd226e0ed8cf
|
||||
base_revision: 4d9e56e694b656610ab87fcf2efbcd226e0ed8cf
|
||||
create_revision: b0850beeb25f6d5b10426284f506557f66181b36
|
||||
base_revision: b0850beeb25f6d5b10426284f506557f66181b36
|
||||
- platform: macos
|
||||
create_revision: 4d9e56e694b656610ab87fcf2efbcd226e0ed8cf
|
||||
base_revision: 4d9e56e694b656610ab87fcf2efbcd226e0ed8cf
|
||||
create_revision: b0850beeb25f6d5b10426284f506557f66181b36
|
||||
base_revision: b0850beeb25f6d5b10426284f506557f66181b36
|
||||
- platform: web
|
||||
create_revision: 4d9e56e694b656610ab87fcf2efbcd226e0ed8cf
|
||||
base_revision: 4d9e56e694b656610ab87fcf2efbcd226e0ed8cf
|
||||
create_revision: b0850beeb25f6d5b10426284f506557f66181b36
|
||||
base_revision: b0850beeb25f6d5b10426284f506557f66181b36
|
||||
- platform: windows
|
||||
create_revision: 4d9e56e694b656610ab87fcf2efbcd226e0ed8cf
|
||||
base_revision: 4d9e56e694b656610ab87fcf2efbcd226e0ed8cf
|
||||
create_revision: b0850beeb25f6d5b10426284f506557f66181b36
|
||||
base_revision: b0850beeb25f6d5b10426284f506557f66181b36
|
||||
|
||||
# User provided section
|
||||
|
||||
|
|
|
@ -0,0 +1,5 @@
|
|||
package com.dan63.tetra_stats
|
||||
|
||||
import io.flutter.embedding.android.FlutterActivity
|
||||
|
||||
class MainActivity: FlutterActivity()
|
|
@ -2,10 +2,11 @@ flutter_app:
|
|||
command: tetra_stats
|
||||
arch: x64
|
||||
parent: /usr/local/lib
|
||||
nonInteractive: true
|
||||
|
||||
control:
|
||||
Package: tetra-stats
|
||||
Version: 0.2.0
|
||||
Version: 2.0.3
|
||||
Architecture: amd64
|
||||
Essential: no
|
||||
Priority: optional
|
||||
|
|
|
@ -1,5 +1,5 @@
|
|||
[Desktop Entry]
|
||||
Version=0.2.0
|
||||
Version=2.0.3
|
||||
Name=Tetra Stats
|
||||
GenericName=Tetra Stats
|
||||
Comment=Track your and other player stats in TETR.IO
|
||||
|
|
|
@ -0,0 +1,12 @@
|
|||
import Flutter
|
||||
import UIKit
|
||||
import XCTest
|
||||
|
||||
class RunnerTests: XCTestCase {
|
||||
|
||||
func testExample() {
|
||||
// If you add code to the Runner application, consider adding tests here.
|
||||
// See https://developer.apple.com/documentation/xctest for more information about using XCTest.
|
||||
}
|
||||
|
||||
}
|
|
@ -1,7 +1,7 @@
|
|||
import 'package:flutter/material.dart';
|
||||
|
||||
const int currentSeason = 2;
|
||||
final DateTime sprintAndBlitzRelevance = DateTime(2024, 8, 25);
|
||||
final DateTime sprintAndBlitzRelevance = DateTime(2025, 1, 16);
|
||||
const double noTrRd = 60.9;
|
||||
const double apmWeight = 1;
|
||||
const double ppsWeight = 45;
|
||||
|
@ -210,46 +210,46 @@ const List<Color> achievementColors = [
|
|||
];
|
||||
|
||||
const Map<String, Duration> sprintAverages = {
|
||||
// based on https://discord.com/channels/673303546107658242/674421736162197515/1277367281264889908
|
||||
'x+': Duration(seconds: 18, milliseconds: 867),
|
||||
'x': Duration(seconds: 23, milliseconds: 277),
|
||||
'u': Duration(seconds: 28, milliseconds: 853),
|
||||
'ss': Duration(seconds: 35, milliseconds: 173),
|
||||
's+': Duration(seconds: 39, milliseconds: 028),
|
||||
's': Duration(seconds: 45, milliseconds: 807),
|
||||
's-': Duration(seconds: 48, milliseconds: 840),
|
||||
'a+': Duration(seconds: 54, milliseconds: 975),
|
||||
'a': Duration(seconds: 60, milliseconds: 287),
|
||||
'a-': Duration(seconds: 64, milliseconds: 019),
|
||||
'b+': Duration(seconds: 76, milliseconds: 531),
|
||||
'b': Duration(seconds: 77, milliseconds: 635),
|
||||
'b-': Duration(seconds: 92, milliseconds: 279),
|
||||
'c+': Duration(seconds: 97, milliseconds: 911),
|
||||
'c': Duration(seconds: 104, milliseconds: 700),
|
||||
'c-': Duration(seconds: 115, milliseconds: 173),
|
||||
'd+': Duration(seconds: 131, milliseconds: 486),
|
||||
'd': Duration(seconds: 158, milliseconds: 397),
|
||||
// based on https://discord.com/channels/673303546107658242/1260605501754839060/1329448681539244094
|
||||
'x+': Duration(seconds: 19, milliseconds: 223),
|
||||
'x': Duration(seconds: 24, milliseconds: 832),
|
||||
'u': Duration(seconds: 32, milliseconds: 586),
|
||||
'ss': Duration(seconds: 40, milliseconds: 011),
|
||||
's+': Duration(seconds: 47, milliseconds: 963),
|
||||
's': Duration(seconds: 54, milliseconds: 413),
|
||||
's-': Duration(seconds: 61, milliseconds: 740),
|
||||
'a+': Duration(seconds: 70, milliseconds: 101),
|
||||
'a': Duration(seconds: 73, milliseconds: 294),
|
||||
'a-': Duration(seconds: 81, milliseconds: 773),
|
||||
'b+': Duration(seconds: 88, milliseconds: 647),
|
||||
'b': Duration(seconds: 97, milliseconds: 699),
|
||||
'b-': Duration(seconds: 105, milliseconds: 721),
|
||||
'c+': Duration(seconds: 113, milliseconds: 229),
|
||||
'c': Duration(seconds: 124, milliseconds: 740),
|
||||
'c-': Duration(seconds: 129, milliseconds: 382),
|
||||
'd+': Duration(seconds: 138, milliseconds: 947),
|
||||
'd': Duration(seconds: 155, milliseconds: 190),
|
||||
};
|
||||
|
||||
const Map<String, int> blitzAverages = {
|
||||
'x+': 879378,
|
||||
'x': 677479,
|
||||
'u': 485962,
|
||||
'ss': 369043,
|
||||
's+': 279242,
|
||||
's': 245619,
|
||||
's-': 199368,
|
||||
'a+': 162035,
|
||||
'a': 130949,
|
||||
'a-': 111505,
|
||||
'b+': 97251,
|
||||
'b': 83580,
|
||||
'b-': 70511,
|
||||
'c+': 56747,
|
||||
'c': 43002,
|
||||
'c-': 38925,
|
||||
'd+': 30483,
|
||||
'd': 22513,
|
||||
'x+': 886046,
|
||||
'x': 631014,
|
||||
'u': 428799,
|
||||
'ss': 296430,
|
||||
's+': 212237,
|
||||
's': 157234,
|
||||
's-': 122791,
|
||||
'a+': 103031,
|
||||
'a': 90174,
|
||||
'a-': 73474,
|
||||
'b+': 60655,
|
||||
'b': 52463,
|
||||
'b-': 43877,
|
||||
'c+': 36594,
|
||||
'c': 34014,
|
||||
'c-': 29613,
|
||||
'd+': 31521,
|
||||
'd': 23437,
|
||||
};
|
||||
|
||||
List<DateTime> seasonStarts = [
|
||||
|
|
|
@ -6,7 +6,7 @@
|
|||
/// Locales: 3
|
||||
/// Strings: 2295 (765 per locale)
|
||||
///
|
||||
/// Built on 2024-12-31 at 17:29 UTC
|
||||
/// Built on 2025-01-14 at 21:20 UTC
|
||||
|
||||
// coverage:ignore-file
|
||||
// ignore_for_file: type=lint
|
||||
|
@ -707,7 +707,7 @@ class _StringsGraphsDestinationEn {
|
|||
final Translations _root; // ignore: unused_field
|
||||
|
||||
// Translations
|
||||
String get fetchAndsaveTLHistory => 'Get player history';
|
||||
String get fetchAndsaveTLHistory => 'Fetch 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';
|
||||
|
@ -2247,7 +2247,7 @@ class _StringsGraphsDestinationRuRu implements _StringsGraphsDestinationEn {
|
|||
@override final _StringsRuRu _root; // ignore: unused_field
|
||||
|
||||
// Translations
|
||||
@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} матчей было найдено';
|
||||
|
@ -4925,7 +4925,7 @@ extension on Translations {
|
|||
case 'actions.ok': return 'OK';
|
||||
case 'actions.apply': return 'Apply';
|
||||
case 'actions.refresh': return 'Refresh';
|
||||
case 'graphsDestination.fetchAndsaveTLHistory': return 'Get player history';
|
||||
case 'graphsDestination.fetchAndsaveTLHistory': return 'Fetch History';
|
||||
case 'graphsDestination.fetchAndSaveOldTLmatches': return 'Get Tetra League matches history';
|
||||
case 'graphsDestination.fetchAndsaveTLHistoryResult': return ({required Object number}) => '${number} states was found';
|
||||
case 'graphsDestination.fetchAndSaveOldTLmatchesResult': return ({required Object number}) => '${number} matches was found';
|
||||
|
@ -5739,7 +5739,7 @@ extension on _StringsRuRu {
|
|||
case 'actions.ok': return 'ОК';
|
||||
case 'actions.apply': return 'Применить';
|
||||
case 'actions.refresh': return 'Обновить';
|
||||
case 'graphsDestination.fetchAndsaveTLHistory': return 'Получить историю игрока';
|
||||
case 'graphsDestination.fetchAndsaveTLHistory': return 'Получить историю';
|
||||
case 'graphsDestination.fetchAndSaveOldTLmatches': return 'Получить историю матчей Тетра Лиги';
|
||||
case 'graphsDestination.fetchAndsaveTLHistoryResult': return ({required Object number}) => '${number} состояний было найдено';
|
||||
case 'graphsDestination.fetchAndSaveOldTLmatchesResult': return ({required Object number}) => '${number} матчей было найдено';
|
||||
|
|
|
@ -88,7 +88,7 @@ class DB {
|
|||
}
|
||||
|
||||
Future<bool> checkImportingDB(File db) async {
|
||||
final newDB = await openDatabase(db.path);
|
||||
final newDB = await openDatabase(db.path); // TODO: Maybe i should use arguments, that this method provides?
|
||||
var usersTable = await newDB.rawQuery("PRAGMA table_xinfo(`${tetrioUsersTable}`);");
|
||||
List<String> usersTableRows = [for (Map<String, Object?> row in usersTable) row["name"] as String];
|
||||
if (!listEquals(usersTableRows, tetrioUsersTableRows)) return false;
|
||||
|
|
|
@ -4,9 +4,11 @@ import 'dart:async';
|
|||
import 'dart:convert';
|
||||
import 'dart:developer' as developer;
|
||||
import 'dart:io';
|
||||
import 'dart:math';
|
||||
import 'package:path/path.dart';
|
||||
import 'package:path_provider/path_provider.dart';
|
||||
import 'package:sqflite_common_ffi/sqflite_ffi.dart';
|
||||
import 'package:tetra_stats/data_objects/beta_record.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';
|
||||
|
@ -24,8 +26,6 @@ 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:flutter/foundation.dart';
|
||||
import 'package:tetra_stats/services/custom_http_client.dart';
|
||||
|
@ -372,7 +372,7 @@ class TetrioService extends DB {
|
|||
dbPath = join(docsPath.path, dbName);
|
||||
}
|
||||
var dbFile = File(dbPath);
|
||||
var dbSize = (await dbFile.stat()).size;
|
||||
var dbSize = kIsWeb ? -1 : (await dbFile.stat()).size;
|
||||
var dbTLRecordsQuery = (await db.rawQuery('SELECT COUNT(*) FROM `${tetraLeagueMatchesTable}`')).first['COUNT(*)']! as int;
|
||||
var dbTLStatesQuery = (await db.rawQuery('SELECT COUNT(*) FROM `${tetrioLeagueTable}`')).first['COUNT(*)']! as int;
|
||||
return (dbSize, dbTLRecordsQuery, dbTLStatesQuery);
|
||||
|
@ -673,8 +673,7 @@ class TetrioService extends DB {
|
|||
|
||||
/// Retrieves Tetra League history from p1nkl0bst3r api for a player with given [id]. Returns a list of states
|
||||
/// (state = instance of [TetrioPlayer] at some point of time). Can throw an exception if fails to retrieve data.
|
||||
Future<List<TetraLeague>> fetchAndsaveTLHistory(String id, int season) async {
|
||||
// TODO: find le way to get season 2 history
|
||||
Future<List<TetraLeague>> fetchAndsaveS1TLHistory(String id) async {
|
||||
Uri url;
|
||||
if (kIsWeb) {
|
||||
url = Uri.https(webVersionDomain, 'oskware_bridge.php', {"endpoint": "TLHistory", "user": id});
|
||||
|
@ -745,6 +744,70 @@ class TetrioService extends DB {
|
|||
}
|
||||
}
|
||||
|
||||
Future<List<TetraLeague>> fetchAndsaveS2TLHistory(String id) async {
|
||||
final db = getDatabaseOrThrow();
|
||||
List<BetaRecord> records = [];
|
||||
int entries = 100;
|
||||
String? prisecter;
|
||||
while (entries > 0){
|
||||
TetraLeagueBetaStream stream = await fetchTLStream(id, prisecter: prisecter);
|
||||
if (stream.records.isEmpty) break;
|
||||
records.addAll(stream.records);
|
||||
prisecter = stream.records.last.prisecter.toString();
|
||||
entries = stream.records.length;
|
||||
}
|
||||
//TetraLeague currentState = await fetchTLSummary(id);
|
||||
List<TetraLeague> states = [];
|
||||
//states.add(currentState);
|
||||
int gp = 0;
|
||||
int gw = 0;
|
||||
List<double> last10apm = [];
|
||||
List<double> last10pps = [];
|
||||
List<double> last10vs = [];
|
||||
int bestRankIndex = -1; // -1 - Z; 0 - D, 1 - D+ ... 18 - X+
|
||||
Batch batch = db.batch();
|
||||
for (BetaRecord match in records.reversed){
|
||||
gp++;
|
||||
if (match.extras.result.contains("victory")) gw++;
|
||||
last10apm.add(match.results.leaderboard.firstWhere((e) => e.id == id).stats.apm);
|
||||
if (last10apm.length > 10) last10apm.removeAt(0);
|
||||
last10pps.add(match.results.leaderboard.firstWhere((e) => e.id == id).stats.pps);
|
||||
if (last10pps.length > 10) last10pps.removeAt(0);
|
||||
last10vs.add(match.results.leaderboard.firstWhere((e) => e.id == id).stats.vs);
|
||||
if (last10vs.length > 10) last10vs.removeAt(0);
|
||||
double apm = last10apm.reduce((v, e) => v + e) / last10apm.length;
|
||||
double pps = last10pps.reduce((v, e) => v + e) / last10pps.length;
|
||||
double vs = last10vs.reduce((v, e) => v + e) / last10vs.length;
|
||||
TetraLeague state = TetraLeague(
|
||||
id: id,
|
||||
timestamp: match.ts,
|
||||
gamesPlayed: gp,
|
||||
gamesWon: gw,
|
||||
bestRank: bestRankIndex != -1 ? ranks[bestRankIndex] : "z",
|
||||
decaying: false,
|
||||
tr: match.extras.league[id]?[1]?.tr??-1.0,
|
||||
glicko: match.extras.league[id]?[1]?.glicko,
|
||||
rd: match.extras.league[id]?[1]?.rd,
|
||||
gxe: match.extras.league[id]?[1]?.glicko != null ? 10000 / (1 + pow(10, (((1500 - match.extras.league[id]![1]!.glicko) * pi / sqrt(3 * pow(ln10, 2) * pow(match.extras.league[id]![1]!.rd, 2) + 2500 * (64 * pow(pi, 2) + 147 * pow(ln10, 2))))))) / 100 : -1,
|
||||
rank: match.extras.league[id]?[1]?.rank??"z",
|
||||
percentileRank: match.extras.league[id]?[1]?.rank??"z",
|
||||
percentile: match.extras.league[id]?[1]?.rank != null ? rankCutoffs[match.extras.league[id]![1]!.rank]! : -1,
|
||||
standing: match.extras.league[id]?[1]?.placement??-1,
|
||||
standingLocal: -1,
|
||||
nextAt: -1,
|
||||
prevAt: -1,
|
||||
apm: apm,
|
||||
pps: pps,
|
||||
vs: vs,
|
||||
season: currentSeason
|
||||
);
|
||||
states.add(state);
|
||||
batch.insert(tetrioLeagueTable, state.toJson(), conflictAlgorithm: ConflictAlgorithm.replace);
|
||||
}
|
||||
batch.commit();
|
||||
return states;
|
||||
}
|
||||
|
||||
/// Docs later
|
||||
Future<TetraLeagueAlphaStream> fetchAndSaveOldTLmatches(String userID) async {
|
||||
Uri url;
|
||||
|
@ -1129,38 +1192,29 @@ class TetrioService extends DB {
|
|||
await db.delete(tetrioTLReplayStatsTable, where: '$idCol = ?', whereArgs: [rID]);
|
||||
}
|
||||
|
||||
/// Retrieves Blitz, 40 Lines and Zen records for a given [userID] from Tetra Channel api. Returns `UserRecords`.
|
||||
/// Throws an exception if fails to retrieve.
|
||||
Future<UserRecords> fetchRecords(String userID) async {
|
||||
UserRecords? cached = _cache.get(userID, UserRecords);
|
||||
Future<TetraLeague> fetchTLSummary(String id) async {
|
||||
TetraLeague? cached = _cache.get(id, TetraLeague);
|
||||
if (cached != null) return cached;
|
||||
|
||||
Uri url;
|
||||
if (kIsWeb) {
|
||||
url = Uri.https(webVersionDomain, 'oskware_bridge.php', {"endpoint": "tetrioUserRecords", "user": userID.toLowerCase().trim()});
|
||||
url = Uri.https(webVersionDomain, 'oskware_bridge.php', {"endpoint": "Summaries", "id": id});
|
||||
} else {
|
||||
url = Uri.https('ch.tetr.io', 'api/users/${userID.toLowerCase().trim()}/records');
|
||||
url = Uri.https('ch.tetr.io', 'api/users/$id/summaries/league');
|
||||
}
|
||||
|
||||
try{
|
||||
final response = await client.get(url);
|
||||
|
||||
switch (response.statusCode) {
|
||||
case 200:
|
||||
if (jsonDecode(response.body)['success']) {
|
||||
Map jsonRecords = jsonDecode(response.body);
|
||||
var sprint = jsonRecords['data']['records']['40l']['record'] != null
|
||||
? RecordSingle.fromJson(jsonRecords['data']['records']['40l']['record'], jsonRecords['data']['records']['40l']['rank'], jsonRecords['data']['records']['40l']['rank_local'])
|
||||
: null;
|
||||
var blitz = jsonRecords['data']['records']['blitz']['record'] != null
|
||||
? RecordSingle.fromJson(jsonRecords['data']['records']['blitz']['record'], jsonRecords['data']['records']['blitz']['rank'], jsonRecords['data']['records']['blitz']['rank_local'])
|
||||
: null;
|
||||
var zen = TetrioZen.fromJson(jsonRecords['data']['zen']);
|
||||
UserRecords result = UserRecords(userID, sprint, blitz, zen);
|
||||
_cache.store(result, jsonDecode(response.body)['cache']['cached_until']);
|
||||
developer.log("fetchRecords: $userID records retrieved and cached", name: "services/tetrio_crud");
|
||||
return result;
|
||||
developer.log("fetchTLSummary: $id TL state retrieved and cached", name: "services/tetrio_crud");
|
||||
TetraLeague league = TetraLeague.fromJson(jsonDecode(response.body)['data'], DateTime.now(), currentSeason, id);
|
||||
_cache.store(league, jsonDecode(response.body)['cache']['cached_until']);
|
||||
return league;
|
||||
} else {
|
||||
developer.log("fetchRecords User dosen't exist", name: "services/tetrio_crud", error: response.body);
|
||||
developer.log("fetchTLSummary: User dosen't exist", name: "services/tetrio_crud", error: response.body);
|
||||
throw TetrioPlayerNotExist();
|
||||
}
|
||||
case 403:
|
||||
|
@ -1175,7 +1229,7 @@ class TetrioService extends DB {
|
|||
case 504:
|
||||
throw TetrioInternalProblem();
|
||||
default:
|
||||
developer.log("fetchRecords Failed to fetch records", name: "services/tetrio_crud", error: response.statusCode);
|
||||
developer.log("fetchTLSummary Failed to fetch TL state", name: "services/tetrio_crud", error: response.statusCode);
|
||||
throw ConnectionIssue(response.statusCode, response.reasonPhrase??"No reason");
|
||||
}
|
||||
} on http.ClientException catch (e, s) {
|
||||
|
@ -1427,15 +1481,4 @@ class TetrioService extends DB {
|
|||
}
|
||||
return data;
|
||||
}
|
||||
|
||||
// Future<void> fetchTracked() async {
|
||||
// for (String userID in (await getAllPlayerToTrack())) {
|
||||
// TetrioPlayer player = await fetchPlayer(userID);
|
||||
// storeState(player);
|
||||
// sleep(Durations.extralong4);
|
||||
// TetraLeagueBetaStream matches = await fetchTLStream(userID);
|
||||
// saveTLMatchesFromStream(matches);
|
||||
// sleep(Durations.extralong4);
|
||||
// }
|
||||
// }
|
||||
}
|
||||
|
|
|
@ -76,7 +76,7 @@ class ClearData{
|
|||
|
||||
if (rules.combo && rules.comboTable != ComboTables.none) {
|
||||
if (combo >= 1){
|
||||
if (lines == 1 && rules.comboTable != ComboTables.multiplier) damage += combotable[rules.comboTable]![max(0, min(combo - 1, combotable[rules.comboTable]!.length - 1))];
|
||||
if (rules.comboTable != ComboTables.multiplier) damage += combotable[rules.comboTable]![max(0, min(combo - 1, combotable[rules.comboTable]!.length - 1))];
|
||||
else damage *= (1 + COMBO_BONUS * (combo));
|
||||
}
|
||||
if (combo >= 2) {
|
||||
|
@ -166,7 +166,7 @@ class _DestinationCalculatorState extends State<DestinationCalculator> {
|
|||
List<ClearData> clears = [];
|
||||
Map<String, int> customClearsChoice = {
|
||||
t.calcDestination.noSpinClears: 5,
|
||||
t.calcDestination.spins: 5
|
||||
t.stats.spins: 5
|
||||
};
|
||||
int idCounter = 0;
|
||||
Rules rules = Rules();
|
||||
|
@ -400,7 +400,13 @@ class _DestinationCalculatorState extends State<DestinationCalculator> {
|
|||
),
|
||||
onTap: (){
|
||||
setState((){
|
||||
clears.add(ClearData("${key == t.calcDestination.spins ? "${t.stats.spin} " : ""}${clearNames[min(customClearsChoice[key]!, clearNames.length-1)]} (${customClearsChoice[key]!} ${t.stats.lines})", key == t.calcDestination.spins ? Lineclears.TSPIN_PENTA : Lineclears.PENTA, customClearsChoice[key]!, false, key == t.calcDestination.spins).cloneWith(idCounter));
|
||||
clears.add(ClearData(
|
||||
"${key == t.stats.spins ? "${t.stats.spin} " : ""}${clearNames[min(customClearsChoice[key]!, clearNames.length-1)]} (${customClearsChoice[key]!} ${t.stats.lines})",
|
||||
key == t.stats.spins ? Lineclears.TSPIN_PENTA : Lineclears.PENTA,
|
||||
customClearsChoice[key]!,
|
||||
false,
|
||||
key == t.stats.spins).cloneWith(idCounter)
|
||||
);
|
||||
});
|
||||
idCounter++;
|
||||
},
|
||||
|
|
|
@ -51,6 +51,7 @@ class _DestinationGraphsState extends State<DestinationGraphs> {
|
|||
ValueNotifier<String> historyPlayerUsername = ValueNotifier("");
|
||||
ValueNotifier<String> historyPlayerAvatarRevizion = ValueNotifier("");
|
||||
List<String> excludeRanks = [];
|
||||
late Future<Map<int, Map<Stats, List<_HistoryChartSpot>>>> playerHistory = getHistoryData(fetchData);
|
||||
late Future<List<_MyScatterSpot>> futureLeague = getTetraLeagueData(_Xchart, Ychart);
|
||||
String searchLeague = "";
|
||||
int? TLstatePlayers;
|
||||
|
@ -143,9 +144,11 @@ class _DestinationGraphsState extends State<DestinationGraphs> {
|
|||
}
|
||||
|
||||
Future<Map<int, Map<Stats, List<_HistoryChartSpot>>>> getHistoryData(bool fetchHistory) async {
|
||||
var playerID = (await teto.fetchPlayer(widget.searchFor)).userId;
|
||||
if(fetchHistory){
|
||||
try{
|
||||
var history = await teto.fetchAndsaveTLHistory(widget.searchFor, 1);
|
||||
//var history = await Future.wait([teto.fetchAndsaveS1TLHistory(widget.searchFor), teto.fetchAndsaveS2TLHistory(widget.searchFor)]); // S1 history unavaliable because of certificate issue on p1nkl0bst3r side
|
||||
var history = await teto.fetchAndsaveS2TLHistory(playerID);
|
||||
if (context.mounted) ScaffoldMessenger.of(context).showSnackBar(SnackBar(content: Text(t.graphsDestination.fetchAndsaveTLHistoryResult(number: history.length))));
|
||||
}on TetrioHistoryNotExist{
|
||||
if (context.mounted) ScaffoldMessenger.of(context).showSnackBar(SnackBar(content: Text(t.errors.noHistorySaved)));
|
||||
|
@ -159,19 +162,19 @@ class _DestinationGraphsState extends State<DestinationGraphs> {
|
|||
}
|
||||
|
||||
List<List<TetraLeague>> states = await Future.wait<List<TetraLeague>>([
|
||||
teto.getStates(widget.searchFor, season: 1), teto.getStates(widget.searchFor, season: 2),
|
||||
teto.getStates(playerID, season: 1), teto.getStates(playerID, season: 2),
|
||||
]);
|
||||
Map<int, Map<Stats, List<_HistoryChartSpot>>> historyData = {}; // [season][metric][spot]
|
||||
for (int season = 0; season < currentSeason; season++){
|
||||
if (states[season].length >= 2){
|
||||
Map<Stats, List<_HistoryChartSpot>> statsMap = {};
|
||||
for (var stat in Stats.values) statsMap[stat] = [for (var tl in states[season]) if (tl.getStatByEnum(stat) != null) _HistoryChartSpot(tl.timestamp, tl.gamesPlayed, tl.rank, tl.getStatByEnum(stat)!.toDouble())];
|
||||
for (var stat in Stats.values) statsMap[stat] = [for (var tl in states[season]) if (tl.getStatByEnum(stat) != null && tl.getStatByEnum(stat) != -1.00) _HistoryChartSpot(tl.timestamp, tl.gamesPlayed, tl.rank, tl.getStatByEnum(stat)!.toDouble())];
|
||||
historyData[season] = statsMap;
|
||||
}
|
||||
}
|
||||
fetchData = false;
|
||||
|
||||
historyPlayerUsername.value = await teto.getNicknameByID(widget.searchFor);
|
||||
historyPlayerUsername.value = await teto.getNicknameByID(playerID);
|
||||
|
||||
return historyData;
|
||||
}
|
||||
|
@ -234,7 +237,7 @@ class _DestinationGraphsState extends State<DestinationGraphs> {
|
|||
trendlines:<Trendline>[
|
||||
Trendline(
|
||||
isVisible: _smooth,
|
||||
period: (selectedGraph.length/175).floor(),
|
||||
period: (selectedGraph.length/100).floor(),
|
||||
type: TrendlineType.movingAverage,
|
||||
color: Theme.of(context).colorScheme.primary)
|
||||
],
|
||||
|
@ -250,7 +253,7 @@ class _DestinationGraphsState extends State<DestinationGraphs> {
|
|||
trendlines:<Trendline>[
|
||||
Trendline(
|
||||
isVisible: _smooth,
|
||||
period: (selectedGraph.length/175).floor(),
|
||||
period: (selectedGraph.length/100).floor(),
|
||||
type: TrendlineType.movingAverage,
|
||||
color: Theme.of(context).colorScheme.primary)
|
||||
],
|
||||
|
@ -532,7 +535,16 @@ class _DestinationGraphsState extends State<DestinationGraphs> {
|
|||
);
|
||||
});
|
||||
}, icon: Icon(Icons.filter_alt)),
|
||||
IconButton(onPressed: () => _zoomPanBehavior.reset(), icon: const Icon(Icons.refresh), alignment: Alignment.center,)
|
||||
IconButton(onPressed: () => _zoomPanBehavior.reset(), icon: const Icon(Icons.refresh), alignment: Alignment.center,),
|
||||
if (graph == Graph.history) ElevatedButton.icon(
|
||||
onPressed: (){
|
||||
setState(() {
|
||||
fetchData = true;
|
||||
});
|
||||
},
|
||||
label: Text(t.graphsDestination.fetchAndsaveTLHistory),
|
||||
icon: Icon(Icons.download),
|
||||
)
|
||||
],
|
||||
),
|
||||
),
|
||||
|
@ -581,6 +593,11 @@ class _DestinationGraphsState extends State<DestinationGraphs> {
|
|||
),
|
||||
);
|
||||
}
|
||||
|
||||
void markNeedsBuild() {
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
class _HistoryChartSpot{
|
||||
|
|
|
@ -447,7 +447,7 @@ class _DestinationSettings extends State<DestinationSettings> with SingleTickerP
|
|||
text: TextSpan(
|
||||
style: TextStyle(fontFamily: "Eurostile Round", color: Colors.white),
|
||||
children: [
|
||||
TextSpan(text: "${bytesToSize(snapshot.data!.$1)} ", style: TextStyle(fontFamily: "Eurostile Round Extended", fontSize: 28)),
|
||||
TextSpan(text: "${snapshot.data!.$1 == -1 ? "???" : bytesToSize(snapshot.data!.$1)} ", style: TextStyle(fontFamily: "Eurostile Round Extended", fontSize: 28)),
|
||||
TextSpan(text: "${t.settingsDestination.bytesOfDataStored}\n"),
|
||||
TextSpan(text: "${intf.format(snapshot.data!.$2)} ", style: TextStyle(fontFamily: "Eurostile Round Extended", fontSize: 28)),
|
||||
TextSpan(text: "${t.settingsDestination.TLrecordsSaved}\n"),
|
||||
|
@ -457,7 +457,7 @@ class _DestinationSettings extends State<DestinationSettings> with SingleTickerP
|
|||
)
|
||||
);
|
||||
}
|
||||
if (snapshot.hasError){ return FutureError(snapshot); }
|
||||
if (snapshot.hasError){ return SizedBox(height: 500.0, child: FutureError(snapshot)); }
|
||||
}
|
||||
return Text("huh?");
|
||||
}
|
||||
|
|
|
@ -41,7 +41,6 @@ Future<FetchResults> getData(String searchFor, {bool withHistory = false}) async
|
|||
}else{
|
||||
player = await teto.fetchPlayer(searchFor); // Otherwise it's probably a user id or username
|
||||
}
|
||||
|
||||
}on TetrioPlayerNotExist{
|
||||
return FetchResults(false, null, [], null, null, null, null, null, false, TetrioPlayerNotExist());
|
||||
}
|
||||
|
@ -62,7 +61,7 @@ Future<FetchResults> getData(String searchFor, {bool withHistory = false}) async
|
|||
cutoffs = requests.elementAtOrNull(2);
|
||||
averages = requests.elementAtOrNull(3);
|
||||
|
||||
if(withHistory) await teto.fetchAndsaveTLHistory(player.userId, 1); // Retrieve if needed
|
||||
if(withHistory) await teto.fetchAndsaveS1TLHistory(player.userId); // Retrieve if needed
|
||||
} on Exception catch (e) {
|
||||
return FetchResults(false, null, [], null, null, null, null, null, false, e);
|
||||
}
|
||||
|
|
|
@ -57,44 +57,38 @@ class SprintAndBlitzState extends State<SprintAndBlitzView> {
|
|||
constraints: const BoxConstraints(maxWidth: 600),
|
||||
child: SingleChildScrollView(
|
||||
padding: const EdgeInsets.all(16),
|
||||
child: Column(
|
||||
mainAxisSize: MainAxisSize.min,
|
||||
child: Table(
|
||||
defaultVerticalAlignment: TableCellVerticalAlignment.middle,
|
||||
border: TableBorder.all(color: Colors.grey.shade900),
|
||||
columnWidths: const {0: FixedColumnWidth(48)},
|
||||
children: [
|
||||
Table(
|
||||
defaultVerticalAlignment: TableCellVerticalAlignment.middle,
|
||||
border: TableBorder.all(color: Colors.grey.shade900),
|
||||
columnWidths: const {0: FixedColumnWidth(48)},
|
||||
TableRow(
|
||||
children: [
|
||||
TableRow(
|
||||
children: [
|
||||
Text(t.rank, textAlign: TextAlign.center, style: const TextStyle(fontFamily: "Eurostile Round", fontSize: 14, fontWeight: FontWeight.w500, color: Colors.white)),
|
||||
Padding(
|
||||
padding: const EdgeInsets.only(right: 8.0),
|
||||
child: Text(t.gamemodes["40l"]!, textAlign: TextAlign.right, style: TextStyle(fontFamily: bigScreen ? "Eurostile Round" : "Eurostile Round Condensed", fontSize: 28, fontWeight: FontWeight.w500, color: Colors.white)),
|
||||
),
|
||||
Padding(
|
||||
padding: const EdgeInsets.only(right: 8.0),
|
||||
child: Text(t.gamemodes["blitz"]!, textAlign: TextAlign.right, style: TextStyle(fontFamily: bigScreen ? "Eurostile Round" : "Eurostile Round Condensed", fontSize: 28, fontWeight: FontWeight.w500, color: Colors.white)),
|
||||
),
|
||||
]
|
||||
Text(t.rank, textAlign: TextAlign.center, style: const TextStyle(fontFamily: "Eurostile Round", fontSize: 14, fontWeight: FontWeight.w500, color: Colors.white)),
|
||||
Padding(
|
||||
padding: const EdgeInsets.only(right: 8.0),
|
||||
child: Text(t.gamemodes["40l"]!, textAlign: TextAlign.right, style: TextStyle(fontFamily: bigScreen ? "Eurostile Round" : "Eurostile Round Condensed", fontSize: 28, fontWeight: FontWeight.w500, color: Colors.white)),
|
||||
),
|
||||
for (MapEntry<String, Duration> sprintEntry in sprintAverages.entries) TableRow(
|
||||
decoration: BoxDecoration(gradient: LinearGradient(colors: [rankColors[sprintEntry.key]!.withAlpha(100), rankColors[sprintEntry.key]!.withAlpha(200)])),
|
||||
children: [
|
||||
Container(decoration: BoxDecoration(boxShadow: [BoxShadow(color: Colors.black.withAlpha(132), blurRadius: 32.0, blurStyle: BlurStyle.inner)]), child: Image.asset("res/tetrio_tl_alpha_ranks/${sprintEntry.key}.png", height: 48)),
|
||||
Padding(
|
||||
padding: const EdgeInsets.only(right: 8.0),
|
||||
child: Text(getALittleBitMoreNormalTime(sprintEntry.value), textAlign: TextAlign.right, style: TextStyle(fontFamily: bigScreen ? "Eurostile Round" : "Eurostile Round Condensed", fontSize: 28, fontWeight: FontWeight.w500, color: Colors.white, shadows: textShadow)),
|
||||
),
|
||||
Padding(
|
||||
padding: const EdgeInsets.only(right: 8.0),
|
||||
child: Text(NumberFormat.decimalPattern().format(blitzAverages[sprintEntry.key]), textAlign: TextAlign.right, style: TextStyle(fontFamily: bigScreen ? "Eurostile Round" : "Eurostile Round Condensed", fontSize: 28, fontWeight: FontWeight.w500, color: Colors.white, shadows: textShadow)),
|
||||
),
|
||||
]
|
||||
)
|
||||
],
|
||||
Padding(
|
||||
padding: const EdgeInsets.only(right: 8.0),
|
||||
child: Text(t.gamemodes["blitz"]!, textAlign: TextAlign.right, style: TextStyle(fontFamily: bigScreen ? "Eurostile Round" : "Eurostile Round Condensed", fontSize: 28, fontWeight: FontWeight.w500, color: Colors.white)),
|
||||
),
|
||||
]
|
||||
),
|
||||
Text(t.sprintAndBlitsRelevance(date: dateFormat.format(DateTime(2024, 8, 25))))
|
||||
for (MapEntry<String, Duration> sprintEntry in sprintAverages.entries) TableRow(
|
||||
decoration: BoxDecoration(gradient: LinearGradient(colors: [rankColors[sprintEntry.key]!.withAlpha(100), rankColors[sprintEntry.key]!.withAlpha(200)])),
|
||||
children: [
|
||||
Container(decoration: BoxDecoration(boxShadow: [BoxShadow(color: Colors.black.withAlpha(132), blurRadius: 32.0, blurStyle: BlurStyle.inner)]), child: Image.asset("res/tetrio_tl_alpha_ranks/${sprintEntry.key}.png", height: 48)),
|
||||
Padding(
|
||||
padding: const EdgeInsets.only(right: 8.0),
|
||||
child: Text(getALittleBitMoreNormalTime(sprintEntry.value), textAlign: TextAlign.right, style: TextStyle(fontFamily: bigScreen ? "Eurostile Round" : "Eurostile Round Condensed", fontSize: 28, fontWeight: FontWeight.w500, color: Colors.white, shadows: textShadow)),
|
||||
),
|
||||
Padding(
|
||||
padding: const EdgeInsets.only(right: 8.0),
|
||||
child: Text(NumberFormat.decimalPattern().format(blitzAverages[sprintEntry.key]), textAlign: TextAlign.right, style: TextStyle(fontFamily: bigScreen ? "Eurostile Round" : "Eurostile Round Condensed", fontSize: 28, fontWeight: FontWeight.w500, color: Colors.white, shadows: textShadow)),
|
||||
),
|
||||
]
|
||||
)
|
||||
],
|
||||
),
|
||||
),
|
||||
|
|
|
@ -1,4 +1,5 @@
|
|||
import 'package:flutter/material.dart';
|
||||
import 'package:intl/intl.dart';
|
||||
import 'package:tetra_stats/data_objects/beta_record.dart';
|
||||
import 'package:tetra_stats/gen/strings.g.dart';
|
||||
import 'package:tetra_stats/utils/numers_formats.dart';
|
||||
|
@ -9,8 +10,8 @@ import 'package:tetra_stats/widgets/text_timestamp.dart';
|
|||
class BetaLeagueEntryThingy extends StatelessWidget{
|
||||
final BetaRecord record;
|
||||
final String userID;
|
||||
// TODO: Rating delta string is too long for small screens
|
||||
const BetaLeagueEntryThingy(this.record, this.userID);
|
||||
final bool wide;
|
||||
const BetaLeagueEntryThingy(this.record, this.userID, this.wide);
|
||||
|
||||
TextSpan matchResult(String result){
|
||||
return switch(result){
|
||||
|
@ -57,6 +58,7 @@ class BetaLeagueEntryThingy extends StatelessWidget{
|
|||
|
||||
@override
|
||||
Widget build(BuildContext context) {
|
||||
NumberFormat diff = wide ? fDiff : comparef2;
|
||||
double? deltaTR = (record.extras.league[userID]?[1]?.tr != null && record.extras.league[userID]?[0]?.tr != null) ? record.extras.league[userID]![1]!.tr - record.extras.league[userID]![0]!.tr : null;
|
||||
double? deltaGlicko = (record.extras.league[userID]?[1]?.glicko != null && record.extras.league[userID]?[0]?.glicko != null) ? record.extras.league[userID]![1]!.glicko - record.extras.league[userID]![0]!.glicko : null;
|
||||
double? deltaRD = (record.extras.league[userID]?[1]?.rd != null && record.extras.league[userID]?[0]?.rd != null) ? record.extras.league[userID]![1]!.rd - record.extras.league[userID]![0]!.rd : null;
|
||||
|
@ -88,7 +90,7 @@ class BetaLeagueEntryThingy extends StatelessWidget{
|
|||
text: ", ${timestamp(record.ts)}\n"
|
||||
),
|
||||
TextSpan(
|
||||
text: deltaTR != null ? "${fDiff.format(deltaTR)} TR" : "??? TR",
|
||||
text: deltaTR != null ? "${diff.format(deltaTR)} TR" : "??? TR",
|
||||
style: TextStyle(
|
||||
color: deltaColor(deltaTR)
|
||||
)
|
||||
|
@ -97,7 +99,7 @@ class BetaLeagueEntryThingy extends StatelessWidget{
|
|||
text: ", "
|
||||
),
|
||||
TextSpan(
|
||||
text: deltaGlicko != null ? "${fDiff.format(deltaGlicko)} Glicko" : "??? Glicko",
|
||||
text: deltaGlicko != null ? "${diff.format(deltaGlicko)} Glicko" : "??? Glicko",
|
||||
style: TextStyle(
|
||||
color: deltaColor(deltaGlicko)
|
||||
)
|
||||
|
@ -106,7 +108,7 @@ class BetaLeagueEntryThingy extends StatelessWidget{
|
|||
text: ", "
|
||||
),
|
||||
TextSpan(
|
||||
text: deltaRD != null ? "${fDiff.format(deltaRD)} RD" : "??? RD",
|
||||
text: deltaRD != null ? "${diff.format(deltaRD)} RD" : "??? RD",
|
||||
style: TextStyle(
|
||||
color: Colors.grey
|
||||
)
|
||||
|
|
|
@ -65,7 +65,7 @@ class TLRatingThingy extends StatelessWidget{
|
|||
} : [TextSpan(text: "---\n", style: TextStyle(fontFamily: "Eurostile Round Extended", fontSize: bigScreen ? 42 : 28, color: Colors.grey)), TextSpan(text: t.gamesUntilRanked(left: 10-tlData.gamesPlayed), style: const TextStyle(color: Colors.grey, fontSize: 14)),]
|
||||
)
|
||||
),
|
||||
if (oldTl != null) RichText(
|
||||
if (oldTl != null && oldTl!.tr != -1.0) RichText(
|
||||
textAlign: TextAlign.center,
|
||||
softWrap: true,
|
||||
text: TextSpan(
|
||||
|
|
|
@ -103,7 +103,7 @@ class _TLRecordsState extends State<TLRecords> {
|
|||
),
|
||||
),
|
||||
itemBuilder: (BuildContext context, int index){
|
||||
return BetaLeagueEntryThingy(records[index], widget.userID);
|
||||
return BetaLeagueEntryThingy(records[index], widget.userID, MediaQuery.of(context).size.width >= 768.0);
|
||||
}
|
||||
),
|
||||
);
|
||||
|
|
|
@ -47,7 +47,7 @@ class TetraLeagueThingy extends StatelessWidget{
|
|||
message: "${t.stats.glixare.full}",
|
||||
child: Tooltip(child: Text(" ${t.stats.glixare.short}", style: TextStyle(fontSize: width > 768.0 ? 21 : 18, color: league.gxe.isNegative ? Colors.grey : Colors.white)), message: "Glixare")
|
||||
),
|
||||
if (toCompare != null) Text(" (${comparef.format(league.gxe-toCompare!.gxe)})", textAlign: TextAlign.right, style: TextStyle(fontSize: width > 768.0 ? 21 : 18, color: getDifferenceColor(league.gxe-toCompare!.gxe))),
|
||||
if (toCompare != null) Text(toCompare!.gxe != -1 ? " (${comparef.format(league.gxe-toCompare!.gxe)})" : "(---)", textAlign: TextAlign.right, style: TextStyle(fontSize: width > 768.0 ? 21 : 18, color: toCompare!.gxe != -1 ? getDifferenceColor(league.gxe-toCompare!.gxe) : Colors.grey)),
|
||||
if (lbPos != null) Text(lbPos?.glixare != null ? (lbPos!.glixare!.position >= 1000 ? " (${t.top} ${f2.format(lbPos!.glixare!.percentage*100)}%)" : " (№ ${lbPos!.glixare!.position})") : "(№ ---)", style: TextStyle(color: lbPos?.glixare != null ? getColorOfRank(lbPos!.glixare!.position) : null))
|
||||
]),
|
||||
];
|
||||
|
@ -60,7 +60,7 @@ class TetraLeagueThingy extends StatelessWidget{
|
|||
child: Column(
|
||||
children: [
|
||||
TLRatingThingy(userID: league.id, tlData: league, oldTl: toCompare, showPositions: true),
|
||||
if (league.gamesPlayed > 9) TLProgress(
|
||||
if (league.gamesPlayed > 9 && league.percentileRank != "z") TLProgress(
|
||||
tlData: league,
|
||||
previousRankTRcutoff: cutoffs != null ? cutoffs!.tr[league.rank != "z" ? league.rank : league.percentileRank] : null,
|
||||
nextRankTRcutoff: cutoffs != null ? cutoffs!.tr[ranks2[ranks2.indexOf(league.rank != "z" ? league.rank : league.percentileRank)-1]] : null,
|
||||
|
|
|
@ -20,6 +20,8 @@ static void my_application_activate(GApplication* application) {
|
|||
GtkWindow* window =
|
||||
GTK_WINDOW(gtk_application_window_new(GTK_APPLICATION(application)));
|
||||
|
||||
gtk_window_set_icon_from_file(GTK_WINDOW(window),"res/icons/app.png",NULL);
|
||||
|
||||
// Use a header bar when running in GNOME as this is the common style used
|
||||
// by applications and is the setup most users will be using (e.g. Ubuntu
|
||||
// desktop).
|
||||
|
|
|
@ -0,0 +1,12 @@
|
|||
import Cocoa
|
||||
import FlutterMacOS
|
||||
import XCTest
|
||||
|
||||
class RunnerTests: XCTestCase {
|
||||
|
||||
func testExample() {
|
||||
// If you add code to the Runner application, consider adding tests here.
|
||||
// See https://developer.apple.com/documentation/xctest for more information about using XCTest.
|
||||
}
|
||||
|
||||
}
|
16
pubspec.lock
16
pubspec.lock
|
@ -328,6 +328,14 @@ packages:
|
|||
description: flutter
|
||||
source: sdk
|
||||
version: "0.0.0"
|
||||
flutter_to_debian:
|
||||
dependency: "direct main"
|
||||
description:
|
||||
name: flutter_to_debian
|
||||
sha256: d23534407334b331ce20fbaa8395b9ecc255d0c047136b8998715f36933ee696
|
||||
url: "https://pub.dev"
|
||||
source: hosted
|
||||
version: "2.0.2"
|
||||
flutter_web_plugins:
|
||||
dependency: transitive
|
||||
description: flutter
|
||||
|
@ -509,6 +517,14 @@ packages:
|
|||
url: "https://pub.dev"
|
||||
source: hosted
|
||||
version: "1.0.5"
|
||||
mime_type:
|
||||
dependency: transitive
|
||||
description:
|
||||
name: mime_type
|
||||
sha256: d652b613e84dac1af28030a9fba82c0999be05b98163f9e18a0849c6e63838bb
|
||||
url: "https://pub.dev"
|
||||
source: hosted
|
||||
version: "1.0.1"
|
||||
node_preamble:
|
||||
dependency: transitive
|
||||
description:
|
||||
|
|
|
@ -2,7 +2,7 @@ name: tetra_stats
|
|||
description: Track your and other player stats in TETR.IO
|
||||
publish_to: 'none'
|
||||
|
||||
version: 2.0.2+43
|
||||
version: 2.0.3+44
|
||||
|
||||
environment:
|
||||
sdk: '>=3.0.0'
|
||||
|
@ -46,6 +46,7 @@ dependencies:
|
|||
flutter_layout_grid: ^2.0.0
|
||||
go_router: ^13.0.0
|
||||
syncfusion_flutter_charts: ^24.2.9
|
||||
flutter_to_debian: ^2.0.2
|
||||
|
||||
dev_dependencies:
|
||||
flutter_test:
|
||||
|
|
|
@ -172,7 +172,7 @@
|
|||
"refresh": "Обновить"
|
||||
},
|
||||
"graphsDestination": {
|
||||
"fetchAndsaveTLHistory": "Получить историю игрока",
|
||||
"fetchAndsaveTLHistory": "Получить историю",
|
||||
"fetchAndSaveOldTLmatches": "Получить историю матчей Тетра Лиги",
|
||||
"fetchAndsaveTLHistoryResult": "${number} состояний было найдено",
|
||||
"fetchAndSaveOldTLmatchesResult": "${number} матчей было найдено",
|
||||
|
|
|
@ -131,7 +131,7 @@
|
|||
}
|
||||
</style>
|
||||
<!-- This script adds the flutter initialization JS code -->
|
||||
<script src="flutter.js?version=2.0.2" defer></script>
|
||||
<script src="flutter.js?version=2.0.3" defer></script>
|
||||
</head>
|
||||
<body>
|
||||
<div id="preloader">
|
||||
|
|
Loading…
Reference in New Issue