Thinking about how to use TetrioService

This commit is contained in:
dan63047 2023-06-08 00:12:21 +03:00
parent 10f4063bf2
commit 18f02a9c54
7 changed files with 725 additions and 910 deletions

View File

@ -33,7 +33,7 @@ class TetrioPlayer {
late int supporterTier; late int supporterTier;
late bool verified; late bool verified;
bool? badstanding; bool? badstanding;
bool? bot; String? botmaster;
late Connections connections; late Connections connections;
late TetraLeagueAlpha tlSeason1; late TetraLeagueAlpha tlSeason1;
List<RecordSingle?> sprint = []; List<RecordSingle?> sprint = [];
@ -60,7 +60,7 @@ class TetrioPlayer {
required this.supporterTier, required this.supporterTier,
required this.verified, required this.verified,
this.badstanding, this.badstanding,
this.bot, this.botmaster,
required this.connections, required this.connections,
required this.tlSeason1, required this.tlSeason1,
required this.sprint, required this.sprint,
@ -98,6 +98,7 @@ class TetrioPlayer {
distinguishment = json['distinguishment'] != null ? Distinguishment.fromJson(json['distinguishment']) : null; distinguishment = json['distinguishment'] != null ? Distinguishment.fromJson(json['distinguishment']) : null;
friendCount = json['friend_count'] ?? 0; friendCount = json['friend_count'] ?? 0;
badstanding = json['badstanding']; badstanding = json['badstanding'];
botmaster = json['botmaster'];
if (fetchRecords) { if (fetchRecords) {
var url = Uri.https('ch.tetr.io', 'api/users/$userId/records'); var url = Uri.https('ch.tetr.io', 'api/users/$userId/records');
Future response = http.get(url); Future response = http.get(url);
@ -124,25 +125,25 @@ class TetrioPlayer {
data['_id'] = userId; data['_id'] = userId;
data['username'] = username; data['username'] = username;
data['role'] = role; data['role'] = role;
data['ts'] = registrationTime?.toString(); if (registrationTime != null) data['ts'] = registrationTime?.toString();
data['badges'] = badges.map((v) => v.toJson()).toList(); data['badges'] = badges.map((v) => v.toJson()).toList();
data['xp'] = xp; data['xp'] = xp;
data['gamesplayed'] = gamesPlayed; data['gamesplayed'] = gamesPlayed;
data['gameswon'] = gamesWon; data['gameswon'] = gamesWon;
data['gametime'] = gameTime.inMicroseconds / 1000000; data['gametime'] = gameTime.inMicroseconds / 1000000;
data['country'] = country; if (country != null) data['country'] = country;
data['supporter_tier'] = supporterTier; data['supporter_tier'] = supporterTier;
data['verified'] = verified; data['verified'] = verified;
data['league'] = tlSeason1.toJson(); data['league'] = tlSeason1.toJson();
data['distinguishment'] = distinguishment?.toJson(); if (distinguishment != null) data['distinguishment'] = distinguishment?.toJson();
data['avatar_revision'] = avatarRevision; if (avatarRevision != null) data['avatar_revision'] = avatarRevision;
data['banner_revision'] = bannerRevision; if (bannerRevision != null) data['banner_revision'] = bannerRevision;
data['bio'] = bio; if (data['bio'] != null) data['bio'] = bio;
data['connections'] = connections.toJson(); data['connections'] = connections.toJson();
data['friend_count'] = friendCount; data['friend_count'] = friendCount;
data['badstanding'] = badstanding; if (badstanding != null) data['badstanding'] = badstanding;
data['bot'] = bot; if (botmaster != null) data['botmaster'] = botmaster;
developer.log("TetrioPlayer.toJson: $bot", name: "data_objects/tetrio"); developer.log("TetrioPlayer.toJson: $data", name: "data_objects/tetrio");
return data; return data;
} }
@ -161,7 +162,7 @@ class TetrioPlayer {
if (supporterTier != other.supporterTier) return false; if (supporterTier != other.supporterTier) return false;
if (verified != other.verified) return false; if (verified != other.verified) return false;
if (badstanding != other.badstanding) return false; if (badstanding != other.badstanding) return false;
if (bot != other.bot) return false; if (botmaster != other.botmaster) return false;
if (connections != other.connections) return false; if (connections != other.connections) return false;
if (tlSeason1 != other.tlSeason1) return false; if (tlSeason1 != other.tlSeason1) return false;
if (distinguishment != other.distinguishment) return false; if (distinguishment != other.distinguishment) return false;
@ -170,7 +171,7 @@ class TetrioPlayer {
@override @override
String toString() { String toString() {
return "$username ($userId)"; return "$username ($state)";
} }
@override @override
@ -678,20 +679,20 @@ class TetraLeagueAlpha {
data['gamesplayed'] = gamesPlayed; data['gamesplayed'] = gamesPlayed;
data['gameswon'] = gamesWon; data['gameswon'] = gamesWon;
data['rating'] = rating; data['rating'] = rating;
data['glicko'] = glicko; if (glicko != null) data['glicko'] = glicko;
data['rd'] = rd; if (rd != null) data['rd'] = rd;
data['rank'] = rank; data['rank'] = rank;
data['bestrank'] = bestRank; data['bestrank'] = bestRank;
data['apm'] = apm; if (apm != null) data['apm'] = apm;
data['pps'] = pps; if (pps != null) data['pps'] = pps;
data['vs'] = vs; if (vs != null) data['vs'] = vs;
data['decaying'] = decaying; data['decaying'] = decaying;
data['standing'] = standing; data['standing'] = standing;
data['percentile'] = percentile; data['percentile'] = percentile;
data['standing_local'] = standingLocal; data['standing_local'] = standingLocal;
data['prev_rank'] = prevRank; if (prevRank != null) data['prev_rank'] = prevRank;
data['prev_at'] = prevAt; data['prev_at'] = prevAt;
data['next_rank'] = nextRank; if (nextRank != null) data['next_rank'] = nextRank;
data['next_at'] = nextAt; data['next_at'] = nextAt;
data['percentile_rank'] = percentileRank; data['percentile_rank'] = percentileRank;
return data; return data;
@ -710,7 +711,7 @@ class RecordSingle {
RecordSingle({required this.userId, required this.replayId, required this.ownId, this.timestamp, this.endContext, this.rank}); RecordSingle({required this.userId, required this.replayId, required this.ownId, this.timestamp, this.endContext, this.rank});
RecordSingle.fromJson(Map<String, dynamic> json, int? ran) { RecordSingle.fromJson(Map<String, dynamic> json, int? ran) {
developer.log("RecordSingle.fromJson: $json", name: "data_objects/tetrio"); //developer.log("RecordSingle.fromJson: $json", name: "data_objects/tetrio");
ownId = json['_id']; ownId = json['_id'];
endContext = json['endcontext'] != null ? EndContextSingle.fromJson(json['endcontext']) : null; endContext = json['endcontext'] != null ? EndContextSingle.fromJson(json['endcontext']) : null;
replayId = json['replayid']; replayId = json['replayid'];
@ -777,3 +778,41 @@ class Distinguishment {
return data; return data;
} }
} }
class TetrioPlayersLeaderboard {
late String type;
late List<TetrioPlayerFromLeaderboard> leaderboard;
TetrioPlayersLeaderboard(this.type, this.leaderboard);
TetrioPlayersLeaderboard.fromJson(Map<String, dynamic> json, String type) {
type = type;
for (Map<String, dynamic> entry in json['users']) {
leaderboard.add(TetrioPlayerFromLeaderboard.fromJson(entry));
}
}
}
class TetrioPlayerFromLeaderboard {
late String userId;
late String username;
late String role;
late double xp;
String? country;
late bool supporter;
late bool verified;
late TetraLeagueAlpha league;
TetrioPlayerFromLeaderboard(this.userId, this.username, this.role, this.xp, this.country, this.supporter, this.verified, this.league);
TetrioPlayerFromLeaderboard.fromJson(Map<String, dynamic> json) {
userId = json['_id'];
username = json['username'];
role = json['role'];
xp = json['xp'].toDouble();
country = json['country '];
supporter = json['supporter'];
verified = json['verified'];
league = TetraLeagueAlpha.fromJson(json['league']);
}
}

View File

@ -4,13 +4,19 @@ import 'package:tetra_stats/views/main_view.dart';
import 'package:tetra_stats/views/compare_view.dart'; import 'package:tetra_stats/views/compare_view.dart';
import 'package:tetra_stats/views/settings_view.dart'; import 'package:tetra_stats/views/settings_view.dart';
import 'package:tetra_stats/views/states_view.dart'; import 'package:tetra_stats/views/states_view.dart';
import 'package:tetra_stats/views/calc_view.dart';
void main() { void main() {
sqfliteFfiInit(); sqfliteFfiInit();
databaseFactory = databaseFactoryFfi; databaseFactory = databaseFactoryFfi;
runApp(MaterialApp( runApp(MaterialApp(
home: const MainView(), home: const MainView(),
routes: {"/settings": (context) => const SettingsView(), "/compare": (context) => const CompareView(), "/states": (context) => const StatesView()}, routes: {
"/settings": (context) => const SettingsView(),
"/compare": (context) => const CompareView(),
"/states": (context) => const StatesView(),
"/calc": (context) => const CalcView()
},
theme: ThemeData( theme: ThemeData(
fontFamily: 'Eurostile Round', fontFamily: 'Eurostile Round',
colorScheme: const ColorScheme.dark(primary: Colors.cyanAccent, secondary: Colors.purpleAccent), colorScheme: const ColorScheme.dark(primary: Colors.cyanAccent, secondary: Colors.purpleAccent),

View File

@ -42,4 +42,12 @@ class DB {
return db; return db;
} }
} }
Future<void> _ensureDbIsOpen(DB udb) async {
try {
await udb.open();
} on DatabaseAlreadyOpen {
// empty
}
}
} }

View File

@ -1,6 +1,7 @@
import 'dart:async'; import 'dart:async';
import 'dart:convert'; import 'dart:convert';
import 'dart:developer' as developer; import 'dart:developer' as developer;
import 'package:http/http.dart' as http;
// import 'package:sqflite/sqflite.dart'; // import 'package:sqflite/sqflite.dart';
// import 'package:path_provider/path_provider.dart' show MissingPlatformDirectoryException, getApplicationDocumentsDirectory; // import 'package:path_provider/path_provider.dart' show MissingPlatformDirectoryException, getApplicationDocumentsDirectory;
// import 'package:path/path.dart' show join; // import 'package:path/path.dart' show join;
@ -31,7 +32,7 @@ class TetrioService {
Future<void> _cachePlayers(DB udb) async { Future<void> _cachePlayers(DB udb) async {
final allPlayers = await getAllPlayers(udb: udb); final allPlayers = await getAllPlayers(udb: udb);
_players = allPlayers.first; _players = allPlayers.toList().first; // ???
_tetrioStreamController.add(_players); _tetrioStreamController.add(_players);
developer.log("_cachePlayers: $_players", name: "services/tetrio_crud"); developer.log("_cachePlayers: $_players", name: "services/tetrio_crud");
} }
@ -58,6 +59,7 @@ class TetrioService {
// } // }
Future<void> createPlayer({required TetrioPlayer tetrioPlayer, required DB udb}) async { Future<void> createPlayer({required TetrioPlayer tetrioPlayer, required DB udb}) async {
_ensureDbIsOpen(udb);
final db = udb.getDatabaseOrThrow(); final db = udb.getDatabaseOrThrow();
final results = await db.query(tetrioUsersTable, limit: 1, where: '$idCol = ?', whereArgs: [tetrioPlayer.userId.toLowerCase()]); final results = await db.query(tetrioUsersTable, limit: 1, where: '$idCol = ?', whereArgs: [tetrioPlayer.userId.toLowerCase()]);
if (results.isNotEmpty) { if (results.isNotEmpty) {
@ -72,9 +74,16 @@ class TetrioService {
} }
Future<void> storeState(TetrioPlayer tetrioPlayer, DB udb) async { Future<void> storeState(TetrioPlayer tetrioPlayer, DB udb) async {
_ensureDbIsOpen(udb);
final db = udb.getDatabaseOrThrow(); final db = udb.getDatabaseOrThrow();
List<TetrioPlayer> states = await getPlayer(id: tetrioPlayer.userId, udb: udb); late List<TetrioPlayer> states;
states.add(tetrioPlayer); try {
states = await getPlayer(id: tetrioPlayer.userId, udb: udb);
} on TetrioPlayerNotExist {
await createPlayer(tetrioPlayer: tetrioPlayer, udb: udb);
states = await getPlayer(id: tetrioPlayer.userId, udb: udb);
}
if (!_players[tetrioPlayer.userId]!.last.isSameState(tetrioPlayer)) states.add(tetrioPlayer);
final Map<String, dynamic> statesJson = {}; final Map<String, dynamic> statesJson = {};
for (var e in states) { for (var e in states) {
statesJson.addEntries({e.state.millisecondsSinceEpoch.toString(): e.toJson()}.entries); statesJson.addEntries({e.state.millisecondsSinceEpoch.toString(): e.toJson()}.entries);
@ -86,6 +95,7 @@ class TetrioService {
} }
Future<List<TetrioPlayer>> getPlayer({required String id, required DB udb}) async { Future<List<TetrioPlayer>> getPlayer({required String id, required DB udb}) async {
_ensureDbIsOpen(udb);
final db = udb.getDatabaseOrThrow(); final db = udb.getDatabaseOrThrow();
List<TetrioPlayer> states = []; List<TetrioPlayer> states = [];
final results = await db.query(tetrioUsersTable, limit: 1, where: '$idCol = ?', whereArgs: [id.toLowerCase()]); final results = await db.query(tetrioUsersTable, limit: 1, where: '$idCol = ?', whereArgs: [id.toLowerCase()]);
@ -102,6 +112,29 @@ class TetrioService {
} }
} }
Future<TetrioPlayer> fetchPlayer(String user, DB udb, bool addToDB) async {
var url = Uri.https('ch.tetr.io', 'api/users/${user.toLowerCase().trim()}');
final response = await http.get(url);
if (response.statusCode == 200) {
if (jsonDecode(response.body)['success']) {
TetrioPlayer player = TetrioPlayer.fromJson(
jsonDecode(response.body)['data']['user'], DateTime.fromMillisecondsSinceEpoch(jsonDecode(response.body)['cache']['cached_at'], isUtc: true), true);
if (addToDB) {
_ensureDbIsOpen(udb);
storeState(player, udb);
}
return player;
} else {
developer.log("fetchTetrioPlayer User dosen't exist", name: "services/tetrio_crud", error: response.body);
throw Exception("User doesn't exist");
}
} else {
developer.log("fetchTetrioPlayer Failed to fetch player", name: "services/tetrio_crud", error: response.statusCode);
throw Exception('Failed to fetch player');
}
}
Future<void> _ensureDbIsOpen(DB udb) async { Future<void> _ensureDbIsOpen(DB udb) async {
try { try {
await udb.open(); await udb.open();
@ -117,6 +150,7 @@ class TetrioService {
Map<String, List<TetrioPlayer>> data = {}; Map<String, List<TetrioPlayer>> data = {};
//developer.log("getAllPlayers: $players", name: "services/tetrio_crud"); //developer.log("getAllPlayers: $players", name: "services/tetrio_crud");
return players.map((row) { return players.map((row) {
// what the fuck am i doing here?
var test = json.decode(row['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)), false))); test.forEach((k, v) => states.add(TetrioPlayer.fromJson(v, DateTime.fromMillisecondsSinceEpoch(int.parse(k)), false)));

21
lib/views/calc_view.dart Normal file
View File

@ -0,0 +1,21 @@
import 'package:flutter/material.dart';
class CalcView extends StatefulWidget {
const CalcView({Key? key}) : super(key: key);
@override
State<StatefulWidget> createState() => CalcState();
}
class CalcState extends State<CalcView> {
@override
Widget build(BuildContext context) {
return Scaffold(
appBar: AppBar(
title: const Text("Stats Calculator"),
),
backgroundColor: Colors.black,
body: const SafeArea(child: Text("Maybe next commit idk... or shoud i think about CRUD??? idk idk")),
);
}
}

File diff suppressed because it is too large Load Diff

View File

@ -65,7 +65,7 @@ class SettingsState extends State<SettingsView> {
builder: (BuildContext context) => AlertDialog( builder: (BuildContext context) => AlertDialog(
title: const Text("Your TETR.IO account nickname or ID", style: TextStyle(fontFamily: "Eurostile Round Extended")), title: const Text("Your TETR.IO account nickname or ID", style: TextStyle(fontFamily: "Eurostile Round Extended")),
content: SingleChildScrollView( content: SingleChildScrollView(
child: ListBody(children: [TextField(controller: _playertext)]), child: ListBody(children: [TextField(controller: _playertext, maxLength: 25)]),
), ),
actions: <Widget>[ actions: <Widget>[
TextButton( TextButton(