1.6.0 ready

This commit is contained in:
dan63047 2024-06-16 20:13:26 +03:00
parent 0262c8dcf9
commit 249c2c4a68
12 changed files with 200 additions and 86 deletions

View File

@ -4,9 +4,9 @@
/// To regenerate, run: `dart run slang` /// To regenerate, run: `dart run slang`
/// ///
/// Locales: 2 /// Locales: 2
/// Strings: 1144 (572 per locale) /// Strings: 1182 (591 per locale)
/// ///
/// Built on 2024-05-28 at 20:38 UTC /// Built on 2024-06-16 at 15:08 UTC
// coverage:ignore-file // coverage:ignore-file
// ignore_for_file: type=lint // ignore_for_file: type=lint
@ -157,6 +157,11 @@ class Translations implements BaseTranslations<AppLocale, Translations> {
String get history => 'History'; String get history => 'History';
String get sprint => '40 Lines'; String get sprint => '40 Lines';
String get blitz => 'Blitz'; String get blitz => 'Blitz';
String get recent => 'Recent';
String get recentRuns => 'Recent runs';
String blitzScore({required Object p}) => '${p} points';
String get openSPreplay => 'Open replay in TETR.IO';
String get downloadSPreplay => 'Download replay';
String get other => 'Other'; String get other => 'Other';
String get distinguishment => 'Distinguishment'; String get distinguishment => 'Distinguishment';
String get zen => 'Zen'; String get zen => 'Zen';
@ -244,14 +249,28 @@ class Translations implements BaseTranslations<AppLocale, Translations> {
String get yourIDAlertTitle => 'Your nickname in TETR.IO'; String get yourIDAlertTitle => 'Your nickname in TETR.IO';
String get yourIDText => 'When app loads, it will retrieve data for this account'; String get yourIDText => 'When app loads, it will retrieve data for this account';
String get language => 'Language'; String get language => 'Language';
String get updateInBackground => 'Update stats in the background';
String get updateInBackgroundDescription => 'While Tetra Stats is running, it can update stats of the current player when cache expires';
String get customization => 'Customization'; String get customization => 'Customization';
String get customizationDescription => 'There is only one toggle, planned to add more settings'; String get customizationDescription => 'Change appearance of different things in Tetra Stats UI';
String get oskKagari => 'Osk Kagari gimmick';
String get oskKagariDescription => 'If on, osk\'s rank on main view will be rendered as :kagari:';
String get AccentColor => 'Accent color';
String get AccentColorDescription => 'Almost all interactive UI elements highlighted with this color';
String get timestamps => 'Timestamps';
String get timestampsDescription => 'You can choose, in which way timestamps shows time';
String get timestampsAbsoluteGMT => 'Absolute (GMT)';
String get timestampsAbsoluteLocalTime => 'Absolute (Your timezone)';
String get timestampsRelative => 'Relative';
String get rating => 'Main representation of rating';
String get ratingDescription => 'TR is not linear, while Glicko does not have boundaries and percentile is volatile';
String get ratingLBposition => 'LB position';
String get sheetbotGraphs => 'Sheetbot-like behavior for radar graphs';
String get sheetbotGraphsDescription => 'If on, points on the graphs can appear on the opposite half of the graph if value is negative';
String get lbStats => 'Show leaderboard based stats'; String get lbStats => 'Show leaderboard based stats';
String get lbStatsDescription => 'That will impact on loading times, but will allow you to see position on LB by stats and comparison with average values'; String get lbStatsDescription => 'That will impact on loading times, but will allow you to see position on LB by stats and comparison with average values';
String get aboutApp => 'About app'; String get aboutApp => 'About app';
String aboutAppText({required Object appName, required Object packageName, required Object version, required Object buildNumber}) => '${appName} (${packageName}) Version ${version} Build ${buildNumber}\n\nDeveloped by dan63047\nFormulas provided by kerrmunism\nHistory provided by p1nkl0bst3r\nTETR.IO replay grabber API by szy'; String aboutAppText({required Object appName, required Object packageName, required Object version, required Object buildNumber}) => '${appName} (${packageName}) Version ${version} Build ${buildNumber}\n\nDeveloped by dan63047\nFormulas provided by kerrmunism\nHistory provided by p1nkl0bst3r\nTETR.IO replay grabber API by szy';
String get oskKagari => 'Osk Kagari gimmick';
String get oskKagariDescription => 'If on, osk\'s rank on main view will be rendered as :kagari:';
String stateViewTitle({required Object nickname, required Object date}) => '${nickname} account on ${date}'; String stateViewTitle({required Object nickname, required Object date}) => '${nickname} account on ${date}';
String statesViewTitle({required Object number, required Object nickname}) => '${number} states of ${nickname} account'; String statesViewTitle({required Object number, required Object nickname}) => '${number} states of ${nickname} account';
String matchesViewTitle({required Object nickname}) => '${nickname} TL matches'; String matchesViewTitle({required Object nickname}) => '${nickname} TL matches';
@ -833,6 +852,11 @@ class _StringsRu implements Translations {
@override String get history => 'История'; @override String get history => 'История';
@override String get sprint => '40 линий'; @override String get sprint => '40 линий';
@override String get blitz => 'Блиц'; @override String get blitz => 'Блиц';
@override String get recent => 'Недавно';
@override String get recentRuns => 'Недавние';
@override String blitzScore({required Object p}) => '${p} очков';
@override String get openSPreplay => 'Открыть повтор в TETR.IO';
@override String get downloadSPreplay => 'Скачать повтор';
@override String get other => 'Другое'; @override String get other => 'Другое';
@override String get distinguishment => 'Заслуга'; @override String get distinguishment => 'Заслуга';
@override String get zen => 'Дзен'; @override String get zen => 'Дзен';
@ -920,14 +944,28 @@ class _StringsRu implements Translations {
@override String get yourIDAlertTitle => 'Ваш ник в TETR.IO'; @override String get yourIDAlertTitle => 'Ваш ник в TETR.IO';
@override String get yourIDText => 'При запуске приложения оно будет получать статистику этого игрока.'; @override String get yourIDText => 'При запуске приложения оно будет получать статистику этого игрока.';
@override String get language => 'Язык (Language)'; @override String get language => 'Язык (Language)';
@override String get updateInBackground => 'Обновлять статистику в фоне';
@override String get updateInBackgroundDescription => 'Пока Tetra Stats работает, он может обновлять статистику самостоятельно когда кеш истекает';
@override String get customization => 'Кастомизация'; @override String get customization => 'Кастомизация';
@override String get customizationDescription => 'Здесь только один переключатель, в планах добавить больше'; @override String get customizationDescription => 'Измените внешний вид пользовательского интерфейса Tetra Stats';
@override String get oskKagari => '"Оск Кагари" прикол';
@override String get oskKagariDescription => 'Если включено, вместо настоящего ранга оска будет рендерится :kagari:';
@override String get AccentColor => 'Цветовой акцент';
@override String get AccentColorDescription => 'Почти все интерактивные элементы пользовательского интерфейса окрашены в этот цвет';
@override String get timestamps => 'Метки времени';
@override String get timestampsDescription => 'Вы можете выбрать, каким образом метки времени показывают время';
@override String get timestampsAbsoluteGMT => 'Абсолютные (GMT)';
@override String get timestampsAbsoluteLocalTime => 'Абсолютные (Ваш часовой пояс)';
@override String get timestampsRelative => 'Относительные';
@override String get rating => 'Основное представление рейтинга';
@override String get ratingDescription => 'TR нелинеен, тогда как Glicko не имеет границ, а положение в таблице лидеров волатильно';
@override String get ratingLBposition => 'Позиция в рейтинге';
@override String get sheetbotGraphs => 'Графики-радары как у sheetBot';
@override String get sheetbotGraphsDescription => 'Если включено, точки на графике могут появляться на противоположной стороне графика если значение отрицательное';
@override String get lbStats => 'Показывать статистику, основанную на рейтинговой таблице'; @override String get lbStats => 'Показывать статистику, основанную на рейтинговой таблице';
@override String get lbStatsDescription => 'Это повлияет на время загрузки, но позволит видеть положение в рейтинге и сравнение со средними значениями по рангу по каждой стате'; @override String get lbStatsDescription => 'Это повлияет на время загрузки, но позволит видеть положение в рейтинге и сравнение со средними значениями по рангу по каждой стате';
@override String get aboutApp => 'О приложении'; @override String get aboutApp => 'О приложении';
@override String aboutAppText({required Object appName, required Object packageName, required Object version, required Object buildNumber}) => '${appName} (${packageName}) Версия ${version} Сборка ${buildNumber}\n\nРазработал dan63047\nФормулы предоставил kerrmunism\nИсторию предоставляет p1nkl0bst3r\nВозможность скачивать повторы из TETR.IO предоставляет szy'; @override String aboutAppText({required Object appName, required Object packageName, required Object version, required Object buildNumber}) => '${appName} (${packageName}) Версия ${version} Сборка ${buildNumber}\n\nРазработал dan63047\nФормулы предоставил kerrmunism\nИсторию предоставляет p1nkl0bst3r\nВозможность скачивать повторы из TETR.IO предоставляет szy';
@override String get oskKagari => '"Оск Кагари" прикол';
@override String get oskKagariDescription => 'Если включено, вместо настоящего ранга оска будет рендерится :kagari:';
@override String stateViewTitle({required Object nickname, required Object date}) => 'Аккаунт ${nickname} ${date}'; @override String stateViewTitle({required Object nickname, required Object date}) => 'Аккаунт ${nickname} ${date}';
@override String statesViewTitle({required Object number, required Object nickname}) => '${number} состояний аккаунта ${nickname}'; @override String statesViewTitle({required Object number, required Object nickname}) => '${number} состояний аккаунта ${nickname}';
@override String matchesViewTitle({required Object nickname}) => 'Матчи аккаунта ${nickname}'; @override String matchesViewTitle({required Object nickname}) => 'Матчи аккаунта ${nickname}';
@ -1489,6 +1527,11 @@ extension on Translations {
case 'history': return 'History'; case 'history': return 'History';
case 'sprint': return '40 Lines'; case 'sprint': return '40 Lines';
case 'blitz': return 'Blitz'; case 'blitz': return 'Blitz';
case 'recent': return 'Recent';
case 'recentRuns': return 'Recent runs';
case 'blitzScore': return ({required Object p}) => '${p} points';
case 'openSPreplay': return 'Open replay in TETR.IO';
case 'downloadSPreplay': return 'Download replay';
case 'other': return 'Other'; case 'other': return 'Other';
case 'distinguishment': return 'Distinguishment'; case 'distinguishment': return 'Distinguishment';
case 'zen': return 'Zen'; case 'zen': return 'Zen';
@ -1588,14 +1631,28 @@ extension on Translations {
case 'yourIDAlertTitle': return 'Your nickname in TETR.IO'; case 'yourIDAlertTitle': return 'Your nickname in TETR.IO';
case 'yourIDText': return 'When app loads, it will retrieve data for this account'; case 'yourIDText': return 'When app loads, it will retrieve data for this account';
case 'language': return 'Language'; case 'language': return 'Language';
case 'updateInBackground': return 'Update stats in the background';
case 'updateInBackgroundDescription': return 'While Tetra Stats is running, it can update stats of the current player when cache expires';
case 'customization': return 'Customization'; case 'customization': return 'Customization';
case 'customizationDescription': return 'There is only one toggle, planned to add more settings'; case 'customizationDescription': return 'Change appearance of different things in Tetra Stats UI';
case 'oskKagari': return 'Osk Kagari gimmick';
case 'oskKagariDescription': return 'If on, osk\'s rank on main view will be rendered as :kagari:';
case 'AccentColor': return 'Accent color';
case 'AccentColorDescription': return 'Almost all interactive UI elements highlighted with this color';
case 'timestamps': return 'Timestamps';
case 'timestampsDescription': return 'You can choose, in which way timestamps shows time';
case 'timestampsAbsoluteGMT': return 'Absolute (GMT)';
case 'timestampsAbsoluteLocalTime': return 'Absolute (Your timezone)';
case 'timestampsRelative': return 'Relative';
case 'rating': return 'Main representation of rating';
case 'ratingDescription': return 'TR is not linear, while Glicko does not have boundaries and percentile is volatile';
case 'ratingLBposition': return 'LB position';
case 'sheetbotGraphs': return 'Sheetbot-like behavior for radar graphs';
case 'sheetbotGraphsDescription': return 'If on, points on the graphs can appear on the opposite half of the graph if value is negative';
case 'lbStats': return 'Show leaderboard based stats'; case 'lbStats': return 'Show leaderboard based stats';
case 'lbStatsDescription': return 'That will impact on loading times, but will allow you to see position on LB by stats and comparison with average values'; case 'lbStatsDescription': return 'That will impact on loading times, but will allow you to see position on LB by stats and comparison with average values';
case 'aboutApp': return 'About app'; case 'aboutApp': return 'About app';
case 'aboutAppText': return ({required Object appName, required Object packageName, required Object version, required Object buildNumber}) => '${appName} (${packageName}) Version ${version} Build ${buildNumber}\n\nDeveloped by dan63047\nFormulas provided by kerrmunism\nHistory provided by p1nkl0bst3r\nTETR.IO replay grabber API by szy'; case 'aboutAppText': return ({required Object appName, required Object packageName, required Object version, required Object buildNumber}) => '${appName} (${packageName}) Version ${version} Build ${buildNumber}\n\nDeveloped by dan63047\nFormulas provided by kerrmunism\nHistory provided by p1nkl0bst3r\nTETR.IO replay grabber API by szy';
case 'oskKagari': return 'Osk Kagari gimmick';
case 'oskKagariDescription': return 'If on, osk\'s rank on main view will be rendered as :kagari:';
case 'stateViewTitle': return ({required Object nickname, required Object date}) => '${nickname} account on ${date}'; case 'stateViewTitle': return ({required Object nickname, required Object date}) => '${nickname} account on ${date}';
case 'statesViewTitle': return ({required Object number, required Object nickname}) => '${number} states of ${nickname} account'; case 'statesViewTitle': return ({required Object number, required Object nickname}) => '${number} states of ${nickname} account';
case 'matchesViewTitle': return ({required Object nickname}) => '${nickname} TL matches'; case 'matchesViewTitle': return ({required Object nickname}) => '${nickname} TL matches';
@ -2081,6 +2138,11 @@ extension on _StringsRu {
case 'history': return 'История'; case 'history': return 'История';
case 'sprint': return '40 линий'; case 'sprint': return '40 линий';
case 'blitz': return 'Блиц'; case 'blitz': return 'Блиц';
case 'recent': return 'Недавно';
case 'recentRuns': return 'Недавние';
case 'blitzScore': return ({required Object p}) => '${p} очков';
case 'openSPreplay': return 'Открыть повтор в TETR.IO';
case 'downloadSPreplay': return 'Скачать повтор';
case 'other': return 'Другое'; case 'other': return 'Другое';
case 'distinguishment': return 'Заслуга'; case 'distinguishment': return 'Заслуга';
case 'zen': return 'Дзен'; case 'zen': return 'Дзен';
@ -2180,14 +2242,28 @@ extension on _StringsRu {
case 'yourIDAlertTitle': return 'Ваш ник в TETR.IO'; case 'yourIDAlertTitle': return 'Ваш ник в TETR.IO';
case 'yourIDText': return 'При запуске приложения оно будет получать статистику этого игрока.'; case 'yourIDText': return 'При запуске приложения оно будет получать статистику этого игрока.';
case 'language': return 'Язык (Language)'; case 'language': return 'Язык (Language)';
case 'updateInBackground': return 'Обновлять статистику в фоне';
case 'updateInBackgroundDescription': return 'Пока Tetra Stats работает, он может обновлять статистику самостоятельно когда кеш истекает';
case 'customization': return 'Кастомизация'; case 'customization': return 'Кастомизация';
case 'customizationDescription': return 'Здесь только один переключатель, в планах добавить больше'; case 'customizationDescription': return 'Измените внешний вид пользовательского интерфейса Tetra Stats';
case 'oskKagari': return '"Оск Кагари" прикол';
case 'oskKagariDescription': return 'Если включено, вместо настоящего ранга оска будет рендерится :kagari:';
case 'AccentColor': return 'Цветовой акцент';
case 'AccentColorDescription': return 'Почти все интерактивные элементы пользовательского интерфейса окрашены в этот цвет';
case 'timestamps': return 'Метки времени';
case 'timestampsDescription': return 'Вы можете выбрать, каким образом метки времени показывают время';
case 'timestampsAbsoluteGMT': return 'Абсолютные (GMT)';
case 'timestampsAbsoluteLocalTime': return 'Абсолютные (Ваш часовой пояс)';
case 'timestampsRelative': return 'Относительные';
case 'rating': return 'Основное представление рейтинга';
case 'ratingDescription': return 'TR нелинеен, тогда как Glicko не имеет границ, а положение в таблице лидеров волатильно';
case 'ratingLBposition': return 'Позиция в рейтинге';
case 'sheetbotGraphs': return 'Графики-радары как у sheetBot';
case 'sheetbotGraphsDescription': return 'Если включено, точки на графике могут появляться на противоположной стороне графика если значение отрицательное';
case 'lbStats': return 'Показывать статистику, основанную на рейтинговой таблице'; case 'lbStats': return 'Показывать статистику, основанную на рейтинговой таблице';
case 'lbStatsDescription': return 'Это повлияет на время загрузки, но позволит видеть положение в рейтинге и сравнение со средними значениями по рангу по каждой стате'; case 'lbStatsDescription': return 'Это повлияет на время загрузки, но позволит видеть положение в рейтинге и сравнение со средними значениями по рангу по каждой стате';
case 'aboutApp': return 'О приложении'; case 'aboutApp': return 'О приложении';
case 'aboutAppText': return ({required Object appName, required Object packageName, required Object version, required Object buildNumber}) => '${appName} (${packageName}) Версия ${version} Сборка ${buildNumber}\n\nРазработал dan63047\nФормулы предоставил kerrmunism\nИсторию предоставляет p1nkl0bst3r\nВозможность скачивать повторы из TETR.IO предоставляет szy'; case 'aboutAppText': return ({required Object appName, required Object packageName, required Object version, required Object buildNumber}) => '${appName} (${packageName}) Версия ${version} Сборка ${buildNumber}\n\nРазработал dan63047\nФормулы предоставил kerrmunism\nИсторию предоставляет p1nkl0bst3r\nВозможность скачивать повторы из TETR.IO предоставляет szy';
case 'oskKagari': return '"Оск Кагари" прикол';
case 'oskKagariDescription': return 'Если включено, вместо настоящего ранга оска будет рендерится :kagari:';
case 'stateViewTitle': return ({required Object nickname, required Object date}) => 'Аккаунт ${nickname} ${date}'; case 'stateViewTitle': return ({required Object nickname, required Object date}) => 'Аккаунт ${nickname} ${date}';
case 'statesViewTitle': return ({required Object number, required Object nickname}) => '${number} состояний аккаунта ${nickname}'; case 'statesViewTitle': return ({required Object number, required Object nickname}) => '${number} состояний аккаунта ${nickname}';
case 'matchesViewTitle': return ({required Object nickname}) => 'Матчи аккаунта ${nickname}'; case 'matchesViewTitle': return ({required Object nickname}) => 'Матчи аккаунта ${nickname}';

View File

@ -29,37 +29,37 @@ late SharedPreferences prefs;
late TetrioService teto; late TetrioService teto;
ThemeData theme = ThemeData(fontFamily: 'Eurostile Round', colorScheme: const ColorScheme.dark(primary: Colors.cyanAccent, secondary: Colors.white), scaffoldBackgroundColor: Colors.black); ThemeData theme = ThemeData(fontFamily: 'Eurostile Round', colorScheme: const ColorScheme.dark(primary: Colors.cyanAccent, secondary: Colors.white), scaffoldBackgroundColor: Colors.black);
Future<dynamic> computeIsolate(Future Function() function) async { // Future<dynamic> computeIsolate(Future Function() function) async {
final receivePort = ReceivePort(); // final receivePort = ReceivePort();
var rootToken = RootIsolateToken.instance!; // var rootToken = RootIsolateToken.instance!;
await Isolate.spawn<_IsolateData>( // await Isolate.spawn<_IsolateData>(
_isolateEntry, // _isolateEntry,
_IsolateData( // _IsolateData(
token: rootToken, // token: rootToken,
function: function, // function: function,
answerPort: receivePort.sendPort, // answerPort: receivePort.sendPort,
), // ),
); // );
return await receivePort.first; // return await receivePort.first;
} // }
void _isolateEntry(_IsolateData isolateData) async { // void _isolateEntry(_IsolateData isolateData) async {
BackgroundIsolateBinaryMessenger.ensureInitialized(isolateData.token); // BackgroundIsolateBinaryMessenger.ensureInitialized(isolateData.token);
final answer = await isolateData.function(); // final answer = await isolateData.function();
isolateData.answerPort.send(answer); // isolateData.answerPort.send(answer);
} // }
class _IsolateData { // class _IsolateData {
final RootIsolateToken token; // final RootIsolateToken token;
final Function function; // final Function function;
final SendPort answerPort; // final SendPort answerPort;
_IsolateData({ // _IsolateData({
required this.token, // required this.token,
required this.function, // required this.function,
required this.answerPort, // required this.answerPort,
}); // });
} // }
final router = GoRouter( final router = GoRouter(
initialLocation: "/", initialLocation: "/",

View File

@ -3,7 +3,7 @@ import 'package:flutter/foundation.dart';
import 'package:flutter/material.dart'; import 'package:flutter/material.dart';
import 'package:flutter_colorpicker/flutter_colorpicker.dart'; import 'package:flutter_colorpicker/flutter_colorpicker.dart';
import 'package:tetra_stats/views/settings_view.dart' show subtitleStyle; import 'package:tetra_stats/views/settings_view.dart' show subtitleStyle;
import 'package:tetra_stats/main.dart' show MyApp, MyAppState, prefs, setAccentColor; import 'package:tetra_stats/main.dart' show MyAppState, prefs;
import 'package:tetra_stats/gen/strings.g.dart'; import 'package:tetra_stats/gen/strings.g.dart';
import 'package:window_manager/window_manager.dart'; import 'package:window_manager/window_manager.dart';
@ -89,7 +89,8 @@ class CustomizationState extends State<CustomizationView> {
child: ListView( child: ListView(
children: [ children: [
ListTile( ListTile(
title: const Text("Accent color"), title: Text(t.AccentColor),
subtitle: Text(t.AccentColorDescription, style: subtitleStyle),
trailing: ColorIndicator(HSVColor.fromColor(Theme.of(context).colorScheme.primary), width: 25, height: 25), trailing: ColorIndicator(HSVColor.fromColor(Theme.of(context).colorScheme.primary), width: 25, height: 25),
onTap: () { onTap: () {
showDialog( showDialog(
@ -119,22 +120,14 @@ class CustomizationState extends State<CustomizationView> {
// title: Text("Stats Table in TL mathes list"), // title: Text("Stats Table in TL mathes list"),
// subtitle: Text("Not implemented"), // subtitle: Text("Not implemented"),
// ), // ),
ListTile(title: Text(t.oskKagari), ListTile(title: Text(t.timestamps),
subtitle: Text(t.oskKagariDescription, style: subtitleStyle), subtitle: Text(t.timestampsDescription, style: subtitleStyle),
trailing: Switch(value: oskKagariGimmick, onChanged: (bool value){
prefs.setBool("oskKagariGimmick", value);
setState(() {
oskKagariGimmick = value;
});
}),),
ListTile(title: Text("Timestamps"),
subtitle: Text(t.oskKagariDescription, style: subtitleStyle),
trailing: DropdownButton( trailing: DropdownButton(
value: timestampMode, value: timestampMode,
items: <DropdownMenuItem>[ items: <DropdownMenuItem>[
DropdownMenuItem(value: 0, child: Text("Absolute (GMT)")), DropdownMenuItem(value: 0, child: Text(t.timestampsAbsoluteGMT)),
DropdownMenuItem(value: 1, child: Text("Absolute (Local Time)")), DropdownMenuItem(value: 1, child: Text(t.timestampsAbsoluteLocalTime)),
DropdownMenuItem(value: 2, child: Text("Relative")) DropdownMenuItem(value: 2, child: Text(t.timestampsRelative))
], ],
onChanged: (dynamic value){ onChanged: (dynamic value){
prefs.setInt("timestampMode", value); prefs.setInt("timestampMode", value);
@ -144,14 +137,14 @@ class CustomizationState extends State<CustomizationView> {
}, },
), ),
), ),
ListTile(title: Text("Main representation of rating"), ListTile(title: Text(t.rating),
subtitle: Text(t.oskKagariDescription, style: subtitleStyle), subtitle: Text(t.ratingDescription, style: subtitleStyle),
trailing: DropdownButton( trailing: DropdownButton(
value: ratingMode, value: ratingMode,
items: <DropdownMenuItem>[ items: <DropdownMenuItem>[
DropdownMenuItem(value: 0, child: Text("TR")), DropdownMenuItem(value: 0, child: Text("TR")),
DropdownMenuItem(value: 1, child: Text("Glicko")), DropdownMenuItem(value: 1, child: Text("Glicko")),
DropdownMenuItem(value: 2, child: Text("LB position")) DropdownMenuItem(value: 2, child: Text(t.ratingLBposition))
], ],
onChanged: (dynamic value){ onChanged: (dynamic value){
prefs.setInt("ratingMode", value); prefs.setInt("ratingMode", value);
@ -161,13 +154,21 @@ class CustomizationState extends State<CustomizationView> {
}, },
), ),
), ),
ListTile(title: Text("Sheetbot-like behavior for radar graphs"), ListTile(title: Text(t.sheetbotGraphs),
subtitle: Text(t.oskKagariDescription, style: subtitleStyle), subtitle: Text(t.sheetbotGraphsDescription, style: subtitleStyle),
trailing: Switch(value: sheetbotRadarGraphs, onChanged: (bool value){ trailing: Switch(value: sheetbotRadarGraphs, onChanged: (bool value){
prefs.setBool("sheetbotRadarGraphs", value); prefs.setBool("sheetbotRadarGraphs", value);
setState(() { setState(() {
sheetbotRadarGraphs = value; sheetbotRadarGraphs = value;
}); });
}),),
ListTile(title: Text(t.oskKagari),
subtitle: Text(t.oskKagariDescription, style: subtitleStyle),
trailing: Switch(value: oskKagariGimmick, onChanged: (bool value){
prefs.setBool("oskKagariGimmick", value);
setState(() {
oskKagariGimmick = value;
});
}),) }),)
], ],
)), )),

View File

@ -438,7 +438,7 @@ class _MainState extends State<MainView> with TickerProviderStateMixin {
Tab(text: t.history), Tab(text: t.history),
Tab(text: t.sprint), Tab(text: t.sprint),
Tab(text: t.blitz), Tab(text: t.blitz),
Tab(text: "Recent runs"), Tab(text: t.recentRuns),
Tab(text: t.other), Tab(text: t.other),
], ],
), ),

View File

@ -263,8 +263,8 @@ class SettingsState extends State<SettingsView> {
onTap: () { onTap: () {
context.go("/settings/customization"); context.go("/settings/customization");
},), },),
ListTile(title: Text("Update stats in the background"), ListTile(title: Text(t.updateInBackground),
subtitle: Text("While tetra stats is running, it can update stats of the current player when cache expires", style: const TextStyle(fontFamily: "Eurostile Round Condensed", color: Colors.grey)), subtitle: Text(t.updateInBackgroundDescription, style: const TextStyle(fontFamily: "Eurostile Round Condensed", color: Colors.grey)),
trailing: Switch(value: updateInBG, onChanged: (bool value){ trailing: Switch(value: updateInBG, onChanged: (bool value){
prefs.setBool("updateInBG", value); prefs.setBool("updateInBG", value);
setState(() { setState(() {

View File

@ -19,9 +19,9 @@ class RecentSingleplayerGames extends StatelessWidget{
Widget build(BuildContext context) { Widget build(BuildContext context) {
return Column( return Column(
children: [ children: [
if (!hideTitle) const Padding( if (!hideTitle) Padding(
padding: EdgeInsets.only(bottom: 8.0), padding: const EdgeInsets.only(bottom: 8.0),
child: Text("Recent", style: TextStyle(height: 0.1, fontFamily: "Eurostile Round Extended", fontSize: 18)), child: Text(t.recent, style: const TextStyle(height: 0.1, fontFamily: "Eurostile Round Extended", fontSize: 18)),
), ),
for(RecordSingle record in recent.records) ListTile( for(RecordSingle record in recent.records) ListTile(
onTap: () => Navigator.push(context, MaterialPageRoute(builder: (context) => SingleplayerRecordView(record: record))), onTap: () => Navigator.push(context, MaterialPageRoute(builder: (context) => SingleplayerRecordView(record: record))),
@ -37,7 +37,7 @@ class RecentSingleplayerGames extends StatelessWidget{
title: Text( title: Text(
switch (record.endContext.gameType){ switch (record.endContext.gameType){
"40l" => get40lTime(record.endContext.finalTime.inMicroseconds), "40l" => get40lTime(record.endContext.finalTime.inMicroseconds),
"blitz" => "${NumberFormat.decimalPattern().format(record.endContext.score)} points", "blitz" => t.blitzScore(p: NumberFormat.decimalPattern().format(record.endContext.score)),
"5mblast" => get40lTime(record.endContext.finalTime.inMicroseconds), "5mblast" => get40lTime(record.endContext.finalTime.inMicroseconds),
String() => "huh", String() => "huh",
}, },

View File

@ -131,8 +131,8 @@ class SingleplayerRecord extends StatelessWidget {
crossAxisAlignment: WrapCrossAlignment.start, crossAxisAlignment: WrapCrossAlignment.start,
spacing: 20, spacing: 20,
children: [ children: [
TextButton(onPressed: (){launchInBrowser(Uri.parse("https://tetr.io/#r:${record!.replayId}"));}, child: Text("Open replay in TETR.IO")), TextButton(onPressed: (){launchInBrowser(Uri.parse("https://tetr.io/#r:${record!.replayId}"));}, child: Text(t.openSPreplay)),
TextButton(onPressed: (){launchInBrowser(Uri.parse("https://inoue.szy.lol/api/replay/${record!.replayId}"));}, child: Text("Download replay")), TextButton(onPressed: (){launchInBrowser(Uri.parse("https://inoue.szy.lol/api/replay/${record!.replayId}"));}, child: Text(t.downloadSPreplay)),
], ],
), ),
if (stream != null && stream!.records.length > 1) for(int i = 1; i < stream!.records.length; i++) ListTile( if (stream != null && stream!.records.length > 1) for(int i = 1; i < stream!.records.length; i++) ListTile(
@ -143,7 +143,7 @@ class SingleplayerRecord extends StatelessWidget {
title: Text( title: Text(
switch (stream!.records[i].endContext.gameType){ switch (stream!.records[i].endContext.gameType){
"40l" => get40lTime(stream!.records[i].endContext.finalTime.inMicroseconds), "40l" => get40lTime(stream!.records[i].endContext.finalTime.inMicroseconds),
"blitz" => "${NumberFormat.decimalPattern().format(stream!.records[i].endContext.score)} points", "blitz" => t.blitzScore(p: NumberFormat.decimalPattern().format(stream!.records[i].endContext.score)),
"5mblast" => get40lTime(stream!.records[i].endContext.finalTime.inMicroseconds), "5mblast" => get40lTime(stream!.records[i].endContext.finalTime.inMicroseconds),
String() => "huh", String() => "huh",
}, },

View File

@ -44,7 +44,7 @@ class TLRatingThingy extends StatelessWidget{
TextSpan(text: " Glicko", style: TextStyle(fontFamily: "Eurostile Round Extended", fontSize: bigScreen ? 42 : 28)) TextSpan(text: " Glicko", style: TextStyle(fontFamily: "Eurostile Round Extended", fontSize: bigScreen ? 42 : 28))
], ],
2 => [ 2 => [
TextSpan(text: "Top ${formatedPercentile[0]}", style: TextStyle(fontFamily: "Eurostile Round Extended", fontSize: bigScreen ? 42 : 28)), TextSpan(text: "${t.top} ${formatedPercentile[0]}", style: TextStyle(fontFamily: "Eurostile Round Extended", fontSize: bigScreen ? 42 : 28)),
if (formatedPercentile.elementAtOrNull(1) != null) TextSpan(text: decimalSeparator + formatedPercentile[1]), if (formatedPercentile.elementAtOrNull(1) != null) TextSpan(text: decimalSeparator + formatedPercentile[1]),
TextSpan(text: " %", style: TextStyle(fontFamily: "Eurostile Round Extended", fontSize: bigScreen ? 42 : 28)) TextSpan(text: " %", style: TextStyle(fontFamily: "Eurostile Round Extended", fontSize: bigScreen ? 42 : 28))
], ],
@ -77,7 +77,7 @@ class TLRatingThingy extends StatelessWidget{
text: TextSpan( text: TextSpan(
style: DefaultTextStyle.of(context).style, style: DefaultTextStyle.of(context).style,
children: [ children: [
TextSpan(text: prefs.getInt("ratingMode") == 2 ? "${f2.format(tlData.rating)} TR • % rank: ${tlData.percentileRank.toUpperCase()}" : "${t.top} ${f2.format(tlData.percentile * 100)}% (${tlData.percentileRank.toUpperCase()})"), TextSpan(text: prefs.getInt("ratingMode") == 2 ? "${f2.format(tlData.rating)} TR • % ${t.rank}: ${tlData.percentileRank.toUpperCase()}" : "${t.top} ${f2.format(tlData.percentile * 100)}% (${tlData.percentileRank.toUpperCase()})"),
if (tlData.bestRank != "z") const TextSpan(text: ""), if (tlData.bestRank != "z") const TextSpan(text: ""),
if (tlData.bestRank != "z") TextSpan(text: "${t.topRank}: ${tlData.bestRank.toUpperCase()}"), if (tlData.bestRank != "z") TextSpan(text: "${t.topRank}: ${tlData.bestRank.toUpperCase()}"),
if (topTR != null) TextSpan(text: " (${f2.format(topTR)} TR)"), if (topTR != null) TextSpan(text: " (${f2.format(topTR)} TR)"),

View File

@ -1,4 +1,5 @@
import 'package:flutter/material.dart'; import 'package:flutter/material.dart';
import 'package:flutter/widgets.dart';
import 'package:intl/intl.dart'; import 'package:intl/intl.dart';
import 'package:tetra_stats/data_objects/tetrio.dart'; import 'package:tetra_stats/data_objects/tetrio.dart';
import 'package:syncfusion_flutter_gauges/gauges.dart'; import 'package:syncfusion_flutter_gauges/gauges.dart';
@ -58,7 +59,7 @@ class _TLThingyState extends State<TLThingy> {
final t = Translations.of(context); final t = Translations.of(context);
String decimalSeparator = f2.symbols.DECIMAL_SEP; String decimalSeparator = f2.symbols.DECIMAL_SEP;
List<String> estTRformated = f2.format(currentTl.estTr!.esttr).split(decimalSeparator); List<String> estTRformated = f2.format(currentTl.estTr!.esttr).split(decimalSeparator);
List<String> estTRaccFormated = intFDiff.format(currentTl.esttracc!).split(decimalSeparator); List<String> estTRaccFormated = intFDiff.format(currentTl.esttracc!).split(".");
if (currentTl.gamesPlayed == 0) return Center(child: Text(widget.guest ? t.anonTL : widget.bot ? t.botTL : t.neverPlayedTL, style: const TextStyle(fontFamily: "Eurostile Round", fontSize: 28), textAlign: TextAlign.center,)); if (currentTl.gamesPlayed == 0) return Center(child: Text(widget.guest ? t.anonTL : widget.bot ? t.botTL : t.neverPlayedTL, style: const TextStyle(fontFamily: "Eurostile Round", fontSize: 28), textAlign: TextAlign.center,));
return LayoutBuilder(builder: (context, constraints) { return LayoutBuilder(builder: (context, constraints) {
bool bigScreen = constraints.maxWidth >= 768; bool bigScreen = constraints.maxWidth >= 768;
@ -245,12 +246,10 @@ class _TLThingyState extends State<TLThingy> {
), ),
if (currentTl.estTr != null) if (currentTl.estTr != null)
Padding( Padding(
padding: const EdgeInsets.fromLTRB(0, 20, 0, 20), padding: const EdgeInsets.fromLTRB(8, 20, 8, 20),
child: Container( child: Container(
//alignment: Alignment.center,
width: bigScreen ? MediaQuery.of(context).size.width * 0.4 : MediaQuery.of(context).size.width * 0.85,
height: 70, height: 70,
constraints: const BoxConstraints(maxWidth: 768), constraints: const BoxConstraints(maxWidth: 500),
child: Stack( child: Stack(
children: [ children: [
Positioned( Positioned(

View File

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

View File

@ -8,6 +8,11 @@
"history": "History", "history": "History",
"sprint": "40 Lines", "sprint": "40 Lines",
"blitz": "Blitz", "blitz": "Blitz",
"recent": "Recent",
"recentRuns": "Recent runs",
"blitzScore": "$p points",
"openSPreplay": "Open replay in TETR.IO",
"downloadSPreplay": "Download replay",
"other": "Other", "other": "Other",
"distinguishment": "Distinguishment", "distinguishment": "Distinguishment",
"zen": "Zen", "zen": "Zen",
@ -109,14 +114,28 @@
"yourIDAlertTitle": "Your nickname in TETR.IO", "yourIDAlertTitle": "Your nickname in TETR.IO",
"yourIDText": "When app loads, it will retrieve data for this account", "yourIDText": "When app loads, it will retrieve data for this account",
"language": "Language", "language": "Language",
"updateInBackground": "Update stats in the background",
"updateInBackgroundDescription": "While Tetra Stats is running, it can update stats of the current player when cache expires",
"customization": "Customization", "customization": "Customization",
"customizationDescription": "There is only one toggle, planned to add more settings", "customizationDescription": "Change appearance of different things in Tetra Stats UI",
"oskKagari": "Osk Kagari gimmick",
"oskKagariDescription": "If on, osk's rank on main view will be rendered as :kagari:",
"AccentColor": "Accent color",
"AccentColorDescription": "Almost all interactive UI elements highlighted with this color",
"timestamps": "Timestamps",
"timestampsDescription": "You can choose, in which way timestamps shows time",
"timestampsAbsoluteGMT": "Absolute (GMT)",
"timestampsAbsoluteLocalTime": "Absolute (Your timezone)",
"timestampsRelative": "Relative",
"rating": "Main representation of rating",
"ratingDescription": "TR is not linear, while Glicko does not have boundaries and percentile is volatile",
"ratingLBposition": "LB position",
"sheetbotGraphs": "Sheetbot-like behavior for radar graphs",
"sheetbotGraphsDescription": "If on, points on the graphs can appear on the opposite half of the graph if value is negative",
"lbStats": "Show leaderboard based stats", "lbStats": "Show leaderboard based stats",
"lbStatsDescription": "That will impact on loading times, but will allow you to see position on LB by stats and comparison with average values", "lbStatsDescription": "That will impact on loading times, but will allow you to see position on LB by stats and comparison with average values",
"aboutApp": "About app", "aboutApp": "About app",
"aboutAppText": "${appName} (${packageName}) Version ${version} Build ${buildNumber}\n\nDeveloped by dan63047\nFormulas provided by kerrmunism\nHistory provided by p1nkl0bst3r\nTETR.IO replay grabber API by szy", "aboutAppText": "${appName} (${packageName}) Version ${version} Build ${buildNumber}\n\nDeveloped by dan63047\nFormulas provided by kerrmunism\nHistory provided by p1nkl0bst3r\nTETR.IO replay grabber API by szy",
"oskKagari": "Osk Kagari gimmick",
"oskKagariDescription": "If on, osk's rank on main view will be rendered as :kagari:",
"stateViewTitle": "${nickname} account on ${date}", "stateViewTitle": "${nickname} account on ${date}",
"statesViewTitle": "${number} states of ${nickname} account", "statesViewTitle": "${number} states of ${nickname} account",
"matchesViewTitle": "${nickname} TL matches", "matchesViewTitle": "${nickname} TL matches",

View File

@ -8,6 +8,11 @@
"history": "История", "history": "История",
"sprint": "40 линий", "sprint": "40 линий",
"blitz": "Блиц", "blitz": "Блиц",
"recent": "Недавно",
"recentRuns": "Недавние",
"blitzScore": "$p очков",
"openSPreplay": "Открыть повтор в TETR.IO",
"downloadSPreplay": "Скачать повтор",
"other": "Другое", "other": "Другое",
"distinguishment": "Заслуга", "distinguishment": "Заслуга",
"zen": "Дзен", "zen": "Дзен",
@ -109,14 +114,28 @@
"yourIDAlertTitle": "Ваш ник в TETR.IO", "yourIDAlertTitle": "Ваш ник в TETR.IO",
"yourIDText": "При запуске приложения оно будет получать статистику этого игрока.", "yourIDText": "При запуске приложения оно будет получать статистику этого игрока.",
"language": "Язык (Language)", "language": "Язык (Language)",
"updateInBackground": "Обновлять статистику в фоне",
"updateInBackgroundDescription": "Пока Tetra Stats работает, он может обновлять статистику самостоятельно когда кеш истекает",
"customization": "Кастомизация", "customization": "Кастомизация",
"customizationDescription": "Здесь только один переключатель, в планах добавить больше", "customizationDescription": "Измените внешний вид пользовательского интерфейса Tetra Stats",
"oskKagari": "\"Оск Кагари\" прикол",
"oskKagariDescription": "Если включено, вместо настоящего ранга оска будет рендерится :kagari:",
"AccentColor": "Цветовой акцент",
"AccentColorDescription": "Почти все интерактивные элементы пользовательского интерфейса окрашены в этот цвет",
"timestamps": "Метки времени",
"timestampsDescription": "Вы можете выбрать, каким образом метки времени показывают время",
"timestampsAbsoluteGMT": "Абсолютные (GMT)",
"timestampsAbsoluteLocalTime": "Абсолютные (Ваш часовой пояс)",
"timestampsRelative": "Относительные",
"rating": "Основное представление рейтинга",
"ratingDescription": "TR нелинеен, тогда как Glicko не имеет границ, а положение в таблице лидеров волатильно",
"ratingLBposition": "Позиция в рейтинге",
"sheetbotGraphs": "Графики-радары как у sheetBot",
"sheetbotGraphsDescription": "Если включено, точки на графике могут появляться на противоположной стороне графика если значение отрицательное",
"lbStats": "Показывать статистику, основанную на рейтинговой таблице", "lbStats": "Показывать статистику, основанную на рейтинговой таблице",
"lbStatsDescription": "Это повлияет на время загрузки, но позволит видеть положение в рейтинге и сравнение со средними значениями по рангу по каждой стате", "lbStatsDescription": "Это повлияет на время загрузки, но позволит видеть положение в рейтинге и сравнение со средними значениями по рангу по каждой стате",
"aboutApp": "О приложении", "aboutApp": "О приложении",
"aboutAppText": "${appName} (${packageName}) Версия ${version} Сборка ${buildNumber}\n\nРазработал dan63047\nФормулы предоставил kerrmunism\nИсторию предоставляет p1nkl0bst3r\nВозможность скачивать повторы из TETR.IO предоставляет szy", "aboutAppText": "${appName} (${packageName}) Версия ${version} Сборка ${buildNumber}\n\nРазработал dan63047\nФормулы предоставил kerrmunism\nИсторию предоставляет p1nkl0bst3r\nВозможность скачивать повторы из TETR.IO предоставляет szy",
"oskKagari": "\"Оск Кагари\" прикол",
"oskKagariDescription": "Если включено, вместо настоящего ранга оска будет рендерится :kagari:",
"stateViewTitle": "Аккаунт ${nickname} ${date}", "stateViewTitle": "Аккаунт ${nickname} ${date}",
"statesViewTitle": "${number} состояний аккаунта ${nickname}", "statesViewTitle": "${number} состояний аккаунта ${nickname}",
"matchesViewTitle": "Матчи аккаунта ${nickname}", "matchesViewTitle": "Матчи аккаунта ${nickname}",