Compare commits
No commits in common. "c03ea447824f727757024dd9911229527f079689" and "3d28e5a21429840916131e015fd0d01be34a4b4e" have entirely different histories.
c03ea44782
...
3d28e5a214
|
@ -45,8 +45,8 @@ jobs:
|
||||||
runs-on: ubuntu-latest
|
runs-on: ubuntu-latest
|
||||||
steps:
|
steps:
|
||||||
- uses: actions/checkout@v2
|
- uses: actions/checkout@v2
|
||||||
- uses: ashutoshvarma/setup-ninja@master
|
|
||||||
- uses: subosito/flutter-action@v1
|
- uses: subosito/flutter-action@v1
|
||||||
|
- uses: ashutoshvarma/setup-ninja@master
|
||||||
with:
|
with:
|
||||||
channel: 'stable'
|
channel: 'stable'
|
||||||
flutter-version: '3.22.3'
|
flutter-version: '3.22.3'
|
||||||
|
|
|
@ -4,9 +4,9 @@
|
||||||
/// To regenerate, run: `dart run slang`
|
/// To regenerate, run: `dart run slang`
|
||||||
///
|
///
|
||||||
/// Locales: 2
|
/// Locales: 2
|
||||||
/// Strings: 1210 (605 per locale)
|
/// Strings: 1216 (608 per locale)
|
||||||
///
|
///
|
||||||
/// Built on 2024-09-04 at 20:41 UTC
|
/// Built on 2024-08-07 at 15:58 UTC
|
||||||
|
|
||||||
// coverage:ignore-file
|
// coverage:ignore-file
|
||||||
// ignore_for_file: type=lint
|
// ignore_for_file: type=lint
|
||||||
|
@ -224,6 +224,9 @@ class Translations implements BaseTranslations<AppLocale, Translations> {
|
||||||
String get smooth => 'Smooth';
|
String get smooth => 'Smooth';
|
||||||
String get postSeason => 'Off-season';
|
String get postSeason => 'Off-season';
|
||||||
String get seasonStarts => 'Season starts in:';
|
String get seasonStarts => 'Season starts in:';
|
||||||
|
String get myMessadgeHeader => 'A messadge from dan63';
|
||||||
|
String get myMessadgeBody => 'TETR.IO Tetra Channel API has been seriously modified after the last update, therefore, some functions may not work. I will try to catch up and add new stats (and return back the old ones) as soon, as public docs on new Tetra Channel API will be available.';
|
||||||
|
String preSeasonMessage({required Object n}) => 'Right now you can play unranked FT3 matches with hidden glicko (200 RD 🙂).\nSeason ${n} rules applied';
|
||||||
String get nanow => 'Not avaliable for now...';
|
String get nanow => 'Not avaliable for now...';
|
||||||
String seasonEnds({required Object countdown}) => 'Season ends in ${countdown}';
|
String seasonEnds({required Object countdown}) => 'Season ends in ${countdown}';
|
||||||
String get seasonEnded => 'Season has ended';
|
String get seasonEnded => 'Season has ended';
|
||||||
|
@ -290,7 +293,7 @@ class Translations implements BaseTranslations<AppLocale, Translations> {
|
||||||
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';
|
||||||
String statesViewEntry({required Object level, required Object glicko, required Object rd, required Object games}) => '${level} TR, ${glicko}±${rd} Glicko, ${games} игр сыграно';
|
String statesViewEntry({required Object level, required Object gameTime, required Object friends, required Object rd}) => 'Level ${level}, ${gameTime} of gametime, ${friends} friends, ${rd} RD';
|
||||||
String stateRemoved({required Object date}) => '${date} state was removed from database!';
|
String stateRemoved({required Object date}) => '${date} state was removed from database!';
|
||||||
String matchRemoved({required Object date}) => '${date} match was removed from database!';
|
String matchRemoved({required Object date}) => '${date} match was removed from database!';
|
||||||
String get viewAllMatches => 'View all matches';
|
String get viewAllMatches => 'View all matches';
|
||||||
|
@ -935,6 +938,9 @@ class _StringsRu implements Translations {
|
||||||
@override String get smooth => 'Гладкий';
|
@override String get smooth => 'Гладкий';
|
||||||
@override String get postSeason => 'Внесезонье';
|
@override String get postSeason => 'Внесезонье';
|
||||||
@override String get seasonStarts => 'Сезон начнётся через:';
|
@override String get seasonStarts => 'Сезон начнётся через:';
|
||||||
|
@override String get myMessadgeHeader => 'Сообщение от dan63';
|
||||||
|
@override String get myMessadgeBody => 'TETR.IO Tetra Channel API был серьёзно изменён после последнего обновления, поэтому некоторый функционал может не работать. Я постараюсь добавить новую статистику (и вернуть старую) как только будут опубликована новая документация по данному API.';
|
||||||
|
@override String preSeasonMessage({required Object n}) => 'Прямо сейчас вы можете сыграть безранговый матч до трёх побед со скрытым Glicko (200 RD 🙂).\nПрименяются правила ${n} сезона';
|
||||||
@override String get nanow => 'Пока недоступно...';
|
@override String get nanow => 'Пока недоступно...';
|
||||||
@override String seasonEnds({required Object countdown}) => 'Сезон закончится через ${countdown}';
|
@override String seasonEnds({required Object countdown}) => 'Сезон закончится через ${countdown}';
|
||||||
@override String get seasonEnded => 'Сезон закончился';
|
@override String get seasonEnded => 'Сезон закончился';
|
||||||
|
@ -1001,7 +1007,7 @@ class _StringsRu implements Translations {
|
||||||
@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}';
|
||||||
@override String statesViewEntry({required Object level, required Object glicko, required Object rd, required Object games}) => '${level} TR, ${glicko}±${rd} Glicko, ${games} игр сыграно';
|
@override String statesViewEntry({required Object level, required Object gameTime, required Object friends, required Object rd}) => '${level} уровень, ${gameTime} сыграно, ${friends} друзей, ${rd} RD';
|
||||||
@override String stateRemoved({required Object date}) => 'Состояние от ${date} было удалено из локальной базы данных!';
|
@override String stateRemoved({required Object date}) => 'Состояние от ${date} было удалено из локальной базы данных!';
|
||||||
@override String matchRemoved({required Object date}) => 'Матч от ${date} был удален из локальной базы данных!';
|
@override String matchRemoved({required Object date}) => 'Матч от ${date} был удален из локальной базы данных!';
|
||||||
@override String get viewAllMatches => 'Все матчи';
|
@override String get viewAllMatches => 'Все матчи';
|
||||||
|
@ -1638,6 +1644,9 @@ extension on Translations {
|
||||||
case 'smooth': return 'Smooth';
|
case 'smooth': return 'Smooth';
|
||||||
case 'postSeason': return 'Off-season';
|
case 'postSeason': return 'Off-season';
|
||||||
case 'seasonStarts': return 'Season starts in:';
|
case 'seasonStarts': return 'Season starts in:';
|
||||||
|
case 'myMessadgeHeader': return 'A messadge from dan63';
|
||||||
|
case 'myMessadgeBody': return 'TETR.IO Tetra Channel API has been seriously modified after the last update, therefore, some functions may not work. I will try to catch up and add new stats (and return back the old ones) as soon, as public docs on new Tetra Channel API will be available.';
|
||||||
|
case 'preSeasonMessage': return ({required Object n}) => 'Right now you can play unranked FT3 matches with hidden glicko (200 RD 🙂).\nSeason ${n} rules applied';
|
||||||
case 'nanow': return 'Not avaliable for now...';
|
case 'nanow': return 'Not avaliable for now...';
|
||||||
case 'seasonEnds': return ({required Object countdown}) => 'Season ends in ${countdown}';
|
case 'seasonEnds': return ({required Object countdown}) => 'Season ends in ${countdown}';
|
||||||
case 'seasonEnded': return 'Season has ended';
|
case 'seasonEnded': return 'Season has ended';
|
||||||
|
@ -1704,7 +1713,7 @@ extension on Translations {
|
||||||
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';
|
||||||
case 'statesViewEntry': return ({required Object level, required Object glicko, required Object rd, required Object games}) => '${level} TR, ${glicko}±${rd} Glicko, ${games} игр сыграно';
|
case 'statesViewEntry': return ({required Object level, required Object gameTime, required Object friends, required Object rd}) => 'Level ${level}, ${gameTime} of gametime, ${friends} friends, ${rd} RD';
|
||||||
case 'stateRemoved': return ({required Object date}) => '${date} state was removed from database!';
|
case 'stateRemoved': return ({required Object date}) => '${date} state was removed from database!';
|
||||||
case 'matchRemoved': return ({required Object date}) => '${date} match was removed from database!';
|
case 'matchRemoved': return ({required Object date}) => '${date} match was removed from database!';
|
||||||
case 'viewAllMatches': return 'View all matches';
|
case 'viewAllMatches': return 'View all matches';
|
||||||
|
@ -2265,6 +2274,9 @@ extension on _StringsRu {
|
||||||
case 'smooth': return 'Гладкий';
|
case 'smooth': return 'Гладкий';
|
||||||
case 'postSeason': return 'Внесезонье';
|
case 'postSeason': return 'Внесезонье';
|
||||||
case 'seasonStarts': return 'Сезон начнётся через:';
|
case 'seasonStarts': return 'Сезон начнётся через:';
|
||||||
|
case 'myMessadgeHeader': return 'Сообщение от dan63';
|
||||||
|
case 'myMessadgeBody': return 'TETR.IO Tetra Channel API был серьёзно изменён после последнего обновления, поэтому некоторый функционал может не работать. Я постараюсь добавить новую статистику (и вернуть старую) как только будут опубликована новая документация по данному API.';
|
||||||
|
case 'preSeasonMessage': return ({required Object n}) => 'Прямо сейчас вы можете сыграть безранговый матч до трёх побед со скрытым Glicko (200 RD 🙂).\nПрименяются правила ${n} сезона';
|
||||||
case 'nanow': return 'Пока недоступно...';
|
case 'nanow': return 'Пока недоступно...';
|
||||||
case 'seasonEnds': return ({required Object countdown}) => 'Сезон закончится через ${countdown}';
|
case 'seasonEnds': return ({required Object countdown}) => 'Сезон закончится через ${countdown}';
|
||||||
case 'seasonEnded': return 'Сезон закончился';
|
case 'seasonEnded': return 'Сезон закончился';
|
||||||
|
@ -2331,7 +2343,7 @@ extension on _StringsRu {
|
||||||
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}';
|
||||||
case 'statesViewEntry': return ({required Object level, required Object glicko, required Object rd, required Object games}) => '${level} TR, ${glicko}±${rd} Glicko, ${games} игр сыграно';
|
case 'statesViewEntry': return ({required Object level, required Object gameTime, required Object friends, required Object rd}) => '${level} уровень, ${gameTime} сыграно, ${friends} друзей, ${rd} RD';
|
||||||
case 'stateRemoved': return ({required Object date}) => 'Состояние от ${date} было удалено из локальной базы данных!';
|
case 'stateRemoved': return ({required Object date}) => 'Состояние от ${date} было удалено из локальной базы данных!';
|
||||||
case 'matchRemoved': return ({required Object date}) => 'Матч от ${date} был удален из локальной базы данных!';
|
case 'matchRemoved': return ({required Object date}) => 'Матч от ${date} был удален из локальной базы данных!';
|
||||||
case 'viewAllMatches': return 'Все матчи';
|
case 'viewAllMatches': return 'Все матчи';
|
||||||
|
|
|
@ -213,7 +213,6 @@ class TetrioService extends DB {
|
||||||
_players.removeWhere((key, value) => key == id);
|
_players.removeWhere((key, value) => key == id);
|
||||||
_tetrioStreamController.add(_players);
|
_tetrioStreamController.add(_players);
|
||||||
}
|
}
|
||||||
await db.delete(tetrioLeagueTable, where: "id LIKE ?", whereArgs: ["$id%"]);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Gets nickname from database or requests it from API if missing.
|
/// Gets nickname from database or requests it from API if missing.
|
||||||
|
@ -1118,14 +1117,46 @@ class TetrioService extends DB {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Remove state, which has [dbID] from the local database
|
/// Remove state (which is [tetrioPlayer]) from the local database
|
||||||
/// ([dbid] is a concatenation of player id and UINX milliseconds in hex)
|
// Future<void> deleteState(TetrioPlayer tetrioPlayer) async {
|
||||||
Future<void> deleteState(String dbID) async {
|
// await ensureDbIsOpen();
|
||||||
await ensureDbIsOpen();
|
// final db = getDatabaseOrThrow();
|
||||||
final db = getDatabaseOrThrow();
|
// //List<TetrioPlayer> states = await getPlayer(tetrioPlayer.userId);
|
||||||
int result = await db.delete(tetrioLeagueTable, where: "id = ?", whereArgs: [dbID]);
|
// // removing state from map that contain every state of each user
|
||||||
if (result == 0) throw Exception("Failed to remove a row $dbID - it's probably not exist");
|
// states.removeWhere((element) => element.state == tetrioPlayer.state);
|
||||||
}
|
|
||||||
|
// // Making map of the states (without deleted one)
|
||||||
|
// final Map<String, dynamic> statesJson = {};
|
||||||
|
// // for (var e in states) {
|
||||||
|
// // statesJson.addEntries({(e.state.millisecondsSinceEpoch ~/ 1000).toString(): e.toJson()}.entries);
|
||||||
|
// // }
|
||||||
|
// // Rewriting database entry with new json
|
||||||
|
// await db.update(tetrioUsersTable, {idCol: tetrioPlayer.userId, nickCol: tetrioPlayer.username, statesCol: jsonEncode(statesJson)},
|
||||||
|
// where: '$idCol = ?', whereArgs: [tetrioPlayer.userId]);
|
||||||
|
// _tetrioStreamController.add(_players);
|
||||||
|
// }
|
||||||
|
|
||||||
|
/// Returns list of all states of player with given [id] from database. Can return empty list if player
|
||||||
|
/// was not found.
|
||||||
|
// Future<List<TetrioPlayer>> getPlayer(String id) async {
|
||||||
|
// await ensureDbIsOpen();
|
||||||
|
// final db = getDatabaseOrThrow();
|
||||||
|
// List<TetrioPlayer> states = [];
|
||||||
|
// final results = await db.query(tetrioUsersTable, limit: 1, where: '$idCol = ?', whereArgs: [id.toLowerCase()]);
|
||||||
|
// if (results.isEmpty) {
|
||||||
|
// return states; // it empty
|
||||||
|
// } else {
|
||||||
|
// dynamic rawStates = results.first['jsonStates'] as String;
|
||||||
|
// rawStates = json.decode(rawStates);
|
||||||
|
// // recreating objects of states
|
||||||
|
// rawStates.forEach((k, v) => states.add(TetrioPlayer.fromJson(v, DateTime.fromMillisecondsSinceEpoch(int.parse(k) * 1000), id, results.first[nickCol] as String)));
|
||||||
|
// // updating the stream
|
||||||
|
// _players.removeWhere((key, value) => key == id);
|
||||||
|
// _players.addEntries({states.last.userId: states.last.username}.entries);
|
||||||
|
// _tetrioStreamController.add(_players);
|
||||||
|
// return states;
|
||||||
|
// }
|
||||||
|
// }
|
||||||
|
|
||||||
/// Retrieves general stats of [user] (nickname or id) from Tetra Channel api. Returns [TetrioPlayer] object of this user.
|
/// Retrieves general stats of [user] (nickname or id) from Tetra Channel api. Returns [TetrioPlayer] object of this user.
|
||||||
/// If [isItDiscordID] is true, function expects [user] to be a discord user id. Throws an exception if fails to retrieve.
|
/// If [isItDiscordID] is true, function expects [user] to be a discord user id. Throws an exception if fails to retrieve.
|
||||||
|
@ -1225,14 +1256,17 @@ class TetrioService extends DB {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Retrieves whole [tetrioUsersTable] and returns Map {id: nickname} of everyone in database
|
/// Retrieves whole [tetrioUsersTable] and returns Map with [TetrioPlayer] objects of everyone in database
|
||||||
Future<Map<String, String>> getAllPlayers() async {
|
Future<Map<String, List<TetrioPlayer>>> getAllPlayers() async {
|
||||||
await ensureDbIsOpen();
|
await ensureDbIsOpen();
|
||||||
final db = getDatabaseOrThrow();
|
final db = getDatabaseOrThrow();
|
||||||
final players = await db.query(tetrioUsersTable);
|
final players = await db.query(tetrioUsersTable);
|
||||||
Map<String, String> data = {};
|
Map<String, List<TetrioPlayer>> data = {};
|
||||||
for (var entry in players){
|
for (var entry in players){
|
||||||
data[entry[idCol] as String] = entry[nickCol] as String;
|
var test = json.decode(entry['jsonStates'] as String);
|
||||||
|
List<TetrioPlayer> states = [];
|
||||||
|
test.forEach((k, v) => states.add(TetrioPlayer.fromJson(v, DateTime.fromMillisecondsSinceEpoch(int.parse(k) * 1000), entry[idCol] as String, entry[nickCol] as String)));
|
||||||
|
data.addEntries({states.last.userId: states}.entries);
|
||||||
}
|
}
|
||||||
return data;
|
return data;
|
||||||
}
|
}
|
||||||
|
|
|
@ -4,15 +4,14 @@ import 'package:flutter/material.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:tetra_stats/gen/strings.g.dart';
|
import 'package:tetra_stats/gen/strings.g.dart';
|
||||||
import 'package:tetra_stats/widgets/text_timestamp.dart';
|
//import 'package:tetra_stats/widgets/tl_thingy.dart';
|
||||||
import 'package:tetra_stats/widgets/tl_thingy.dart';
|
|
||||||
import 'package:tetra_stats/widgets/user_thingy.dart';
|
import 'package:tetra_stats/widgets/user_thingy.dart';
|
||||||
import 'package:window_manager/window_manager.dart';
|
import 'package:window_manager/window_manager.dart';
|
||||||
|
|
||||||
final DateFormat dateFormat = DateFormat.yMMMd(LocaleSettings.currentLocale.languageCode).add_Hms();
|
final DateFormat dateFormat = DateFormat.yMMMd(LocaleSettings.currentLocale.languageCode).add_Hms();
|
||||||
|
|
||||||
class StateView extends StatefulWidget {
|
class StateView extends StatefulWidget {
|
||||||
final TetraLeague state;
|
final TetrioPlayer state;
|
||||||
const StateView({super.key, required this.state});
|
const StateView({super.key, required this.state});
|
||||||
|
|
||||||
@override
|
@override
|
||||||
|
@ -29,7 +28,7 @@ class StateState extends State<StateView> {
|
||||||
_scrollController = ScrollController();
|
_scrollController = ScrollController();
|
||||||
if (!kIsWeb && !Platform.isAndroid && !Platform.isIOS){
|
if (!kIsWeb && !Platform.isAndroid && !Platform.isIOS){
|
||||||
windowManager.getTitle().then((value) => oldWindowTitle = value);
|
windowManager.getTitle().then((value) => oldWindowTitle = value);
|
||||||
windowManager.setTitle("State from ${timestamp(widget.state.timestamp)}");
|
windowManager.setTitle("Tetra Stats: ${t.stateViewTitle(nickname: widget.state.username.toUpperCase(), date: dateFormat.format(widget.state.state))}");
|
||||||
}
|
}
|
||||||
super.initState();
|
super.initState();
|
||||||
}
|
}
|
||||||
|
@ -50,12 +49,15 @@ class StateState extends State<StateView> {
|
||||||
final t = Translations.of(context);
|
final t = Translations.of(context);
|
||||||
return Scaffold(
|
return Scaffold(
|
||||||
appBar: AppBar(
|
appBar: AppBar(
|
||||||
title: Text("State from ${timestamp(widget.state.timestamp)}"),
|
title: Text(t.stateViewTitle(nickname: widget.state.username.toUpperCase(), date: dateFormat.format(widget.state.state))),
|
||||||
),
|
),
|
||||||
backgroundColor: Colors.black,
|
backgroundColor: Colors.black,
|
||||||
body: SafeArea(
|
body: SafeArea(
|
||||||
child: TLThingy(tl: widget.state, userID: widget.state.id, states: [])
|
child: NestedScrollView(
|
||||||
)
|
controller: _scrollController,
|
||||||
);
|
headerSliverBuilder: (context, value) {
|
||||||
|
return [SliverToBoxAdapter(child: UserThingy(player: widget.state, showStateTimestamp: true, setState: _justUpdate))];
|
||||||
|
},
|
||||||
|
body: Container())));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -1,19 +1,18 @@
|
||||||
import 'dart:io';
|
import 'dart:io';
|
||||||
import 'package:flutter/foundation.dart';
|
import 'package:flutter/foundation.dart';
|
||||||
import 'package:flutter/material.dart';
|
import 'package:flutter/material.dart';
|
||||||
|
import 'package:intl/intl.dart';
|
||||||
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/gen/strings.g.dart';
|
||||||
import 'package:tetra_stats/main.dart' show teto;
|
import 'package:tetra_stats/main.dart' show teto;
|
||||||
import 'package:tetra_stats/utils/numers_formats.dart';
|
|
||||||
import 'package:tetra_stats/views/mathes_view.dart';
|
import 'package:tetra_stats/views/mathes_view.dart';
|
||||||
import 'package:tetra_stats/views/state_view.dart';
|
import 'package:tetra_stats/views/state_view.dart';
|
||||||
import 'package:tetra_stats/widgets/text_timestamp.dart';
|
import 'package:tetra_stats/widgets/text_timestamp.dart';
|
||||||
import 'package:window_manager/window_manager.dart';
|
import 'package:window_manager/window_manager.dart';
|
||||||
|
|
||||||
class StatesView extends StatefulWidget {
|
class StatesView extends StatefulWidget {
|
||||||
final String nickname;
|
final List<TetraLeague> states;
|
||||||
final String id;
|
const StatesView({super.key, required this.states});
|
||||||
const StatesView({required this.nickname, required this.id, super.key});
|
|
||||||
|
|
||||||
@override
|
@override
|
||||||
State<StatefulWidget> createState() => StatesState();
|
State<StatefulWidget> createState() => StatesState();
|
||||||
|
@ -26,7 +25,7 @@ class StatesState extends State<StatesView> {
|
||||||
void initState() {
|
void initState() {
|
||||||
if (!kIsWeb && !Platform.isAndroid && !Platform.isIOS){
|
if (!kIsWeb && !Platform.isAndroid && !Platform.isIOS){
|
||||||
windowManager.getTitle().then((value) => oldWindowTitle = value);
|
windowManager.getTitle().then((value) => oldWindowTitle = value);
|
||||||
//windowManager.setTitle("Tetra Stats: ${t.statesViewTitle(number: widget.states.length, nickname: widget.states.last.id.toUpperCase())}");
|
windowManager.setTitle("Tetra Stats: ${t.statesViewTitle(number: widget.states.length, nickname: widget.states.last.id.toUpperCase())}");
|
||||||
}
|
}
|
||||||
super.initState();
|
super.initState();
|
||||||
}
|
}
|
||||||
|
@ -42,14 +41,14 @@ class StatesState extends State<StatesView> {
|
||||||
final t = Translations.of(context);
|
final t = Translations.of(context);
|
||||||
return Scaffold(
|
return Scaffold(
|
||||||
appBar: AppBar(
|
appBar: AppBar(
|
||||||
title: Text(t.statesViewTitle(number: "", nickname: widget.nickname)),
|
title: Text(t.statesViewTitle(number: widget.states.length, nickname: widget.states.first.id)),
|
||||||
actions: [
|
actions: [
|
||||||
IconButton(
|
IconButton(
|
||||||
onPressed: (){
|
onPressed: (){
|
||||||
Navigator.push(
|
Navigator.push(
|
||||||
context,
|
context,
|
||||||
MaterialPageRoute(
|
MaterialPageRoute(
|
||||||
builder: (context) => MatchesView(userID: widget.id, username: widget.nickname),
|
builder: (context) => MatchesView(userID: widget.states.first.id, username: widget.states.first.id),
|
||||||
),
|
),
|
||||||
);
|
);
|
||||||
}, icon: const Icon(Icons.list), tooltip: t.viewAllMatches)
|
}, icon: const Icon(Icons.list), tooltip: t.viewAllMatches)
|
||||||
|
@ -57,63 +56,30 @@ class StatesState extends State<StatesView> {
|
||||||
),
|
),
|
||||||
backgroundColor: Colors.black,
|
backgroundColor: Colors.black,
|
||||||
body: SafeArea(
|
body: SafeArea(
|
||||||
child: FutureBuilder<List<TetraLeague>>(future: teto.getStates(widget.id), builder: (context, snapshot) {
|
child: ListView.builder(
|
||||||
switch (snapshot.connectionState) {
|
itemCount: widget.states.length,
|
||||||
case ConnectionState.none:
|
|
||||||
case ConnectionState.waiting:
|
|
||||||
case ConnectionState.active:
|
|
||||||
return const Center(child: CircularProgressIndicator(color: Colors.white));
|
|
||||||
case ConnectionState.done:
|
|
||||||
if (snapshot.hasData) {
|
|
||||||
return ListView.builder(
|
|
||||||
itemCount: snapshot.data!.length,
|
|
||||||
prototypeItem: ListTile(
|
|
||||||
title: Text(""),
|
|
||||||
subtitle: Text("", style: TextStyle(color: Colors.grey)),
|
|
||||||
trailing: IconButton(icon: const Icon(Icons.delete_forever), onPressed: (){}),
|
|
||||||
),
|
|
||||||
itemBuilder: (context, index) {
|
itemBuilder: (context, index) {
|
||||||
return ListTile(
|
return ListTile(
|
||||||
title: Text(timestamp(snapshot.data![index].timestamp)),
|
title: Text(timestamp(widget.states[index].timestamp)),
|
||||||
subtitle: Text(
|
//subtitle: Text(t.statesViewEntry(level: widget.states[index].level.toStringAsFixed(2), gameTime: widget.states[index].gameTime, friends: widget.states[index].friendCount, rd: 0)),
|
||||||
t.statesViewEntry(level: f2.format(snapshot.data![index].tr), games: intf.format(snapshot.data![index].gamesPlayed), glicko: snapshot.data![index].glicko != null ? f2.format(snapshot.data![index].glicko) : "---", rd: snapshot.data![index].rd != null ? f2.format(snapshot.data![index].rd) : "--"),
|
|
||||||
style: TextStyle(color: Colors.grey),
|
|
||||||
),
|
|
||||||
trailing: IconButton(
|
trailing: IconButton(
|
||||||
icon: const Icon(Icons.delete_forever),
|
icon: const Icon(Icons.delete_forever),
|
||||||
onPressed: () {
|
onPressed: () {
|
||||||
teto.deleteState(snapshot.data![index].id+snapshot.data![index].timestamp.millisecondsSinceEpoch.toRadixString(16)).then((value) => setState(() {
|
//DateTime nn = widget.states[index].state;
|
||||||
ScaffoldMessenger.of(context).showSnackBar(SnackBar(content: Text(t.stateRemoved(date: timestamp(snapshot.data![index].timestamp)))));
|
// teto.deleteState(widget.states[index]).then((value) => setState(() {
|
||||||
}));
|
// ScaffoldMessenger.of(context).showSnackBar(SnackBar(content: Text(t.stateRemoved(date: timestamp(nn)))));
|
||||||
|
// }));
|
||||||
},
|
},
|
||||||
),
|
),
|
||||||
onTap: () {
|
onTap: () {
|
||||||
Navigator.push(
|
// Navigator.push(
|
||||||
context,
|
// context,
|
||||||
MaterialPageRoute(
|
// MaterialPageRoute(
|
||||||
builder: (context) => StateView(state: snapshot.data![index]),
|
// builder: (context) => StateView(state: widget.states[index]),
|
||||||
),
|
// ),
|
||||||
);
|
// );
|
||||||
},
|
},
|
||||||
);
|
);
|
||||||
});
|
})));
|
||||||
} else if (snapshot.hasError) {
|
|
||||||
return Center(child:
|
|
||||||
Column(
|
|
||||||
mainAxisSize: MainAxisSize.min,
|
|
||||||
children: [
|
|
||||||
Text(snapshot.error.toString(), style: const TextStyle(fontFamily: "Eurostile Round", fontSize: 42, fontWeight: FontWeight.bold), textAlign: TextAlign.center),
|
|
||||||
Padding(
|
|
||||||
padding: const EdgeInsets.only(top: 8.0),
|
|
||||||
child: Text(snapshot.stackTrace.toString(), style: const TextStyle(fontFamily: "Eurostile Round", fontSize: 18), textAlign: TextAlign.center),
|
|
||||||
),
|
|
||||||
],
|
|
||||||
)
|
|
||||||
);
|
|
||||||
}
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
return const Center(child: Text('default case of FutureBuilder', style: TextStyle(fontFamily: "Eurostile Round Extended", fontSize: 42), textAlign: TextAlign.center));
|
|
||||||
}
|
|
||||||
)));}
|
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
|
|
@ -78,7 +78,7 @@ class TrackedPlayersState extends State<TrackedPlayersView> {
|
||||||
case ConnectionState.active:
|
case ConnectionState.active:
|
||||||
return const Center(child: CircularProgressIndicator(color: Colors.white));
|
return const Center(child: CircularProgressIndicator(color: Colors.white));
|
||||||
case ConnectionState.done:
|
case ConnectionState.done:
|
||||||
final allPlayers = (snapshot.data != null) ? snapshot.data as Map<String, String> : <String, String>{};
|
final allPlayers = (snapshot.data != null) ? snapshot.data as Map<String, List<TetrioPlayer>> : <String, List<TetrioPlayer>>{};
|
||||||
List<String> keys = allPlayers.keys.toList();
|
List<String> keys = allPlayers.keys.toList();
|
||||||
return NestedScrollView(
|
return NestedScrollView(
|
||||||
headerSliverBuilder: (context, value) {
|
headerSliverBuilder: (context, value) {
|
||||||
|
@ -107,24 +107,24 @@ class TrackedPlayersState extends State<TrackedPlayersView> {
|
||||||
body: ListView.builder(
|
body: ListView.builder(
|
||||||
itemCount: allPlayers.length,
|
itemCount: allPlayers.length,
|
||||||
itemBuilder: (context, index) {
|
itemBuilder: (context, index) {
|
||||||
print(index);
|
|
||||||
return ListTile(
|
return ListTile(
|
||||||
title: Text(allPlayers[keys[index]]??"No nickname (huh?)"),
|
title: Text(t.trackedPlayersEntry(nickname: allPlayers[keys[index]]!.last.username, numberOfStates: allPlayers[keys[index]]!.length)),
|
||||||
subtitle: Text(keys[index], style: TextStyle(fontFamily: "Eurostile Round Condensed", color: Colors.grey)),
|
subtitle: Text(t.trackedPlayersDescription(firstStateDate: timestamp(allPlayers[keys[index]]!.first.state), lastStateDate: timestamp(allPlayers[keys[index]]!.last.state))),
|
||||||
trailing: IconButton(
|
trailing: IconButton(
|
||||||
icon: const Icon(Icons.delete_forever),
|
icon: const Icon(Icons.delete_forever),
|
||||||
onPressed: () {
|
onPressed: () {
|
||||||
|
String nn = allPlayers[keys[index]]!.last.username;
|
||||||
setState(() {teto.deletePlayer(keys[index]);});
|
setState(() {teto.deletePlayer(keys[index]);});
|
||||||
ScaffoldMessenger.of(context).showSnackBar(SnackBar(content: Text(t.trackedPlayersStatesDeleted(nickname: allPlayers[keys[index]]??"No nickname (huh?)"))));
|
ScaffoldMessenger.of(context).showSnackBar(SnackBar(content: Text(t.trackedPlayersStatesDeleted(nickname: nn))));
|
||||||
},
|
},
|
||||||
),
|
),
|
||||||
onTap: () {
|
onTap: () {
|
||||||
Navigator.push(
|
// Navigator.push(
|
||||||
context,
|
// context,
|
||||||
MaterialPageRoute(
|
// MaterialPageRoute(
|
||||||
builder: (context) => StatesView(nickname: allPlayers[keys[index]]!, id: keys[index]),
|
// builder: (context) => StatesView(states: allPlayers[keys[index]]!),
|
||||||
),
|
// ),
|
||||||
);
|
// );
|
||||||
},
|
},
|
||||||
);
|
);
|
||||||
}));
|
}));
|
||||||
|
|
|
@ -124,9 +124,8 @@ class _ZenithThingyState extends State<ZenithThingy> {
|
||||||
StatCellNum(playerStat: record!.aggregateStats.apm, playerStatLabel: t.statCellNum.apm, fractionDigits: 2, isScreenBig: bigScreen, higherIsBetter: true, smallDecimal: true),
|
StatCellNum(playerStat: record!.aggregateStats.apm, playerStatLabel: t.statCellNum.apm, fractionDigits: 2, isScreenBig: bigScreen, higherIsBetter: true, smallDecimal: true),
|
||||||
StatCellNum(playerStat: record!.aggregateStats.pps, playerStatLabel: t.statCellNum.pps, fractionDigits: 2, isScreenBig: bigScreen, higherIsBetter: true, smallDecimal: false),
|
StatCellNum(playerStat: record!.aggregateStats.pps, playerStatLabel: t.statCellNum.pps, fractionDigits: 2, isScreenBig: bigScreen, higherIsBetter: true, smallDecimal: false),
|
||||||
StatCellNum(playerStat: record!.aggregateStats.vs, playerStatLabel: t.statCellNum.vs, fractionDigits: 2, isScreenBig: bigScreen, higherIsBetter: true, smallDecimal: true),
|
StatCellNum(playerStat: record!.aggregateStats.vs, playerStatLabel: t.statCellNum.vs, fractionDigits: 2, isScreenBig: bigScreen, higherIsBetter: true, smallDecimal: true),
|
||||||
StatCellNum(playerStat: record!.stats.kills, playerStatLabel: "KO's", isScreenBig: bigScreen, higherIsBetter: true),
|
StatCellNum(playerStat: record!.stats.kills, playerStatLabel: "Kills", isScreenBig: bigScreen, higherIsBetter: true),
|
||||||
StatCellNum(playerStat: record!.stats.cps, playerStatLabel: "Climb speed\n(Peak: ${f2.format(record!.stats.zenith!.peakrank)})", fractionDigits: 2, isScreenBig: bigScreen, higherIsBetter: true),
|
StatCellNum(playerStat: record!.stats.cps, playerStatLabel: "CPS\n(Peak: ${f2.format(record!.stats.zenith!.peakrank)})", fractionDigits: 2, isScreenBig: bigScreen, higherIsBetter: true)
|
||||||
StatCellNum(playerStat: record!.stats.topBtB, playerStatLabel: "Top B2B\nchain", isScreenBig: bigScreen, higherIsBetter: true)
|
|
||||||
],
|
],
|
||||||
),
|
),
|
||||||
FinesseThingy(record?.stats.finesse, record?.stats.finessePercentage),
|
FinesseThingy(record?.stats.finesse, record?.stats.finessePercentage),
|
||||||
|
|
|
@ -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.6.9+35
|
version: 1.6.8+34
|
||||||
|
|
||||||
environment:
|
environment:
|
||||||
sdk: '>=3.0.0'
|
sdk: '>=3.0.0'
|
||||||
|
|
|
@ -89,6 +89,9 @@
|
||||||
"smooth": "Smooth",
|
"smooth": "Smooth",
|
||||||
"postSeason": "Off-season",
|
"postSeason": "Off-season",
|
||||||
"seasonStarts": "Season starts in:",
|
"seasonStarts": "Season starts in:",
|
||||||
|
"myMessadgeHeader": "A messadge from dan63",
|
||||||
|
"myMessadgeBody": "TETR.IO Tetra Channel API has been seriously modified after the last update, therefore, some functions may not work. I will try to catch up and add new stats (and return back the old ones) as soon, as public docs on new Tetra Channel API will be available.",
|
||||||
|
"preSeasonMessage": "Right now you can play unranked FT3 matches with hidden glicko (200 RD 🙂).\nSeason ${n} rules applied",
|
||||||
"nanow": "Not avaliable for now...",
|
"nanow": "Not avaliable for now...",
|
||||||
"seasonEnds": "Season ends in ${countdown}",
|
"seasonEnds": "Season ends in ${countdown}",
|
||||||
"seasonEnded": "Season has ended",
|
"seasonEnded": "Season has ended",
|
||||||
|
@ -155,7 +158,7 @@
|
||||||
"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",
|
||||||
"statesViewEntry": "${level} TR, ${glicko}±${rd} Glicko, ${games} игр сыграно",
|
"statesViewEntry": "Level ${level}, ${gameTime} of gametime, ${friends} friends, ${rd} RD",
|
||||||
"stateRemoved": "${date} state was removed from database!",
|
"stateRemoved": "${date} state was removed from database!",
|
||||||
"matchRemoved": "${date} match was removed from database!",
|
"matchRemoved": "${date} match was removed from database!",
|
||||||
"viewAllMatches": "View all matches",
|
"viewAllMatches": "View all matches",
|
||||||
|
|
|
@ -89,6 +89,9 @@
|
||||||
"smooth": "Гладкий",
|
"smooth": "Гладкий",
|
||||||
"postSeason": "Внесезонье",
|
"postSeason": "Внесезонье",
|
||||||
"seasonStarts": "Сезон начнётся через:",
|
"seasonStarts": "Сезон начнётся через:",
|
||||||
|
"myMessadgeHeader": "Сообщение от dan63",
|
||||||
|
"myMessadgeBody": "TETR.IO Tetra Channel API был серьёзно изменён после последнего обновления, поэтому некоторый функционал может не работать. Я постараюсь добавить новую статистику (и вернуть старую) как только будут опубликована новая документация по данному API.",
|
||||||
|
"preSeasonMessage": "Прямо сейчас вы можете сыграть безранговый матч до трёх побед со скрытым Glicko (200 RD 🙂).\nПрименяются правила ${n} сезона",
|
||||||
"nanow": "Пока недоступно...",
|
"nanow": "Пока недоступно...",
|
||||||
"seasonEnds": "Сезон закончится через ${countdown}",
|
"seasonEnds": "Сезон закончится через ${countdown}",
|
||||||
"seasonEnded": "Сезон закончился",
|
"seasonEnded": "Сезон закончился",
|
||||||
|
@ -155,7 +158,7 @@
|
||||||
"stateViewTitle": "Аккаунт ${nickname} ${date}",
|
"stateViewTitle": "Аккаунт ${nickname} ${date}",
|
||||||
"statesViewTitle": "${number} состояний аккаунта ${nickname}",
|
"statesViewTitle": "${number} состояний аккаунта ${nickname}",
|
||||||
"matchesViewTitle": "Матчи аккаунта ${nickname}",
|
"matchesViewTitle": "Матчи аккаунта ${nickname}",
|
||||||
"statesViewEntry": "${level} TR, ${glicko}±${rd} Glicko, ${games} игр сыграно",
|
"statesViewEntry": "${level} уровень, ${gameTime} сыграно, ${friends} друзей, ${rd} RD",
|
||||||
"stateRemoved": "Состояние от ${date} было удалено из локальной базы данных!",
|
"stateRemoved": "Состояние от ${date} было удалено из локальной базы данных!",
|
||||||
"matchRemoved": "Матч от ${date} был удален из локальной базы данных!",
|
"matchRemoved": "Матч от ${date} был удален из локальной базы данных!",
|
||||||
"viewAllMatches": "Все матчи",
|
"viewAllMatches": "Все матчи",
|
||||||
|
|
Loading…
Reference in New Issue