diff --git a/README.md b/README.md
index c189774..7d7b11a 100644
--- a/README.md
+++ b/README.md
@@ -1,26 +1,22 @@
# Tetra Stats
-
Track your and other players stats in TETR.IO
+Track your and other players stats in TETR.IO
-![Screenshot of the app](https://imgur.com/CKGYyBg.png)
+You can [download an app](https://github.com/dan63047/TetraStats/releases), or [use web version](https://ts.dan63.by).
-You can [try it out right now](https://ts.dan63.by)!!! (web version)
+![Screenshot of the app 1](https://imgur.com/CKGYyBg.png)
-If you want an app, you can find it [here](https://github.com/dan63047/TetraStats/releases)!
# Available functionality
- Advanced stats for players
-- Rank cutoffs and averages
-- Sqlite database, that can store all data
+- Ranks cutoffs
+- Minimums, averages, and maximums for every stat of every rank, as well, as whole leaderboard
+- Chart for analyzing tetra league state
+- Local database, that can store players data
- Comparison to players, rank averages, and player stats from the past
- Stats Calculator
- Player history in charts
-# I forgorπ to do
-- UI Animations
-- im still not rendering distinguishment
-
----
-
-Special thanks to kerrmunism for formulas
-
-and to osk for TETR.IO
\ No newline at end of file
+# Special thanks
+- **kerrmunism** β formulas
+- **p1nkl0bst3r** β providing players history
+- **osk** and his team β TETR.IO
\ No newline at end of file
diff --git a/lib/data_objects/tetrio.dart b/lib/data_objects/tetrio.dart
index 6a4fbfd..cfb86ba 100644
--- a/lib/data_objects/tetrio.dart
+++ b/lib/data_objects/tetrio.dart
@@ -1,3 +1,5 @@
+// ignore_for_file: hash_and_equals
+
import 'dart:math';
import 'package:flutter/foundation.dart';
import 'package:flutter/material.dart';
@@ -533,9 +535,9 @@ class EstTr {
statrank = 11.2 * atan((srarea - 93) / 130) + 1;
if (statrank <= 0) statrank = 0.001;
estglicko = (4.0867 * srarea + 186.68);
- double temp = (1500 - estglicko) * pi;
- double temp2 = pow((15.9056943314 * (pow(_rd, 2)) + 3527584.25978), 0.5) as double;
- double temp3 = 1 + pow(10, (temp / temp2)) as double;
+ // double temp = (1500 - estglicko) * pi;
+ // double temp2 = pow((15.9056943314 * (pow(_rd, 2)) + 3527584.25978), 0.5) as double;
+ // double temp3 = 1 + pow(10, (temp / temp2)) as double;
//esttr = 25000 / temp3;
double ntemp = _pps*(150+(((_vs/_apm) - 1.66)*35))+_app*290+_dsp*700;
esttr = 25000 /
diff --git a/lib/gen/strings.g.dart b/lib/gen/strings.g.dart
index da4e39a..559f23c 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: 896 (448 per locale)
+/// Strings: 898 (449 per locale)
///
-/// Built on 2023-08-20 at 21:53 UTC
+/// Built on 2023-08-21 at 09:52 UTC
// coverage:ignore-file
// ignore_for_file: type=lint
@@ -160,6 +160,7 @@ class _StringsEn implements BaseTranslations {
String get sprint => '40 Lines';
String get blitz => 'Blitz';
String get other => 'Other';
+ String get distinguishment => 'Distinguishment';
String get zen => 'Zen';
String get bio => 'Bio';
String get openSearch => 'Search player';
@@ -683,6 +684,7 @@ class _StringsRu implements _StringsEn {
@override String get sprint => '40 Π»ΠΈΠ½ΠΈΠΉ';
@override String get blitz => 'ΠΠ»ΠΈΡ';
@override String get other => 'ΠΡΡΠ³ΠΎΠ΅';
+ @override String get distinguishment => 'ΠΠ°ΡΠ»ΡΠ³Π°';
@override String get zen => 'ΠΠ·Π΅Π½';
@override String get bio => 'ΠΠΈΠΎΠ³ΡΠ°ΡΠΈΡ';
@override String get openSearch => 'ΠΡΠΊΠ°ΡΡ ΠΈΠ³ΡΠΎΠΊΠ°';
@@ -1185,6 +1187,7 @@ extension on _StringsEn {
case 'sprint': return '40 Lines';
case 'blitz': return 'Blitz';
case 'other': return 'Other';
+ case 'distinguishment': return 'Distinguishment';
case 'zen': return 'Zen';
case 'bio': return 'Bio';
case 'openSearch': return 'Search player';
@@ -1643,6 +1646,7 @@ extension on _StringsRu {
case 'sprint': return '40 Π»ΠΈΠ½ΠΈΠΉ';
case 'blitz': return 'ΠΠ»ΠΈΡ';
case 'other': return 'ΠΡΡΠ³ΠΎΠ΅';
+ case 'distinguishment': return 'ΠΠ°ΡΠ»ΡΠ³Π°';
case 'zen': return 'ΠΠ·Π΅Π½';
case 'bio': return 'ΠΠΈΠΎΠ³ΡΠ°ΡΠΈΡ';
case 'openSearch': return 'ΠΡΠΊΠ°ΡΡ ΠΈΠ³ΡΠΎΠΊΠ°';
diff --git a/lib/main.dart b/lib/main.dart
index 4c48be5..d6d0222 100644
--- a/lib/main.dart
+++ b/lib/main.dart
@@ -29,7 +29,7 @@ void main() async {
LocaleSettings.setLocaleRaw(locale);
}
runApp(TranslationProvider(
- child: MyApp(),
+ child: const MyApp(),
));
}
@@ -41,7 +41,7 @@ class MyApp extends StatelessWidget {
return MaterialApp(
title: "Tetra Stats",
home: const MainView(),
- scrollBehavior: MaterialScrollBehavior().copyWith(
+ scrollBehavior: const MaterialScrollBehavior().copyWith(
dragDevices: {PointerDeviceKind.mouse, PointerDeviceKind.touch, PointerDeviceKind.stylus, PointerDeviceKind.unknown},
),
locale: TranslationProvider.of(context).flutterLocale,
diff --git a/lib/views/compare_view.dart b/lib/views/compare_view.dart
index 918fd08..c553adb 100644
--- a/lib/views/compare_view.dart
+++ b/lib/views/compare_view.dart
@@ -250,7 +250,7 @@ class CompareState extends State {
titleRedSide = "${theRedSide[2].apm} APM, ${theRedSide[2].pps} PPS, ${theRedSide[2].vs} VS";
break;
case Mode.averages:
- titleRedSide = t.averageXrank(rankLetter: theRedSide[2].rank.toUpperCase());;
+ titleRedSide = t.averageXrank(rankLetter: theRedSide[2].rank.toUpperCase());
break;
}
return Scaffold(
@@ -863,7 +863,7 @@ class PlayerSelector extends StatelessWidget {
final Function fetch;
final Function change;
final Function updateState;
- PlayerSelector(
+ const PlayerSelector(
{super.key,
required this.data,
required this.mode,
diff --git a/lib/views/main_view.dart b/lib/views/main_view.dart
index 5728b81..5e8ccf6 100644
--- a/lib/views/main_view.dart
+++ b/lib/views/main_view.dart
@@ -1,6 +1,7 @@
import 'dart:io';
import 'package:flutter/foundation.dart';
import 'package:flutter/material.dart';
+import 'package:flutter_svg/flutter_svg.dart';
import 'package:intl/intl.dart';
import 'dart:math';
import 'package:fl_chart/fl_chart.dart';
@@ -331,7 +332,7 @@ class _MainState extends State with SingleTickerProviderStateMixin {
? snapshot.data![1]['blitz'][0]
: null),
_OtherThingy(
- zen: snapshot.data![1]['zen'], bio: snapshot.data![0].bio)
+ zen: snapshot.data![1]['zen'], bio: snapshot.data![0].bio, distinguishment: snapshot.data![0].distinguishment,)
],
),
),
@@ -581,7 +582,7 @@ class _HistoryChartThigy extends StatelessWidget{
bottomTitles: AxisTitles(sideTitles: SideTitles(interval: xInterval, showTitles: true, reservedSize: 30, getTitlesWidget: (double value, TitleMeta meta){
return value != meta.min && value != meta.max ? SideTitleWidget(
axisSide: meta.axisSide,
- child: Text(DateFormat.yMMMd(LocaleSettings.currentLocale.languageCode) .format(DateTime.fromMillisecondsSinceEpoch(value.floor()))),
+ child: Text(DateFormat.yMMMd(LocaleSettings.currentLocale.languageCode).format(DateTime.fromMillisecondsSinceEpoch(value.floor()))),
) : Container();
})),
leftTitles: AxisTitles(sideTitles: SideTitles(showTitles: true, reservedSize: leftSpace, getTitlesWidget: (double value, TitleMeta meta){
@@ -628,7 +629,12 @@ class _RecordThingy extends StatelessWidget {
fontFamily: "Eurostile Round Extended",
fontSize: bigScreen ? 42 : 28)),
if (record!.stream.contains("40l"))
- Text(
+ if (record!.endContext!.finalTime.inMicroseconds > 60000000) Text(
+ "${(record!.endContext!.finalTime.inMicroseconds/1000000/60).floor()}:${(f2.format(record!.endContext!.finalTime.inMicroseconds /1000000 % 60))}",
+ style: TextStyle(
+ fontFamily: "Eurostile Round Extended",
+ fontSize: bigScreen ? 42 : 28))
+ else Text(
timeInSec.format(
record!.endContext!.finalTime.inMicroseconds /
1000000),
@@ -936,9 +942,34 @@ class _RecordThingy extends StatelessWidget {
class _OtherThingy extends StatelessWidget {
final TetrioZen? zen;
final String? bio;
- const _OtherThingy({Key? key, required this.zen, required this.bio})
+ final Distinguishment? distinguishment;
+ const _OtherThingy({Key? key, required this.zen, required this.bio, required this.distinguishment})
: super(key: key);
+ List getDistinguishmentSetOfWidgets(String text) {
+ var exploded = text.split(" ");
+ List result = [];
+ for (String shit in exploded){
+ switch (shit) {
+ case "%osk%":
+ result.add(WidgetSpan(child: Padding(
+ padding: const EdgeInsets.only(left: 8),
+ child: SvgPicture.asset("res/icons/osk.svg", height: 28),
+ )));
+ break;
+ case "%tetrio%":
+ result.add(WidgetSpan(child: Padding(
+ padding: const EdgeInsets.only(left: 8),
+ child: SvgPicture.asset("res/icons/tetrio-logo.svg", height: 28),
+ )));
+ break;
+ default:
+ result.add(TextSpan(text: " $shit", style: const TextStyle(fontSize: 28, fontWeight: FontWeight.bold)));
+ }
+ }
+ return result;
+ }
+
@override
Widget build(BuildContext context) {
return LayoutBuilder(builder: (context, constraints) {
@@ -949,27 +980,19 @@ class _OtherThingy extends StatelessWidget {
itemBuilder: (BuildContext context, int index) {
return Column(
children: [
- Text(t.other,
- style: TextStyle(
- fontFamily: "Eurostile Round Extended",
- fontSize: bigScreen ? 42 : 28)),
- if (zen != null)
+ if (distinguishment != null)
Padding(
- padding: const EdgeInsets.fromLTRB(0, 48, 0, 48),
+ padding: const EdgeInsets.fromLTRB(0, 0, 0, 48),
child: Column(
children: [
- Text(t.zen,
- style: TextStyle(
- fontFamily: "Eurostile Round Extended",
- fontSize: bigScreen ? 42 : 28)),
- Text(
- "${t.statCellNum.level} ${NumberFormat.decimalPattern().format(zen!.level)}",
- style: TextStyle(
- fontFamily: "Eurostile Round Extended",
- fontSize: bigScreen ? 42 : 28)),
- Text(
- "${t.statCellNum.score} ${NumberFormat.decimalPattern().format(zen!.score)}",
- style: const TextStyle(fontSize: 18)),
+ Text(t.distinguishment, style: TextStyle(fontFamily: "Eurostile Round Extended", fontSize: bigScreen ? 42 : 28)),
+ RichText(
+ text: TextSpan(
+ style: DefaultTextStyle.of(context).style,
+ children: getDistinguishmentSetOfWidgets(distinguishment!.header!),
+ ),
+ ),
+ Text(distinguishment!.footer!, style: const TextStyle(fontSize: 18)),
],
),
),
@@ -978,14 +1001,23 @@ class _OtherThingy extends StatelessWidget {
padding: const EdgeInsets.fromLTRB(0, 0, 0, 48),
child: Column(
children: [
- Text(t.bio,
- style: TextStyle(
- fontFamily: "Eurostile Round Extended",
- fontSize: bigScreen ? 42 : 28)),
+ Text(t.bio, style: TextStyle(fontFamily: "Eurostile Round Extended",fontSize: bigScreen ? 42 : 28)),
Text(bio!, style: const TextStyle(fontSize: 18)),
],
),
),
+ if (zen != null)
+ Padding(
+ padding: const EdgeInsets.fromLTRB(0, 0, 0, 0),
+ child: Column(
+ children: [
+ Text(t.zen, style: TextStyle(fontFamily: "Eurostile Round Extended", fontSize: bigScreen ? 42 : 28)),
+ Text("${t.statCellNum.level} ${NumberFormat.decimalPattern().format(zen!.level)}", style: const TextStyle(fontSize: 28, fontWeight: FontWeight.bold)),
+ Text("${t.statCellNum.score} ${NumberFormat.decimalPattern().format(zen!.score)}", style: const TextStyle(fontSize: 18)),
+ ],
+ ),
+ ),
+
],
);
},
diff --git a/lib/views/rank_averages_view.dart b/lib/views/rank_averages_view.dart
index 5cf3819..13fe714 100644
--- a/lib/views/rank_averages_view.dart
+++ b/lib/views/rank_averages_view.dart
@@ -1,5 +1,3 @@
-import 'dart:math';
-
import 'package:fl_chart/fl_chart.dart';
import 'package:flutter/material.dart';
import 'package:intl/intl.dart';
@@ -7,9 +5,6 @@ import 'package:tetra_stats/data_objects/tetrio.dart';
//import 'package:tetra_stats/data_objects/tetrio.dart';
import 'package:tetra_stats/gen/strings.g.dart';
import 'package:tetra_stats/views/main_view.dart' show MainView, f4, f2;
-import 'package:tetra_stats/widgets/stat_sell_num.dart';
-import 'package:tetra_stats/widgets/tl_thingy.dart';
-//import 'package:tetra_stats/widgets/tl_thingy.dart';
List chartsShortTitles = [
"TR",
@@ -39,7 +34,7 @@ List chartsShortTitles = [
"Stride - Plonk",
"Opener - Inf. DS"
];
-var chartsShortTitlesDropdowns = [for (String e in chartsShortTitles) DropdownMenuItem(child: Text(e), value: e,)];
+var chartsShortTitlesDropdowns = [for (String e in chartsShortTitles) DropdownMenuItem(value: e,child: Text(e),)];
int chartsIndexX = 0;
int chartsIndexY = 6;
//final DateFormat dateFormat = DateFormat.yMMMd(LocaleSettings.currentLocale.languageCode).add_Hms();
@@ -204,7 +199,7 @@ class RankState extends State with SingleTickerProviderStateMixin {
scatterTouchData: ScatterTouchData(touchTooltipData: ScatterTouchTooltipData(
fitInsideHorizontally: true, fitInsideVertically: true, getTooltipItems: (touchedSpot) {
touchedSpot as _MyScatterSpot;
- return ScatterTooltipItem("${touchedSpot.nickname}\n", textStyle: TextStyle(fontFamily: "Eurostile Round Extended"), children: [TextSpan(text: "${f4.format(touchedSpot.x)} ${chartsShortTitles[chartsIndexX]}\n${f4.format(touchedSpot.y)} ${chartsShortTitles[chartsIndexY]}", style: TextStyle(fontFamily: "Eurostile Round"))]);
+ return ScatterTooltipItem("${touchedSpot.nickname}\n", textStyle: const TextStyle(fontFamily: "Eurostile Round Extended"), children: [TextSpan(text: "${f4.format(touchedSpot.x)} ${chartsShortTitles[chartsIndexX]}\n${f4.format(touchedSpot.y)} ${chartsShortTitles[chartsIndexY]}", style: const TextStyle(fontFamily: "Eurostile Round"))]);
}),
touchCallback:(event, response) {
if (event.runtimeType == FlTapDownEvent && response?.touchedSpot?.spot != null){
@@ -219,7 +214,7 @@ class RankState extends State with SingleTickerProviderStateMixin {
}
},),
),
- swapAnimationDuration: Duration(milliseconds: 150), // Optional
+ swapAnimationDuration: const Duration(milliseconds: 150), // Optional
swapAnimationCurve: Curves.linear, // Optional
),
),
diff --git a/pubspec.lock b/pubspec.lock
index b19d111..95ed1f6 100644
--- a/pubspec.lock
+++ b/pubspec.lock
@@ -299,6 +299,14 @@ packages:
url: "https://pub.dev"
source: hosted
version: "2.0.15"
+ flutter_svg:
+ dependency: "direct main"
+ description:
+ name: flutter_svg
+ sha256: "8c5d68a82add3ca76d792f058b186a0599414f279f00ece4830b9b231b570338"
+ url: "https://pub.dev"
+ source: hosted
+ version: "2.0.7"
flutter_test:
dependency: "direct dev"
description: flutter
@@ -485,6 +493,14 @@ packages:
url: "https://pub.dev"
source: hosted
version: "1.8.3"
+ path_parsing:
+ dependency: transitive
+ description:
+ name: path_parsing
+ sha256: e3e67b1629e6f7e8100b367d3db6ba6af4b1f0bb80f64db18ef1fbabd2fa9ccf
+ url: "https://pub.dev"
+ source: hosted
+ version: "1.0.1"
path_provider:
dependency: "direct main"
description:
@@ -922,6 +938,30 @@ packages:
url: "https://pub.dev"
source: hosted
version: "3.0.7"
+ vector_graphics:
+ dependency: transitive
+ description:
+ name: vector_graphics
+ sha256: "670f6e07aca990b4a2bcdc08a784193c4ccdd1932620244c3a86bb72a0eac67f"
+ url: "https://pub.dev"
+ source: hosted
+ version: "1.1.7"
+ vector_graphics_codec:
+ dependency: transitive
+ description:
+ name: vector_graphics_codec
+ sha256: "7451721781d967db9933b63f5733b1c4533022c0ba373a01bdd79d1a5457f69f"
+ url: "https://pub.dev"
+ source: hosted
+ version: "1.1.7"
+ vector_graphics_compiler:
+ dependency: transitive
+ description:
+ name: vector_graphics_compiler
+ sha256: "80a13c613c8bde758b1464a1755a7b3a8f2b6cec61fbf0f5a53c94c30f03ba2e"
+ url: "https://pub.dev"
+ source: hosted
+ version: "1.1.7"
vector_math:
dependency: "direct main"
description:
diff --git a/pubspec.yaml b/pubspec.yaml
index cf7078e..8767f33 100644
--- a/pubspec.yaml
+++ b/pubspec.yaml
@@ -2,7 +2,7 @@ name: tetra_stats
description: Track your and other player stats in TETR.IO
publish_to: 'none'
-version: 1.0.1+6
+version: 1.1.0+7
environment:
sdk: '>=2.19.6 <3.0.0'
@@ -38,6 +38,7 @@ dependencies:
slang_flutter: ^3.20.0
csv: ^5.0.2
url_launcher: ^6.1.12
+ flutter_svg: any
dev_dependencies:
flutter_test:
@@ -79,6 +80,8 @@ flutter:
- res/avatars/tetrio_anon.png
- res/avatars/tetrio_banned.png
- res/icons/kagari.png
+ - res/icons/osk.svg
+ - res/icons/tetrio-logo.svg
- res/tetrio_tl_alpha_ranks/x.png
- res/tetrio_tl_alpha_ranks/u.png
- res/tetrio_tl_alpha_ranks/ss.png
diff --git a/res/i18n/strings.i18n.json b/res/i18n/strings.i18n.json
index 0e6c384..35af696 100644
--- a/res/i18n/strings.i18n.json
+++ b/res/i18n/strings.i18n.json
@@ -9,6 +9,7 @@
"sprint": "40 Lines",
"blitz": "Blitz",
"other": "Other",
+ "distinguishment": "Distinguishment",
"zen": "Zen",
"bio": "Bio",
"openSearch": "Search player",
diff --git a/res/i18n/strings_ru.i18n.json b/res/i18n/strings_ru.i18n.json
index 70d7942..1eadca7 100644
--- a/res/i18n/strings_ru.i18n.json
+++ b/res/i18n/strings_ru.i18n.json
@@ -9,6 +9,7 @@
"sprint": "40 Π»ΠΈΠ½ΠΈΠΉ",
"blitz": "ΠΠ»ΠΈΡ",
"other": "ΠΡΡΠ³ΠΎΠ΅",
+ "distinguishment": "ΠΠ°ΡΠ»ΡΠ³Π°",
"zen": "ΠΠ·Π΅Π½",
"bio": "ΠΠΈΠΎΠ³ΡΠ°ΡΠΈΡ",
"openSearch": "ΠΡΠΊΠ°ΡΡ ΠΈΠ³ΡΠΎΠΊΠ°",
diff --git a/res/icons/osk.svg b/res/icons/osk.svg
new file mode 100644
index 0000000..da3e6ba
--- /dev/null
+++ b/res/icons/osk.svg
@@ -0,0 +1,83 @@
+
+
+
+
diff --git a/res/icons/tetrio-logo.svg b/res/icons/tetrio-logo.svg
new file mode 100644
index 0000000..c7c6edd
--- /dev/null
+++ b/res/icons/tetrio-logo.svg
@@ -0,0 +1,383 @@
+
+
+
+