TetrioService now should eat less ram
Also app now checks if valid nickname was entered in "Your TETR.IO account" dialog. No need to paste userID, app will do it by itself.
This commit is contained in:
parent
07929ca6f7
commit
7099f7471a
|
@ -6,7 +6,7 @@
|
||||||
/// Locales: 2
|
/// Locales: 2
|
||||||
/// Strings: 1016 (508 per locale)
|
/// Strings: 1016 (508 per locale)
|
||||||
///
|
///
|
||||||
/// Built on 2024-02-03 at 12:49 UTC
|
/// Built on 2024-02-06 at 20:25 UTC
|
||||||
|
|
||||||
// coverage:ignore-file
|
// coverage:ignore-file
|
||||||
// ignore_for_file: type=lint
|
// ignore_for_file: type=lint
|
||||||
|
@ -224,8 +224,8 @@ class Translations implements BaseTranslations<AppLocale, Translations> {
|
||||||
String get importCancelled => 'Operation was cancelled';
|
String get importCancelled => 'Operation was cancelled';
|
||||||
String get importSuccess => 'Import successful';
|
String get importSuccess => 'Import successful';
|
||||||
String get yourID => 'Your TETR.IO account';
|
String get yourID => 'Your TETR.IO account';
|
||||||
String get yourIDAlertTitle => 'Your TETR.IO account nickname or ID';
|
String get yourIDAlertTitle => 'Your nickname in TETR.IO';
|
||||||
String get yourIDText => 'Every time when app loads, stats of that player will be fetched. Please prefer ID over nickname because nickname can be changed.';
|
String get yourIDText => 'When app loads, it will retrieve data for this account';
|
||||||
String get language => 'Language';
|
String get language => 'Language';
|
||||||
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';
|
||||||
|
@ -816,8 +816,8 @@ class _StringsRu implements Translations {
|
||||||
@override String get importCancelled => 'Операция была отменена';
|
@override String get importCancelled => 'Операция была отменена';
|
||||||
@override String get importSuccess => 'Успешно импортировано';
|
@override String get importSuccess => 'Успешно импортировано';
|
||||||
@override String get yourID => 'Ваш аккаунт в TETR.IO';
|
@override String get yourID => 'Ваш аккаунт в TETR.IO';
|
||||||
@override String get yourIDAlertTitle => 'Никнейм или ID вашего аккаунта в TETR.IO';
|
@override String get yourIDAlertTitle => 'Ваш ник в TETR.IO';
|
||||||
@override String get yourIDText => 'Каждый раз, когда приложение запускается, приложение будет получать статистику этого игрока. Пожалуйста, отдайте предпочтение ID, так как никнейм можно изменить.';
|
@override String get yourIDText => 'При запуске приложения оно будет получать статистику этого игрока.';
|
||||||
@override String get language => 'Язык (Language)';
|
@override String get language => 'Язык (Language)';
|
||||||
@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';
|
||||||
|
@ -1400,8 +1400,8 @@ extension on Translations {
|
||||||
case 'importCancelled': return 'Operation was cancelled';
|
case 'importCancelled': return 'Operation was cancelled';
|
||||||
case 'importSuccess': return 'Import successful';
|
case 'importSuccess': return 'Import successful';
|
||||||
case 'yourID': return 'Your TETR.IO account';
|
case 'yourID': return 'Your TETR.IO account';
|
||||||
case 'yourIDAlertTitle': return 'Your TETR.IO account nickname or ID';
|
case 'yourIDAlertTitle': return 'Your nickname in TETR.IO';
|
||||||
case 'yourIDText': return 'Every time when app loads, stats of that player will be fetched. Please prefer ID over nickname because nickname can be changed.';
|
case 'yourIDText': return 'When app loads, it will retrieve data for this account';
|
||||||
case 'language': return 'Language';
|
case 'language': return 'Language';
|
||||||
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';
|
||||||
|
@ -1918,8 +1918,8 @@ extension on _StringsRu {
|
||||||
case 'importCancelled': return 'Операция была отменена';
|
case 'importCancelled': return 'Операция была отменена';
|
||||||
case 'importSuccess': return 'Успешно импортировано';
|
case 'importSuccess': return 'Успешно импортировано';
|
||||||
case 'yourID': return 'Ваш аккаунт в TETR.IO';
|
case 'yourID': return 'Ваш аккаунт в TETR.IO';
|
||||||
case 'yourIDAlertTitle': return 'Никнейм или ID вашего аккаунта в TETR.IO';
|
case 'yourIDAlertTitle': return 'Ваш ник в TETR.IO';
|
||||||
case 'yourIDText': return 'Каждый раз, когда приложение запускается, приложение будет получать статистику этого игрока. Пожалуйста, отдайте предпочтение ID, так как никнейм можно изменить.';
|
case 'yourIDText': return 'При запуске приложения оно будет получать статистику этого игрока.';
|
||||||
case 'language': return 'Язык (Language)';
|
case 'language': return 'Язык (Language)';
|
||||||
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';
|
||||||
|
|
|
@ -27,7 +27,7 @@ const String endContext2 = "endContext2";
|
||||||
const String statesCol = "jsonStates";
|
const String statesCol = "jsonStates";
|
||||||
const String player1id = "player1id";
|
const String player1id = "player1id";
|
||||||
const String player2id = "player2id";
|
const String player2id = "player2id";
|
||||||
/// Table, that store players data, their stats and some moments of time
|
/// Table, that store players data, their stats at some moments of time
|
||||||
const String createTetrioUsersTable = '''
|
const String createTetrioUsersTable = '''
|
||||||
CREATE TABLE IF NOT EXISTS "tetrioUsers" (
|
CREATE TABLE IF NOT EXISTS "tetrioUsers" (
|
||||||
"id" TEXT UNIQUE,
|
"id" TEXT UNIQUE,
|
||||||
|
@ -66,7 +66,7 @@ const String createTetrioTLReplayStats = '''
|
||||||
''';
|
''';
|
||||||
|
|
||||||
class TetrioService extends DB {
|
class TetrioService extends DB {
|
||||||
Map<String, List<TetrioPlayer>> _players = {};
|
final Map<String, String> _players = {};
|
||||||
|
|
||||||
// I'm trying to send as less requests, as possible, so i'm caching the results of those requests.
|
// I'm trying to send as less requests, as possible, so i'm caching the results of those requests.
|
||||||
// Usually those maps looks like this: {"cached_until_unix_milliseconds": Object}
|
// Usually those maps looks like this: {"cached_until_unix_milliseconds": Object}
|
||||||
|
@ -82,9 +82,9 @@ class TetrioService extends DB {
|
||||||
/// We should have only one instanse of this service
|
/// We should have only one instanse of this service
|
||||||
static final TetrioService _shared = TetrioService._sharedInstance();
|
static final TetrioService _shared = TetrioService._sharedInstance();
|
||||||
factory TetrioService() => _shared;
|
factory TetrioService() => _shared;
|
||||||
late final StreamController<Map<String, List<TetrioPlayer>>> _tetrioStreamController;
|
late final StreamController<Map<String, String>> _tetrioStreamController;
|
||||||
TetrioService._sharedInstance() {
|
TetrioService._sharedInstance() {
|
||||||
_tetrioStreamController = StreamController<Map<String, List<TetrioPlayer>>>.broadcast(onListen: () {
|
_tetrioStreamController = StreamController<Map<String, String>>.broadcast(onListen: () {
|
||||||
_tetrioStreamController.sink.add(_players);
|
_tetrioStreamController.sink.add(_players);
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
@ -95,17 +95,15 @@ class TetrioService extends DB {
|
||||||
await _loadPlayers();
|
await _loadPlayers();
|
||||||
}
|
}
|
||||||
|
|
||||||
Stream<Map<String, List<TetrioPlayer>>> get allPlayers => _tetrioStreamController.stream;
|
Stream<Map<String, String>> get allPlayers => _tetrioStreamController.stream;
|
||||||
|
|
||||||
/// Loading and sending to the stream everyone.
|
/// Loading and sending to the stream everyone.
|
||||||
Future<void> _loadPlayers() async {
|
Future<void> _loadPlayers() async {
|
||||||
final allPlayers = await getAllPlayers();
|
final allPlayers = await getAllPlayerToTrack();
|
||||||
try{
|
for (var element in allPlayers) {
|
||||||
_players = allPlayers.toList().first; // ???
|
_players[element] = await getNicknameByID(element);
|
||||||
}catch (e){
|
|
||||||
developer.log("_loadPlayers: allPlayers.toList().first did oopsie", name: "services/tetrio_crud", error: e);
|
|
||||||
_players = {};
|
|
||||||
}
|
}
|
||||||
|
developer.log("_loadPlayers: $_players", name: "services/tetrio_crud");
|
||||||
_tetrioStreamController.add(_players);
|
_tetrioStreamController.add(_players);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -128,7 +126,10 @@ class TetrioService extends DB {
|
||||||
Future<String> getNicknameByID(String id) async {
|
Future<String> getNicknameByID(String id) async {
|
||||||
if (id.length <= 16) return id; // nicknames can be up to 16 symbols in length, that's how i'm differentiate nickname from ids
|
if (id.length <= 16) return id; // nicknames can be up to 16 symbols in length, that's how i'm differentiate nickname from ids
|
||||||
try{
|
try{
|
||||||
return await getPlayer(id).then((value) => value.last.username);
|
await ensureDbIsOpen();
|
||||||
|
final db = getDatabaseOrThrow();
|
||||||
|
var request = await db.query(tetrioUsersTable, limit: 1, where: '$idCol = ?', whereArgs: [id.toLowerCase()]);
|
||||||
|
return request.first[nickCol] as String;
|
||||||
} catch (e){
|
} catch (e){
|
||||||
return await fetchPlayer(id).then((value) => value.username);
|
return await fetchPlayer(id).then((value) => value.username);
|
||||||
}
|
}
|
||||||
|
@ -350,16 +351,8 @@ class TetrioService extends DB {
|
||||||
// trying to dump it to local DB
|
// trying to dump it to local DB
|
||||||
await ensureDbIsOpen();
|
await ensureDbIsOpen();
|
||||||
final db = getDatabaseOrThrow();
|
final db = getDatabaseOrThrow();
|
||||||
late List<TetrioPlayer> states;
|
List<TetrioPlayer> states = await getPlayer(id);
|
||||||
try{
|
if (states.isEmpty) await createPlayer(history.first);
|
||||||
// checking if tetra stats aware about that player TODO: is it necessary?
|
|
||||||
states = _players[id]!;
|
|
||||||
}catch(e){
|
|
||||||
// if somehow not - create it
|
|
||||||
var player = await fetchPlayer(id);
|
|
||||||
await createPlayer(player);
|
|
||||||
states = _players[id]!;
|
|
||||||
}
|
|
||||||
states.insertAll(0, history.reversed);
|
states.insertAll(0, history.reversed);
|
||||||
final Map<String, dynamic> statesJson = {};
|
final Map<String, dynamic> statesJson = {};
|
||||||
for (var e in states) { // making one big json out of this list
|
for (var e in states) { // making one big json out of this list
|
||||||
|
@ -367,7 +360,6 @@ class TetrioService extends DB {
|
||||||
}
|
}
|
||||||
// and putting it to local DB
|
// and putting it to local DB
|
||||||
await db.update(tetrioUsersTable, {idCol: id, nickCol: nick, statesCol: jsonEncode(statesJson)}, where: '$idCol = ?', whereArgs: [id]);
|
await db.update(tetrioUsersTable, {idCol: id, nickCol: nick, statesCol: jsonEncode(statesJson)}, where: '$idCol = ?', whereArgs: [id]);
|
||||||
_tetrioStreamController.add(_players);
|
|
||||||
return history;
|
return history;
|
||||||
case 404:
|
case 404:
|
||||||
developer.log("fetchTLHistory: Probably, history doesn't exist", name: "services/tetrio_crud", error: response.statusCode);
|
developer.log("fetchTLHistory: Probably, history doesn't exist", name: "services/tetrio_crud", error: response.statusCode);
|
||||||
|
@ -732,7 +724,7 @@ class TetrioService extends DB {
|
||||||
await db.delete(tetrioTLReplayStatsTable, where: '$idCol = ?', whereArgs: [rID]);
|
await db.delete(tetrioTLReplayStatsTable, where: '$idCol = ?', whereArgs: [rID]);
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Retrieves Blitz, 40 Lines and Zen records for a given [playerID] from Tetra Channel api. Returns Map, which contains user id (`user`),
|
/// Retrieves Blitz, 40 Lines and Zen records for a given [userID] from Tetra Channel api. Returns Map, which contains user id (`user`),
|
||||||
/// Blitz (`blitz`) and 40 Lines (`sprint`) record objects and Zen object (`zen`). Throws an exception if fails to retrieve.
|
/// Blitz (`blitz`) and 40 Lines (`sprint`) record objects and Zen object (`zen`). Throws an exception if fails to retrieve.
|
||||||
Future<Map<String, dynamic>> fetchRecords(String userID) async {
|
Future<Map<String, dynamic>> fetchRecords(String userID) async {
|
||||||
try{
|
try{
|
||||||
|
@ -811,9 +803,7 @@ class TetrioService extends DB {
|
||||||
// converting to json and store
|
// converting to json and store
|
||||||
final Map<String, dynamic> statesJson = {(tetrioPlayer.state.millisecondsSinceEpoch ~/ 1000).toString(): tetrioPlayer.toJson()};
|
final Map<String, dynamic> statesJson = {(tetrioPlayer.state.millisecondsSinceEpoch ~/ 1000).toString(): tetrioPlayer.toJson()};
|
||||||
db.insert(tetrioUsersTable, {idCol: tetrioPlayer.userId, nickCol: tetrioPlayer.username, statesCol: jsonEncode(statesJson)});
|
db.insert(tetrioUsersTable, {idCol: tetrioPlayer.userId, nickCol: tetrioPlayer.username, statesCol: jsonEncode(statesJson)});
|
||||||
_players.addEntries({
|
_players.addEntries({tetrioPlayer.userId: tetrioPlayer.username}.entries);
|
||||||
tetrioPlayer.userId: [tetrioPlayer]
|
|
||||||
}.entries);
|
|
||||||
_tetrioStreamController.add(_players);
|
_tetrioStreamController.add(_players);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -841,7 +831,6 @@ class TetrioService extends DB {
|
||||||
await ensureDbIsOpen();
|
await ensureDbIsOpen();
|
||||||
final db = getDatabaseOrThrow();
|
final db = getDatabaseOrThrow();
|
||||||
final players = await db.query(tetrioUsersToTrackTable);
|
final players = await db.query(tetrioUsersToTrackTable);
|
||||||
developer.log("getAllPlayerToTrack: $players", name: "services/tetrio_crud");
|
|
||||||
return players.map((noteRow) => noteRow["id"].toString());
|
return players.map((noteRow) => noteRow["id"].toString());
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -853,25 +842,22 @@ class TetrioService extends DB {
|
||||||
if (deletedPlayer != 1) {
|
if (deletedPlayer != 1) {
|
||||||
throw CouldNotDeletePlayer();
|
throw CouldNotDeletePlayer();
|
||||||
} else {
|
} else {
|
||||||
// _players.removeWhere((key, value) => key == id);
|
_players.removeWhere((key, value) => key == id);
|
||||||
// _tetrioStreamController.add(_players);
|
_tetrioStreamController.add(_players);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Saves state (which is [tetrioPlayer]) to the local database.
|
/// Saves state (which is [tetrioPlayer]) to the local database.
|
||||||
Future<void> storeState(TetrioPlayer tetrioPlayer) async {
|
Future<void> storeState(TetrioPlayer tetrioPlayer) async {
|
||||||
await ensureDbIsOpen();
|
// if tetrio player doesn't have entry in database - just calling different function
|
||||||
final db = getDatabaseOrThrow();
|
List<TetrioPlayer> states = await getPlayer(tetrioPlayer.userId);
|
||||||
late List<TetrioPlayer> states;
|
if (states.isEmpty) {
|
||||||
try { // retrieveing previous states
|
await createPlayer(tetrioPlayer);
|
||||||
states = _players[tetrioPlayer.userId]!;
|
return;
|
||||||
} catch (e) { // nothing found - player not exist - create them
|
|
||||||
await createPlayer(tetrioPlayer);
|
|
||||||
states = await getPlayer(tetrioPlayer.userId);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// we not going to add state, that is same, as the previous
|
// we not going to add state, that is same, as the previous
|
||||||
bool test = _players[tetrioPlayer.userId]!.last.isSameState(tetrioPlayer);
|
bool test = states.last.isSameState(tetrioPlayer);
|
||||||
if (test == false) states.add(tetrioPlayer);
|
if (test == false) states.add(tetrioPlayer);
|
||||||
|
|
||||||
// Making map of the states
|
// Making map of the states
|
||||||
|
@ -880,21 +866,21 @@ class TetrioService extends DB {
|
||||||
// Saving in format: {"unix_seconds": json_of_state}
|
// Saving in format: {"unix_seconds": json_of_state}
|
||||||
statesJson.addEntries({(e.state.millisecondsSinceEpoch ~/ 1000).toString(): e.toJson()}.entries);
|
statesJson.addEntries({(e.state.millisecondsSinceEpoch ~/ 1000).toString(): e.toJson()}.entries);
|
||||||
}
|
}
|
||||||
|
|
||||||
// Rewrite our database
|
// Rewrite our database
|
||||||
|
await ensureDbIsOpen();
|
||||||
|
final db = getDatabaseOrThrow();
|
||||||
await db.update(tetrioUsersTable, {idCol: tetrioPlayer.userId, nickCol: tetrioPlayer.username, statesCol: jsonEncode(statesJson)},
|
await db.update(tetrioUsersTable, {idCol: tetrioPlayer.userId, nickCol: tetrioPlayer.username, statesCol: jsonEncode(statesJson)},
|
||||||
where: '$idCol = ?', whereArgs: [tetrioPlayer.userId]);
|
where: '$idCol = ?', whereArgs: [tetrioPlayer.userId]);
|
||||||
_players[tetrioPlayer.userId]!.add(tetrioPlayer);
|
|
||||||
_tetrioStreamController.add(_players);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Remove state (which is [tetrioPlayer]) from the local database
|
/// Remove state (which is [tetrioPlayer]) from the local database
|
||||||
Future<void> deleteState(TetrioPlayer tetrioPlayer) async {
|
Future<void> deleteState(TetrioPlayer tetrioPlayer) async {
|
||||||
await ensureDbIsOpen();
|
await ensureDbIsOpen();
|
||||||
final db = getDatabaseOrThrow();
|
final db = getDatabaseOrThrow();
|
||||||
late List<TetrioPlayer> states;
|
List<TetrioPlayer> states = await getPlayer(tetrioPlayer.userId);
|
||||||
// removing state from map that contain every state of each user
|
// removing state from map that contain every state of each user
|
||||||
_players[tetrioPlayer.userId]!.removeWhere((element) => element.state == tetrioPlayer.state);
|
states.removeWhere((element) => element.state == tetrioPlayer.state);
|
||||||
states = _players[tetrioPlayer.userId]!;
|
|
||||||
|
|
||||||
// Making map of the states (without deleted one)
|
// Making map of the states (without deleted one)
|
||||||
final Map<String, dynamic> statesJson = {};
|
final Map<String, dynamic> statesJson = {};
|
||||||
|
@ -904,7 +890,6 @@ class TetrioService extends DB {
|
||||||
// Rewriting database entry with new json
|
// Rewriting database entry with new json
|
||||||
await db.update(tetrioUsersTable, {idCol: tetrioPlayer.userId, nickCol: tetrioPlayer.username, statesCol: jsonEncode(statesJson)},
|
await db.update(tetrioUsersTable, {idCol: tetrioPlayer.userId, nickCol: tetrioPlayer.username, statesCol: jsonEncode(statesJson)},
|
||||||
where: '$idCol = ?', whereArgs: [tetrioPlayer.userId]);
|
where: '$idCol = ?', whereArgs: [tetrioPlayer.userId]);
|
||||||
_players[tetrioPlayer.userId]!.add(tetrioPlayer);
|
|
||||||
_tetrioStreamController.add(_players);
|
_tetrioStreamController.add(_players);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -924,7 +909,7 @@ class TetrioService extends DB {
|
||||||
rawStates.forEach((k, v) => states.add(TetrioPlayer.fromJson(v, DateTime.fromMillisecondsSinceEpoch(int.parse(k) * 1000), id, results.first[nickCol] as String)));
|
rawStates.forEach((k, v) => states.add(TetrioPlayer.fromJson(v, DateTime.fromMillisecondsSinceEpoch(int.parse(k) * 1000), id, results.first[nickCol] as String)));
|
||||||
// updating the stream
|
// updating the stream
|
||||||
_players.removeWhere((key, value) => key == id);
|
_players.removeWhere((key, value) => key == id);
|
||||||
_players.addEntries({states.last.userId: states}.entries);
|
_players.addEntries({states.last.userId: states.last.username}.entries);
|
||||||
_tetrioStreamController.add(_players);
|
_tetrioStreamController.add(_players);
|
||||||
return states;
|
return states;
|
||||||
}
|
}
|
||||||
|
@ -1034,20 +1019,18 @@ class TetrioService extends DB {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Basucally, retrieves whole [tetrioUsersTable] and do stupud things idk
|
/// Retrieves whole [tetrioUsersTable] and returns Map with [TetrioPlayer] objects of everyone in database
|
||||||
/// Returns god knows what. TODO: Rewrite this shit
|
Future<Map<String, List<TetrioPlayer>>> getAllPlayers() async {
|
||||||
Future<Iterable<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, List<TetrioPlayer>> data = {};
|
Map<String, List<TetrioPlayer>> data = {};
|
||||||
return players.map((row) {
|
for (var entry in players){
|
||||||
// what the fuck am i doing here?
|
var test = json.decode(entry['jsonStates'] as String);
|
||||||
var test = json.decode(row['jsonStates'] as String);
|
|
||||||
List<TetrioPlayer> states = [];
|
List<TetrioPlayer> states = [];
|
||||||
test.forEach((k, v) => states.add(TetrioPlayer.fromJson(v, DateTime.fromMillisecondsSinceEpoch(int.parse(k) * 1000), row[idCol] as String, row[nickCol] as String)));
|
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);
|
data.addEntries({states.last.userId: states}.entries);
|
||||||
return data;
|
}
|
||||||
});
|
return data;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -494,8 +494,9 @@ class _NavDrawerState extends State<NavDrawer> {
|
||||||
case ConnectionState.waiting:
|
case ConnectionState.waiting:
|
||||||
case ConnectionState.active:
|
case ConnectionState.active:
|
||||||
final allPlayers = (snapshot.data != null)
|
final allPlayers = (snapshot.data != null)
|
||||||
? snapshot.data as Map<String, List<TetrioPlayer>>
|
? snapshot.data as Map<String, String>
|
||||||
: <String, List<TetrioPlayer>>{};
|
: <String, String>{};
|
||||||
|
allPlayers.remove(prefs.getString("player") ?? "6098518e3d5155e6ec429cdc"); // player from the home button will be delisted
|
||||||
List<String> keys = allPlayers.keys.toList();
|
List<String> keys = allPlayers.keys.toList();
|
||||||
return NestedScrollView(
|
return NestedScrollView(
|
||||||
headerSliverBuilder: (context, value) {
|
headerSliverBuilder: (context, value) {
|
||||||
|
@ -550,7 +551,7 @@ class _NavDrawerState extends State<NavDrawer> {
|
||||||
itemBuilder: (context, index) {
|
itemBuilder: (context, index) {
|
||||||
var i = allPlayers.length-1-index; // Last players in this map are most recent ones, they are gonna be shown at the top.
|
var i = allPlayers.length-1-index; // Last players in this map are most recent ones, they are gonna be shown at the top.
|
||||||
return ListTile(
|
return ListTile(
|
||||||
title: Text(allPlayers[keys[i]]?.last.username as String), // Takes last known username from list of states
|
title: Text(allPlayers[keys[i]]??keys[i]), // Takes last known username from list of states
|
||||||
onTap: () {
|
onTap: () {
|
||||||
widget.changePlayer(keys[i]); // changes to chosen player
|
widget.changePlayer(keys[i]); // changes to chosen player
|
||||||
Navigator.of(context).pop(); // and closes itself.
|
Navigator.of(context).pop(); // and closes itself.
|
||||||
|
|
|
@ -1,4 +1,5 @@
|
||||||
import 'dart:io';
|
import 'dart:io';
|
||||||
|
import 'package:tetra_stats/data_objects/tetrio.dart';
|
||||||
import 'package:tetra_stats/main.dart' show packageInfo;
|
import 'package:tetra_stats/main.dart' show packageInfo;
|
||||||
import 'package:file_selector/file_selector.dart';
|
import 'package:file_selector/file_selector.dart';
|
||||||
import 'package:file_picker/file_picker.dart';
|
import 'package:file_picker/file_picker.dart';
|
||||||
|
@ -66,6 +67,11 @@ class SettingsState extends State<SettingsView> {
|
||||||
await _setDefaultNickname(player);
|
await _setDefaultNickname(player);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
Future<void> _removePlayer() async {
|
||||||
|
await prefs.remove('player');
|
||||||
|
await _setDefaultNickname("dan63047");
|
||||||
|
}
|
||||||
|
|
||||||
@override
|
@override
|
||||||
Widget build(BuildContext context) {
|
Widget build(BuildContext context) {
|
||||||
final t = Translations.of(context);
|
final t = Translations.of(context);
|
||||||
|
@ -212,9 +218,21 @@ class SettingsState extends State<SettingsView> {
|
||||||
),
|
),
|
||||||
TextButton(
|
TextButton(
|
||||||
child: Text(t.popupActions.submit),
|
child: Text(t.popupActions.submit),
|
||||||
onPressed: () {
|
onPressed: () async {
|
||||||
_setPlayer(_playertext.text.toLowerCase().trim());
|
if (_playertext.text.isEmpty) {
|
||||||
Navigator.of(context).pop();
|
_removePlayer();
|
||||||
|
Navigator.of(context).pop();
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
late TetrioPlayer user;
|
||||||
|
try{
|
||||||
|
user = await teto.fetchPlayer(_playertext.text.toLowerCase().trim());
|
||||||
|
}on Exception{
|
||||||
|
if (context.mounted) ScaffoldMessenger.of(context).showSnackBar(SnackBar(content: Text(t.errors.noSuchUser)));
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
_setPlayer(user.userId);
|
||||||
|
if (context.mounted) Navigator.of(context).pop();
|
||||||
setState(() {});
|
setState(() {});
|
||||||
},
|
},
|
||||||
)
|
)
|
||||||
|
|
|
@ -70,14 +70,15 @@ class TrackedPlayersState extends State<TrackedPlayersView> {
|
||||||
),
|
),
|
||||||
backgroundColor: Colors.black,
|
backgroundColor: Colors.black,
|
||||||
body: SafeArea(
|
body: SafeArea(
|
||||||
child: StreamBuilder(
|
child: FutureBuilder(
|
||||||
stream: teto.allPlayers,
|
future: teto.getAllPlayers(),
|
||||||
builder: (context, snapshot) {
|
builder: (context, snapshot) {
|
||||||
switch (snapshot.connectionState) {
|
switch (snapshot.connectionState) {
|
||||||
case ConnectionState.none:
|
case ConnectionState.none:
|
||||||
return const Center(child: Text('none case of StreamBuilder'));
|
|
||||||
case ConnectionState.waiting:
|
case ConnectionState.waiting:
|
||||||
case ConnectionState.active:
|
case ConnectionState.active:
|
||||||
|
return const Center(child: CircularProgressIndicator(color: Colors.white));
|
||||||
|
case ConnectionState.done:
|
||||||
final allPlayers = (snapshot.data != null) ? snapshot.data as Map<String, List<TetrioPlayer>> : <String, List<TetrioPlayer>>{};
|
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(
|
||||||
|
@ -114,7 +115,7 @@ class TrackedPlayersState extends State<TrackedPlayersView> {
|
||||||
icon: const Icon(Icons.delete_forever),
|
icon: const Icon(Icons.delete_forever),
|
||||||
onPressed: () {
|
onPressed: () {
|
||||||
String nn = allPlayers[keys[index]]!.last.username;
|
String nn = allPlayers[keys[index]]!.last.username;
|
||||||
teto.deletePlayer(keys[index]);
|
setState(() {teto.deletePlayer(keys[index]);});
|
||||||
ScaffoldMessenger.of(context).showSnackBar(SnackBar(content: Text(t.trackedPlayersStatesDeleted(nickname: nn))));
|
ScaffoldMessenger.of(context).showSnackBar(SnackBar(content: Text(t.trackedPlayersStatesDeleted(nickname: nn))));
|
||||||
},
|
},
|
||||||
),
|
),
|
||||||
|
@ -128,10 +129,6 @@ class TrackedPlayersState extends State<TrackedPlayersView> {
|
||||||
},
|
},
|
||||||
);
|
);
|
||||||
}));
|
}));
|
||||||
case ConnectionState.done:
|
|
||||||
return const Center(
|
|
||||||
child: Text('done case of StreamBuilder',
|
|
||||||
style: TextStyle(fontFamily: "Eurostile Round Extended", fontSize: 42), textAlign: TextAlign.center));
|
|
||||||
}
|
}
|
||||||
})),
|
})),
|
||||||
);
|
);
|
||||||
|
|
|
@ -89,8 +89,8 @@
|
||||||
"importCancelled": "Operation was cancelled",
|
"importCancelled": "Operation was cancelled",
|
||||||
"importSuccess": "Import successful",
|
"importSuccess": "Import successful",
|
||||||
"yourID": "Your TETR.IO account",
|
"yourID": "Your TETR.IO account",
|
||||||
"yourIDAlertTitle": "Your TETR.IO account nickname or ID",
|
"yourIDAlertTitle": "Your nickname in TETR.IO",
|
||||||
"yourIDText": "Every time when app loads, stats of that player will be fetched. Please prefer ID over nickname because nickname can be changed.",
|
"yourIDText": "When app loads, it will retrieve data for this account",
|
||||||
"language": "Language",
|
"language": "Language",
|
||||||
"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",
|
||||||
|
|
|
@ -89,8 +89,8 @@
|
||||||
"importCancelled": "Операция была отменена",
|
"importCancelled": "Операция была отменена",
|
||||||
"importSuccess": "Успешно импортировано",
|
"importSuccess": "Успешно импортировано",
|
||||||
"yourID": "Ваш аккаунт в TETR.IO",
|
"yourID": "Ваш аккаунт в TETR.IO",
|
||||||
"yourIDAlertTitle": "Никнейм или ID вашего аккаунта в TETR.IO",
|
"yourIDAlertTitle": "Ваш ник в TETR.IO",
|
||||||
"yourIDText": "Каждый раз, когда приложение запускается, приложение будет получать статистику этого игрока. Пожалуйста, отдайте предпочтение ID, так как никнейм можно изменить.",
|
"yourIDText": "При запуске приложения оно будет получать статистику этого игрока.",
|
||||||
"language": "Язык (Language)",
|
"language": "Язык (Language)",
|
||||||
"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",
|
||||||
|
|
Binary file not shown.
After Width: | Height: | Size: 7.1 KiB |
Loading…
Reference in New Issue