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 bool verified;
bool? badstanding;
bool? bot;
String? botmaster;
late Connections connections;
late TetraLeagueAlpha tlSeason1;
List<RecordSingle?> sprint = [];
@ -60,7 +60,7 @@ class TetrioPlayer {
required this.supporterTier,
required this.verified,
this.badstanding,
this.bot,
this.botmaster,
required this.connections,
required this.tlSeason1,
required this.sprint,
@ -98,6 +98,7 @@ class TetrioPlayer {
distinguishment = json['distinguishment'] != null ? Distinguishment.fromJson(json['distinguishment']) : null;
friendCount = json['friend_count'] ?? 0;
badstanding = json['badstanding'];
botmaster = json['botmaster'];
if (fetchRecords) {
var url = Uri.https('ch.tetr.io', 'api/users/$userId/records');
Future response = http.get(url);
@ -124,25 +125,25 @@ class TetrioPlayer {
data['_id'] = userId;
data['username'] = username;
data['role'] = role;
data['ts'] = registrationTime?.toString();
if (registrationTime != null) data['ts'] = registrationTime?.toString();
data['badges'] = badges.map((v) => v.toJson()).toList();
data['xp'] = xp;
data['gamesplayed'] = gamesPlayed;
data['gameswon'] = gamesWon;
data['gametime'] = gameTime.inMicroseconds / 1000000;
data['country'] = country;
if (country != null) data['country'] = country;
data['supporter_tier'] = supporterTier;
data['verified'] = verified;
data['league'] = tlSeason1.toJson();
data['distinguishment'] = distinguishment?.toJson();
data['avatar_revision'] = avatarRevision;
data['banner_revision'] = bannerRevision;
data['bio'] = bio;
if (distinguishment != null) data['distinguishment'] = distinguishment?.toJson();
if (avatarRevision != null) data['avatar_revision'] = avatarRevision;
if (bannerRevision != null) data['banner_revision'] = bannerRevision;
if (data['bio'] != null) data['bio'] = bio;
data['connections'] = connections.toJson();
data['friend_count'] = friendCount;
data['badstanding'] = badstanding;
data['bot'] = bot;
developer.log("TetrioPlayer.toJson: $bot", name: "data_objects/tetrio");
if (badstanding != null) data['badstanding'] = badstanding;
if (botmaster != null) data['botmaster'] = botmaster;
developer.log("TetrioPlayer.toJson: $data", name: "data_objects/tetrio");
return data;
}
@ -161,7 +162,7 @@ class TetrioPlayer {
if (supporterTier != other.supporterTier) return false;
if (verified != other.verified) 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 (tlSeason1 != other.tlSeason1) return false;
if (distinguishment != other.distinguishment) return false;
@ -170,7 +171,7 @@ class TetrioPlayer {
@override
String toString() {
return "$username ($userId)";
return "$username ($state)";
}
@override
@ -678,20 +679,20 @@ class TetraLeagueAlpha {
data['gamesplayed'] = gamesPlayed;
data['gameswon'] = gamesWon;
data['rating'] = rating;
data['glicko'] = glicko;
data['rd'] = rd;
if (glicko != null) data['glicko'] = glicko;
if (rd != null) data['rd'] = rd;
data['rank'] = rank;
data['bestrank'] = bestRank;
data['apm'] = apm;
data['pps'] = pps;
data['vs'] = vs;
if (apm != null) data['apm'] = apm;
if (pps != null) data['pps'] = pps;
if (vs != null) data['vs'] = vs;
data['decaying'] = decaying;
data['standing'] = standing;
data['percentile'] = percentile;
data['standing_local'] = standingLocal;
data['prev_rank'] = prevRank;
if (prevRank != null) data['prev_rank'] = prevRank;
data['prev_at'] = prevAt;
data['next_rank'] = nextRank;
if (nextRank != null) data['next_rank'] = nextRank;
data['next_at'] = nextAt;
data['percentile_rank'] = percentileRank;
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.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'];
endContext = json['endcontext'] != null ? EndContextSingle.fromJson(json['endcontext']) : null;
replayId = json['replayid'];
@ -777,3 +778,41 @@ class Distinguishment {
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/settings_view.dart';
import 'package:tetra_stats/views/states_view.dart';
import 'package:tetra_stats/views/calc_view.dart';
void main() {
sqfliteFfiInit();
databaseFactory = databaseFactoryFfi;
runApp(MaterialApp(
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(
fontFamily: 'Eurostile Round',
colorScheme: const ColorScheme.dark(primary: Colors.cyanAccent, secondary: Colors.purpleAccent),

View File

@ -42,4 +42,12 @@ class 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:convert';
import 'dart:developer' as developer;
import 'package:http/http.dart' as http;
// import 'package:sqflite/sqflite.dart';
// import 'package:path_provider/path_provider.dart' show MissingPlatformDirectoryException, getApplicationDocumentsDirectory;
// import 'package:path/path.dart' show join;
@ -31,7 +32,7 @@ class TetrioService {
Future<void> _cachePlayers(DB udb) async {
final allPlayers = await getAllPlayers(udb: udb);
_players = allPlayers.first;
_players = allPlayers.toList().first; // ???
_tetrioStreamController.add(_players);
developer.log("_cachePlayers: $_players", name: "services/tetrio_crud");
}
@ -58,6 +59,7 @@ class TetrioService {
// }
Future<void> createPlayer({required TetrioPlayer tetrioPlayer, required DB udb}) async {
_ensureDbIsOpen(udb);
final db = udb.getDatabaseOrThrow();
final results = await db.query(tetrioUsersTable, limit: 1, where: '$idCol = ?', whereArgs: [tetrioPlayer.userId.toLowerCase()]);
if (results.isNotEmpty) {
@ -72,9 +74,16 @@ class TetrioService {
}
Future<void> storeState(TetrioPlayer tetrioPlayer, DB udb) async {
_ensureDbIsOpen(udb);
final db = udb.getDatabaseOrThrow();
List<TetrioPlayer> states = await getPlayer(id: tetrioPlayer.userId, udb: udb);
states.add(tetrioPlayer);
late List<TetrioPlayer> states;
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 = {};
for (var e in states) {
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 {
_ensureDbIsOpen(udb);
final db = udb.getDatabaseOrThrow();
List<TetrioPlayer> states = [];
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 {
try {
await udb.open();
@ -117,6 +150,7 @@ class TetrioService {
Map<String, List<TetrioPlayer>> data = {};
//developer.log("getAllPlayers: $players", name: "services/tetrio_crud");
return players.map((row) {
// what the fuck am i doing here?
var test = json.decode(row['jsonStates'] as String);
List<TetrioPlayer> states = [];
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(
title: const Text("Your TETR.IO account nickname or ID", style: TextStyle(fontFamily: "Eurostile Round Extended")),
content: SingleChildScrollView(
child: ListBody(children: [TextField(controller: _playertext)]),
child: ListBody(children: [TextField(controller: _playertext, maxLength: 25)]),
),
actions: <Widget>[
TextButton(