Database import, leaderboard positions, various bugfixes

Need to work on info center
This commit is contained in:
dan63047 2024-11-05 01:20:36 +03:00
parent e3d7e94729
commit 647d1f87f4
12 changed files with 256 additions and 86 deletions

View File

@ -9,6 +9,7 @@ class PlayerLeaderboardPosition{
late LeaderboardPosition? gamesPlayed;
late LeaderboardPosition? gamesWon;
late LeaderboardPosition? winrate;
late LeaderboardPosition? glixare;
late LeaderboardPosition? app;
late LeaderboardPosition? vsapm;
late LeaderboardPosition? dss;
@ -28,6 +29,7 @@ class PlayerLeaderboardPosition{
required this.gamesPlayed,
required this.gamesWon,
required this.winrate,
required this.glixare,
required this.app,
required this.vsapm,
required this.dss,
@ -48,16 +50,17 @@ class PlayerLeaderboardPosition{
gamesPlayed = results[3];
gamesWon = results[4];
winrate = results[5];
app = results[6];
vsapm = results[7];
dss = results[8];
dsp = results[9];
appdsp = results[10];
cheese = results[11];
gbe = results[12];
nyaapp = results[13];
area = results[14];
estTr = results[15];
accOfEst = results[16];
glixare = results[6];
app = results[7];
vsapm = results[8];
dss = results[9];
dsp = results[10];
appdsp = results[11];
cheese = results[12];
gbe = results[13];
nyaapp = results[14];
area = results[15];
estTr = results[16];
accOfEst = results[17];
}
}

View File

@ -684,7 +684,7 @@ class TetrioPlayersLeaderboard {
copyOfLeaderboard = List.of(leaderboard);
copyOfLeaderboard.add(league.values.first.convertToPlayerFromLeaderboard(league.keys.first));
}
List<Stats> stats = [Stats.apm, Stats.pps, Stats.vs, Stats.gp, Stats.gw, Stats.wr,
List<Stats> stats = [Stats.apm, Stats.pps, Stats.vs, Stats.gp, Stats.gw, Stats.wr, Stats.gxe,
Stats.app, Stats.vsapm, Stats.dss, Stats.dsp, Stats.appdsp, Stats.cheese, Stats.gbe, Stats.nyaapp, Stats.area, Stats.eTR, Stats.acceTR];
List<LeaderboardPosition?> results = [];
for (Stats stat in stats) {

View File

@ -86,4 +86,24 @@ class DB {
var newDBStats = await dbFile.stat();
return dbStats.size - newDBStats.size;
}
Future<bool> checkImportingDB(File db) async {
final newDB = await openDatabase(db.path);
var usersTable = await newDB.rawQuery("PRAGMA table_xinfo(`${tetrioUsersTable}`);");
List<String> usersTableRows = [for (Map<String, Object?> row in usersTable) row["name"] as String];
if (!listEquals(usersTableRows, tetrioUsersTableRows)) return false;
var usersToTrackTable = await newDB.rawQuery("PRAGMA table_xinfo(`${tetrioUsersToTrackTable}`);");
List<String> usersToTrackTableRows = [for (Map<String, Object?> row in usersToTrackTable) row["name"] as String];
if (!listEquals(usersToTrackTableRows, tetrioUsersToTrackTableRows)) return false;
var leagueMatchesTable = await newDB.rawQuery("PRAGMA table_xinfo(`${tetraLeagueMatchesTable}`);");
List<String> leagueMatchesTableRows = [for (Map<String, Object?> row in leagueMatchesTable) row["name"] as String];
if (!listEquals(leagueMatchesTableRows, tetraLeagueMatchesTableRows)) return false;
var tlReplayStatsTable = await newDB.rawQuery("PRAGMA table_xinfo(`${tetrioTLReplayStatsTable}`);");
List<String> TLReplayStatsTableRows = [for (Map<String, Object?> row in tlReplayStatsTable) row["name"] as String];
if (!listEquals(TLReplayStatsTableRows, tetrioTLReplayStatsTableRows)) return false;
var leagueTable = await newDB.rawQuery("PRAGMA table_xinfo(`${tetrioLeagueTable}`);");
List<String> leagueTableRows = [for (Map<String, Object?> row in leagueTable) row["name"] as String];
if (!listEquals(leagueTableRows, tetrioLeagueTableRows)) return false;
return true;
}
}

View File

@ -49,6 +49,11 @@ const String endContext2 = "endContext2";
const String statesCol = "jsonStates";
const String player1id = "player1id";
const String player2id = "player2id";
const List<String> tetrioUsersTableRows = [idCol, nickCol, "jsonStates"];
const List<String> tetrioUsersToTrackTableRows = [idCol];
const List<String> tetraLeagueMatchesTableRows = [idCol, replayID, player1id, player2id, timestamp, endContext1, endContext2];
const List<String> tetrioTLReplayStatsTableRows = [idCol, "data", "freyhoe"];
const List<String> tetrioLeagueTableRows = [idCol, "gamesplayed", "gameswon", "tr", "glicko", "rd", "gxe", "rank", "bestrank", "apm", "pps", "vs", "decaying", "standing", "standing_local", "percentile", "prev_rank", "prev_at", "next_rank", "next_at", "percentile_rank", "season"];
/// Table, that store players data, their stats at some moments of time
const String createTetrioUsersTable = '''
CREATE TABLE IF NOT EXISTS "tetrioUsers" (

View File

@ -510,7 +510,7 @@ class _DestinationCalculatorState extends State<DestinationCalculator> {
Text("PC's: ${intf.format(pcDamage)}")
],
),
SfLinearGauge(
if (totalDamage > 0) SfLinearGauge(
minimum: 0,
maximum: totalDamage.toDouble(),
showLabels: false,

View File

@ -240,10 +240,10 @@ class _DestinationCutoffsState extends State<DestinationCutoffs> {
style: const TextStyle(fontFamily: "Eurostile Round", fontSize: 14, fontWeight: FontWeight.w100, color: Colors.white, shadows: textShadow),
children: [
if (rank == "x+") TextSpan(text: "№ 1 is ${f2.format(snapshot.data!.data["top1"]!.tr)} TR", style: const TextStyle(color: Colors.white60, shadows: null))
else TextSpan(text: snapshot.data!.data[ranks[ranks.indexOf(rank)+1]]!.tr > snapshot.data!.data[ranks[ranks.indexOf(rank)+1]]!.targetTr ? "Inflated from ${NumberFormat.compact().format(snapshot.data!.data[ranks[ranks.indexOf(rank)+1]]!.targetTr)} TR" : "Not inflated", style: TextStyle(color: snapshot.data!.data[ranks[ranks.indexOf(rank)+1]]!.tr > snapshot.data!.data[ranks[ranks.indexOf(rank)+1]]!.targetTr ? Colors.white :Colors.white60, shadows: null)),
else TextSpan(text: snapshot.data!.data[ranks[ranks.indexOf(rank)+1]]!.tr > snapshot.data!.data[ranks[ranks.indexOf(rank)+1]]!.targetTr ? "Inflated on ${f2.format(snapshot.data!.data[ranks[ranks.indexOf(rank)+1]]!.tr - snapshot.data!.data[ranks[ranks.indexOf(rank)+1]]!.targetTr)} TR" : "Not inflated", style: TextStyle(color: snapshot.data!.data[ranks[ranks.indexOf(rank)+1]]!.tr > snapshot.data!.data[ranks[ranks.indexOf(rank)+1]]!.targetTr ? Colors.white :Colors.white60, shadows: null)),
TextSpan(text: "\n", style: const TextStyle(color: Colors.white60, shadows: null)),
if (rank == "d") TextSpan(text: "Well...", style: const TextStyle(color: Colors.white60, shadows: null))
else TextSpan(text: snapshot.data!.data[rank]!.tr < snapshot.data!.data[rank]!.targetTr ? "Deflated untill ${NumberFormat.compact().format(snapshot.data!.data[rank]!.targetTr)} TR" : "Not deflated", style: TextStyle(color: snapshot.data!.data[rank]!.tr < snapshot.data!.data[rank]!.targetTr ? Colors.white : Colors.white60, shadows: null))
else TextSpan(text: snapshot.data!.data[rank]!.tr < snapshot.data!.data[rank]!.targetTr ? "Deflated on ${f2.format(snapshot.data!.data[rank]!.targetTr - snapshot.data!.data[rank]!.tr)} TR" : "Not deflated", style: TextStyle(color: snapshot.data!.data[rank]!.tr < snapshot.data!.data[rank]!.targetTr ? Colors.white : Colors.white60, shadows: null))
]
)),
),

View File

@ -6,12 +6,12 @@ import 'package:intl/intl.dart';
import 'package:tetra_stats/data_objects/cutoff_tetrio.dart';
import 'package:tetra_stats/data_objects/news.dart';
import 'package:tetra_stats/data_objects/p1nkl0bst3r.dart';
import 'package:tetra_stats/data_objects/player_leaderboard_position.dart';
import 'package:tetra_stats/data_objects/record_extras.dart';
import 'package:tetra_stats/data_objects/record_single.dart';
import 'package:tetra_stats/data_objects/singleplayer_stream.dart';
import 'package:tetra_stats/data_objects/summaries.dart';
import 'package:tetra_stats/data_objects/tetra_league.dart';
import 'package:tetra_stats/data_objects/tetra_league_beta_stream.dart';
import 'package:tetra_stats/data_objects/tetrio_constants.dart';
import 'package:tetra_stats/data_objects/tetrio_player.dart';
import 'package:tetra_stats/gen/strings.g.dart';
@ -32,8 +32,9 @@ class DestinationHome extends StatefulWidget{
final Future<FetchResults> dataFuture;
final Future<News>? newsFuture;
final BoxConstraints constraints;
final bool noSidebar;
const DestinationHome({super.key, required this.searchFor, required this.dataFuture, this.newsFuture, required this.constraints});
const DestinationHome({super.key, required this.searchFor, required this.dataFuture, this.newsFuture, required this.constraints, this.noSidebar = false});
@override
State<DestinationHome> createState() => _DestinationHomeState();
@ -46,10 +47,11 @@ class FetchResults{
Summaries? summaries;
Cutoffs? cutoffs;
CutoffsTetrio? averages;
PlayerLeaderboardPosition? playerPos;
bool isTracked;
Exception? exception;
FetchResults(this.success, this.player, this.states, this.summaries, this.cutoffs, this.averages, this.isTracked, this.exception);
FetchResults(this.success, this.player, this.states, this.summaries, this.cutoffs, this.averages, this.playerPos, this.isTracked, this.exception);
}
class RecordSummary extends StatelessWidget{
@ -389,7 +391,7 @@ class _DestinationHomeState extends State<DestinationHome> with SingleTickerProv
);
}
Widget getTetraLeagueCard(TetraLeague data, Cutoffs? cutoffs, CutoffTetrio? averages, List<TetraLeague> states){
Widget getTetraLeagueCard(TetraLeague data, Cutoffs? cutoffs, CutoffTetrio? averages, List<TetraLeague> states, PlayerLeaderboardPosition? lbPos){
TetraLeague? toCompare = states.length >= 2 ? states.elementAtOrNull(states.length-2) : null;
return Column(
children: [
@ -409,7 +411,7 @@ class _DestinationHomeState extends State<DestinationHome> with SingleTickerProv
),
),
),
TetraLeagueThingy(league: data, toCompare: toCompare, cutoffs: cutoffs, averages: averages),
TetraLeagueThingy(league: data, toCompare: toCompare, cutoffs: cutoffs, averages: averages, lbPos: lbPos),
if (data.nerdStats != null) Card(
//surfaceTintColor: rankColors[data.rank],
child: Row(
@ -604,26 +606,6 @@ class _DestinationHomeState extends State<DestinationHome> with SingleTickerProv
),
),
TLRecords(userID),
// Card(
// clipBehavior: Clip.antiAlias,
// child: FutureBuilder<TetraLeagueBetaStream>(
// future: teto.fetchTLStream(widget.searchFor),
// builder: (context, snapshot) {
// switch (snapshot.connectionState){
// case ConnectionState.none:
// case ConnectionState.waiting:
// case ConnectionState.active:
// return const Center(child: CircularProgressIndicator());
// case ConnectionState.done:
// if (snapshot.hasData){
// return SizedBox(height: constraints.maxHeight - 145, child: TLRecords(userID: userID, changePlayer: (){}, data: snapshot.data!.records, wasActiveInTL: snapshot.data!.records.isNotEmpty, oldMathcesHere: false));
// }
// if (snapshot.hasError){ return FutureError(snapshot); }
// }
// return const Text("what?");
// },
// ),
// ),
],
);
}
@ -1080,7 +1062,7 @@ class _DestinationHomeState extends State<DestinationHome> with SingleTickerProv
),
),
SizedBox(
width: widget.constraints.maxWidth - 450 - 80,
width: widget.noSidebar ? widget.constraints.maxWidth - 450 : widget.constraints.maxWidth - 530,
child: Column(
children: [
SizedBox(
@ -1091,7 +1073,7 @@ class _DestinationHomeState extends State<DestinationHome> with SingleTickerProv
child: switch (rightCard){
Cards.overview => getOverviewCard(snapshot.data!.summaries!, (snapshot.data!.averages != null && snapshot.data!.summaries!.league.rank != "z") ? snapshot.data!.averages!.data[snapshot.data!.summaries!.league.rank] : (snapshot.data!.averages != null && snapshot.data!.summaries!.league.percentileRank != "z") ? snapshot.data!.averages!.data[snapshot.data!.summaries!.league.percentileRank] : null),
Cards.tetraLeague => switch (cardMod){
CardMod.info => getTetraLeagueCard(snapshot.data!.summaries!.league, snapshot.data!.cutoffs, (snapshot.data!.averages != null && snapshot.data!.summaries!.league.rank != "z") ? snapshot.data!.averages!.data[snapshot.data!.summaries!.league.rank] : (snapshot.data!.averages != null && snapshot.data!.summaries!.league.percentileRank != "z") ? snapshot.data!.averages!.data[snapshot.data!.summaries!.league.percentileRank] : null, snapshot.data!.states),
CardMod.info => getTetraLeagueCard(snapshot.data!.summaries!.league, snapshot.data!.cutoffs, (snapshot.data!.averages != null && snapshot.data!.summaries!.league.rank != "z") ? snapshot.data!.averages!.data[snapshot.data!.summaries!.league.rank] : (snapshot.data!.averages != null && snapshot.data!.summaries!.league.percentileRank != "z") ? snapshot.data!.averages!.data[snapshot.data!.summaries!.league.percentileRank] : null, snapshot.data!.states, snapshot.data!.playerPos),
CardMod.ex => getPreviousSeasonsList(snapshot.data!.summaries!.pastLeague),
CardMod.records => getRecentTLrecords(widget.constraints, snapshot.data!.player!.userId),
_ => const Center(child: Text("huh?"))

View File

@ -8,7 +8,6 @@ import 'package:tetra_stats/main.dart';
import 'package:tetra_stats/utils/numers_formats.dart';
import 'package:tetra_stats/utils/relative_timestamps.dart';
import 'package:tetra_stats/views/main_view_tiles.dart';
import 'package:tetra_stats/views/tl_leaderboard_view.dart';
import 'package:tetra_stats/views/user_view.dart';
class DestinationLeaderboards extends StatefulWidget{
@ -49,6 +48,7 @@ class _DestinationLeaderboardsState extends State<DestinationLeaderboards> {
Stream<List<dynamic>> get dataStream => _dataStreamController.stream;
List<dynamic> list = [];
bool _isFetchingData = false;
bool _reachedTheEnd = false;
List<String> _excludeRanks = [];
bool _reverse = false;
String? prisecter;
@ -64,7 +64,7 @@ class _DestinationLeaderboardsState extends State<DestinationLeaderboards> {
}
Future<void> _fetchData() async {
if (_isFetchingData) {
if (_isFetchingData || _reachedTheEnd) {
// Avoid fetching new data while already fetching
return;
}
@ -84,7 +84,7 @@ class _DestinationLeaderboardsState extends State<DestinationLeaderboards> {
};
if (_currentLb == Leaderboards.fullTL && _excludeRanks.isNotEmpty) items.removeWhere((e) => _excludeRanks.indexOf((e as TetrioPlayerFromLeaderboard).rank) != -1);
if (_currentLb == Leaderboards.fullTL || items.isEmpty) _reachedTheEnd = true;
list.addAll((_reverse && _currentLb == Leaderboards.fullTL) ? items.reversed : items);
_dataStreamController.add(list);
@ -150,6 +150,7 @@ class _DestinationLeaderboardsState extends State<DestinationLeaderboards> {
_currentLb = leaderboards.keys.elementAt(index);
list.clear();
prisecter = null;
_reachedTheEnd = false;
_fetchData();
},
),
@ -192,6 +193,7 @@ class _DestinationLeaderboardsState extends State<DestinationLeaderboards> {
list.clear();
prisecter = null;
_isFetchingData = false;
_reachedTheEnd = false;
setState((){_fetchData();});
})
),
@ -209,6 +211,7 @@ class _DestinationLeaderboardsState extends State<DestinationLeaderboards> {
list.clear();
prisecter = null;
_isFetchingData = false;
_reachedTheEnd = false;
setState((){_fetchData();});
})
),
@ -266,7 +269,7 @@ class _DestinationLeaderboardsState extends State<DestinationLeaderboards> {
}, icon: Icon(Icons.filter_alt)),
if (_currentLb == Leaderboards.fullTL) IconButton(
color: _reverse ? Theme.of(context).colorScheme.primary : null,
icon: Container(transform: _reverse ? Matrix4.rotationX(pi) : null, child: Icon(Icons.filter_list)),
icon: Transform.rotate(angle: _reverse ? pi : 0.0, child: Icon(Icons.filter_list)),
onPressed: (){
setState((){
_reverse = !_reverse;
@ -302,13 +305,21 @@ class _DestinationLeaderboardsState extends State<DestinationLeaderboards> {
Image.asset("res/tetrio_tl_alpha_ranks/${snapshot.data![index].rank}.png", height: 36)
],
),
Leaderboards.fullTL => Row(
mainAxisSize: MainAxisSize.min,
children: [
Text("${f2.format(snapshot.data![index].tr)} TR", style: trailingStyle),
Image.asset("res/tetrio_tl_alpha_ranks/${snapshot.data![index].rank}.png", height: 36)
],
),
Leaderboards.fullTL => switch (stat) {
Stats.tr => Row(
mainAxisSize: MainAxisSize.min,
children: [
Text("${f2.format(snapshot.data![index].tr)} TR", style: trailingStyle),
Image.asset("res/tetrio_tl_alpha_ranks/${snapshot.data![index].rank}.png", height: 36)
],
),
Stats.gp => Text("${intf.format(snapshot.data![index].getStatByEnum(stat))} ${chartsShortTitles[stat]}", style: trailingStyle),
Stats.gw => Text("${intf.format(snapshot.data![index].getStatByEnum(stat))} ${chartsShortTitles[stat]}", style: trailingStyle),
Stats.apm => Text("${f2.format(snapshot.data![index].getStatByEnum(stat))} ${chartsShortTitles[stat]}", style: trailingStyle),
Stats.pps => Text("${f2.format(snapshot.data![index].getStatByEnum(stat))} ${chartsShortTitles[stat]}", style: trailingStyle),
Stats.vs => Text("${f2.format(snapshot.data![index].getStatByEnum(stat))} ${chartsShortTitles[stat]}", style: trailingStyle),
_ => Text("${f4.format(snapshot.data![index].getStatByEnum(stat))} ${chartsShortTitles[stat]}", style: trailingStyle)
},
Leaderboards.xp => Text("LVL ${f2.format(snapshot.data![index].level)}", style: trailingStyle),
Leaderboards.ar => Text("${intf.format(snapshot.data![index].ar)} AR", style: trailingStyle),
Leaderboards.sprint => Text(get40lTime(snapshot.data![index].stats.finalTime.inMicroseconds), style: trailingStyle),
@ -318,7 +329,10 @@ class _DestinationLeaderboardsState extends State<DestinationLeaderboards> {
},
subtitle: Text(switch (_currentLb){
Leaderboards.tl => "${f2.format(snapshot.data![index].apm)} APM, ${f2.format(snapshot.data![index].pps)} PPS, ${f2.format(snapshot.data![index].vs)} VS, ${f2.format(snapshot.data![index].nerdStats.app)} APP, ${f2.format(snapshot.data![index].nerdStats.vsapm)} VS/APM",
Leaderboards.fullTL => "${f2.format(snapshot.data![index].apm)} APM, ${f2.format(snapshot.data![index].pps)} PPS, ${f2.format(snapshot.data![index].vs)} VS, ${f2.format(snapshot.data![index].nerdStats.app)} APP, ${f2.format(snapshot.data![index].nerdStats.vsapm)} VS/APM",
Leaderboards.fullTL => switch (stat) {
Stats.tr => "${f2.format(snapshot.data![index].apm)} APM, ${f2.format(snapshot.data![index].pps)} PPS, ${f2.format(snapshot.data![index].vs)} VS, ${f2.format(snapshot.data![index].nerdStats.app)} APP, ${f2.format(snapshot.data![index].nerdStats.vsapm)} VS/APM",
_ => "${f2.format(snapshot.data![index].tr)} TR, ${snapshot.data![index].rank.toUpperCase()} rank"
},
Leaderboards.xp => "${f2.format(snapshot.data![index].xp)} XP${snapshot.data![index].playtime.isNegative ? "" : ", ${playtime(snapshot.data![index].playtime)} of gametime"}",
Leaderboards.ar => "${snapshot.data![index].ar_counts}",
Leaderboards.sprint => "${intf.format(snapshot.data![index].stats.finesse.faults)} FF, ${f2.format(snapshot.data![index].stats.kpp)} KPP, ${f2.format(snapshot.data![index].stats.kps)} KPS, ${f2.format(snapshot.data![index].stats.pps)} PPS, ${intf.format(snapshot.data![index].stats.piecesPlaced)} P",

View File

@ -1,8 +1,12 @@
import 'dart:async';
import 'dart:io';
import 'package:file_picker/file_picker.dart';
import 'package:file_selector/file_selector.dart';
import 'package:flutter/foundation.dart';
import 'package:flutter/material.dart';
import 'package:flutter_colorpicker/flutter_colorpicker.dart';
import 'package:intl/intl.dart';
import 'package:path_provider/path_provider.dart';
import 'package:tetra_stats/data_objects/tetrio_player.dart';
import 'package:tetra_stats/gen/strings.g.dart';
import 'package:tetra_stats/main.dart';
@ -486,11 +490,118 @@ class _DestinationSettings extends State<DestinationSettings> with SingleTickerP
Card(
child: ListTile(
title: Text("Export Database", style: Theme.of(context).textTheme.displayLarge),
onTap: () {
if (kIsWeb){
ScaffoldMessenger.of(context).showSnackBar(SnackBar(content: Text(t.notForWeb)));
} else if (Platform.isAndroid){
var downloadFolder = Directory("/storage/emulated/0/Download");
File exportedDB = File("${downloadFolder.path}/TetraStats.db");
getApplicationDocumentsDirectory().then((value) {
exportedDB.writeAsBytes(File("${value.path}/TetraStats.db").readAsBytesSync());
showDialog(
context: context,
builder: (BuildContext context) => AlertDialog(
title: Text(t.androidExportAlertTitle,
style: const TextStyle(
fontFamily: "Eurostile Round Extended")),
content: SingleChildScrollView(
child: ListBody(children: [Text(t.androidExportText(exportedDB: exportedDB))]),
),
actions: <Widget>[
TextButton(
child: Text(t.popupActions.ok),
onPressed: () {
Navigator.of(context).pop();
},
),
],
));
});
} else if (Platform.isLinux || Platform.isWindows) {
showDialog(
context: context,
builder: (BuildContext context) => AlertDialog(
title: Text(t.desktopExportAlertTitle,
style: const TextStyle(
fontFamily: "Eurostile Round Extended")),
content: SingleChildScrollView(
child: ListBody(children: [
Text(t.desktopExportText)
]),
),
actions: <Widget>[
TextButton(
child: Text(t.popupActions.ok),
onPressed: () {
Navigator.of(context).pop();
},
),
],
));
}
}
),
),
Card(
child: ListTile(
title: Text("Import Database", style: Theme.of(context).textTheme.displayLarge),
onTap: (){
if (kIsWeb){
ScaffoldMessenger.of(context).showSnackBar(SnackBar(content: Text(t.notForWeb)));
}else if(Platform.isAndroid){
FilePicker.platform.pickFiles(
type: FileType.any,
).then((value){
if (value != null){
var newDB = value.paths[0]!;
teto.checkImportingDB(File(newDB)).then((v){
if (v){
teto.close().then((value){
getApplicationDocumentsDirectory().then((value){
var oldDB = File("${value.path}/TetraStats.db");
oldDB.writeAsBytes(File(newDB).readAsBytesSync()).then((value){
teto.open();
ScaffoldMessenger.of(context).showSnackBar(SnackBar(content: Text(t.importSuccess)));
});
});
});
}else{
ScaffoldMessenger.of(context).showSnackBar(SnackBar(content: Text("Import Failed: Wrong database sheme")));
}
});
} else {
ScaffoldMessenger.of(context).showSnackBar(SnackBar(content: Text(t.importCancelled)));
}
});
}else{
const XTypeGroup typeGroup = XTypeGroup(
label: 'Tetra Stats Database',
extensions: <String>['db'],
);
openFile(acceptedTypeGroups: <XTypeGroup>[typeGroup]).then((value){
if (value != null){
var newDB = value.path;
teto.checkImportingDB(File(newDB)).then((v){
if (v){
teto.close().then((value){
getApplicationDocumentsDirectory().then((value){
var oldDB = File("${value.path}/TetraStats.db");
oldDB.writeAsBytes(File(newDB).readAsBytesSync()).then((value){
teto.open();
ScaffoldMessenger.of(context).showSnackBar(SnackBar(content: Text(t.importSuccess)));
});
});
});
}else{
ScaffoldMessenger.of(context).showSnackBar(SnackBar(content: Text("Import Failed: Wrong database sheme")));
}
});
} else {
ScaffoldMessenger.of(context).showSnackBar(SnackBar(content: Text(t.importCancelled)));
}
});
}
},
),
)
],

View File

@ -16,6 +16,7 @@ import 'package:tetra_stats/data_objects/nerd_stats.dart';
import 'package:tetra_stats/data_objects/news.dart';
import 'package:tetra_stats/data_objects/news_entry.dart';
import 'package:tetra_stats/data_objects/p1nkl0bst3r.dart';
import 'package:tetra_stats/data_objects/player_leaderboard_position.dart';
import 'package:tetra_stats/data_objects/playstyle.dart';
import 'package:tetra_stats/data_objects/record_extras.dart';
import 'package:tetra_stats/data_objects/record_single.dart';
@ -24,6 +25,7 @@ import 'package:tetra_stats/data_objects/tetra_league.dart';
import 'package:tetra_stats/data_objects/tetra_league_alpha_record.dart';
import 'package:tetra_stats/data_objects/tetrio_constants.dart';
import 'package:tetra_stats/data_objects/tetrio_player.dart';
import 'package:tetra_stats/data_objects/tetrio_players_leaderboard.dart';
import 'package:tetra_stats/gen/strings.g.dart';
import 'package:tetra_stats/services/crud_exceptions.dart';
import 'package:tetra_stats/utils/colors_functions.dart';
@ -53,6 +55,7 @@ import 'package:vector_math/vector_math_64.dart' hide Colors;
var fDiff = NumberFormat("+#,###.####;-#,###.####");
late Future<FetchResults> _data;
late Future<News> _newsData;
TetrioPlayersLeaderboard? _everyone;
Future<FetchResults> getData(String searchFor) async {
TetrioPlayer player;
@ -64,23 +67,33 @@ Future<FetchResults> getData(String searchFor) async {
}
}on TetrioPlayerNotExist{
return FetchResults(false, null, [], null, null, null, false, TetrioPlayerNotExist());
return FetchResults(false, null, [], null, null, null, null, false, TetrioPlayerNotExist());
}
late Summaries summaries;
late Cutoffs cutoffs;
late CutoffsTetrio averages;
late Cutoffs? cutoffs;
late CutoffsTetrio? averages;
try {
List<dynamic> requests = await Future.wait([
teto.fetchSummaries(player.userId),
teto.fetchCutoffsBeanserver(),
teto.fetchCutoffsTetrio()
if (prefs.getBool("showAverages") == true) teto.fetchCutoffsTetrio()
]);
summaries = requests[0];
cutoffs = requests.elementAtOrNull(1);
averages = requests.elementAtOrNull(2);
} on Exception catch (e) {
return FetchResults(false, null, [], null, null, null, false, e);
return FetchResults(false, null, [], null, null, null, null, false, e);
}
PlayerLeaderboardPosition? _meAmongEveryone;
if (prefs.getBool("showPositions") == true){
// Get tetra League leaderboard
_everyone = teto.getCachedLeaderboard();
_everyone ??= await teto.fetchTLLeaderboard();
if (_everyone!.leaderboard.isNotEmpty){
_meAmongEveryone = await compute(_everyone!.getLeaderboardPosition, {player.userId: summaries.league});
if (_meAmongEveryone != null) teto.cacheLeaderboardPositions(player.userId, _meAmongEveryone);
}
}
List<TetraLeague> states = await teto.getStates(player.userId, season: currentSeason);
@ -89,7 +102,7 @@ Future<FetchResults> getData(String searchFor) async {
await teto.storeState(summaries.league);
}
return FetchResults(true, player, states, summaries, cutoffs, averages, isTracking, null);
return FetchResults(true, player, states, summaries, cutoffs, averages, _meAmongEveryone, isTracking, null);
}
class MainView extends StatefulWidget {
@ -579,7 +592,10 @@ class DistinguishmentThingy extends StatelessWidget{
children: getDistinguishmentTitle(distinguishment.header),
),
),
Text(getDistinguishmentSubtitle(distinguishment.footer), style: Theme.of(context).textTheme.displayLarge, textAlign: TextAlign.center),
Padding(
padding: const EdgeInsets.fromLTRB(8.0, 4.0, 8.0, 4.0),
child: Text(getDistinguishmentSubtitle(distinguishment.footer), style: Theme.of(context).textTheme.displayLarge, textAlign: TextAlign.center),
),
],
),
);
@ -641,7 +657,10 @@ class FakeDistinguishmentThingy extends StatelessWidget{
),
),
),
Text(getDistinguishmentSubtitle(), style: Theme.of(context).textTheme.displayLarge, textAlign: TextAlign.center),
Padding(
padding: const EdgeInsets.fromLTRB(8.0, 4.0, 8.0, 4.0),
child: Text(getDistinguishmentSubtitle(), style: Theme.of(context).textTheme.displayLarge, textAlign: TextAlign.center),
),
],
),
),
@ -1103,7 +1122,7 @@ class _SearchDrawerState extends State<SearchDrawer> {
SliverToBoxAdapter(
child: SearchBar(
controller: widget.controller,
hintText: "Hello",
hintText: "Enter the username",
hintStyle: const WidgetStatePropertyAll(TextStyle(color: Colors.grey)),
trailing: [
IconButton(onPressed: (){setState(() {
@ -1121,12 +1140,22 @@ class _SearchDrawerState extends State<SearchDrawer> {
),
SliverToBoxAdapter(
child: ListTile(
leading: Icon(Icons.home),
title: Text(prefs.getString("player") ?? "dan63"),
onTap: () {
widget.changePlayer(prefs.getString("playerID") ?? "6098518e3d5155e6ec429cdc");
Navigator.of(context).pop();
},
),
),
SliverToBoxAdapter(
child: Divider(),
),
SliverToBoxAdapter(
child: Padding(
padding: const EdgeInsets.only(left: 10.0),
child: Text("Tracked Players", style: Theme.of(context).textTheme.headlineLarge),
),
)
];
},
@ -1136,6 +1165,9 @@ class _SearchDrawerState extends State<SearchDrawer> {
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(
title: Text(allPlayers[keys[i]]??keys[i]), // Takes last known username from list of states
trailing: IconButton(onPressed: (){
teto.deletePlayerToTrack(keys[i]);
}, icon: Icon(Icons.delete, color: Colors.grey)),
onTap: () {
widget.changePlayer(keys[i]); // changes to chosen player
Navigator.of(context).pop(); // and closes itself.
@ -1155,8 +1187,9 @@ class TetraLeagueThingy extends StatelessWidget{
final TetraLeague? toCompare;
final Cutoffs? cutoffs;
final CutoffTetrio? averages;
final PlayerLeaderboardPosition? lbPos;
const TetraLeagueThingy({super.key, required this.league, this.toCompare, this.cutoffs, this.averages});
const TetraLeagueThingy({super.key, required this.league, this.toCompare, this.cutoffs, this.averages, this.lbPos});
@override
Widget build(BuildContext context) {
@ -1182,22 +1215,27 @@ class TetraLeagueThingy extends StatelessWidget{
Expanded(
child: Center(
child: Table(
defaultVerticalAlignment: TableCellVerticalAlignment.baseline,
textBaseline: TextBaseline.alphabetic,
defaultColumnWidth:const IntrinsicColumnWidth(),
children: [
TableRow(children: [
Text(league.apm != null ? f2.format(league.apm) : "-.--", textAlign: TextAlign.right, style: TextStyle(fontSize: 21, color: league.apm != null ? getStatColor(league.apm!, averages?.apm, true) : Colors.grey)),
Text(" APM", style: TextStyle(fontSize: 21, color: league.apm != null ? getStatColor(league.apm!, averages?.apm, true) : Colors.grey)),
if (toCompare != null) Text(" (${comparef2.format(league.apm!-toCompare!.apm!)})", textAlign: TextAlign.right, style: TextStyle(fontSize: 21, color: getDifferenceColor(league.apm!-toCompare!.apm!)))
if (toCompare != null) Text(" (${comparef2.format(league.apm!-toCompare!.apm!)})", textAlign: TextAlign.right, style: TextStyle(fontSize: 21, color: getDifferenceColor(league.apm!-toCompare!.apm!))),
if (lbPos != null) Text(lbPos?.apm != null ? (lbPos!.apm!.position >= 1000 ? " (${t.top} ${f2.format(lbPos!.apm!.percentage*100)}%)" : " (№ ${lbPos!.apm!.position})") : "(№ ---)", style: TextStyle(color: lbPos?.apm != null ? getColorOfRank(lbPos!.apm!.position) : null))
]),
TableRow(children: [
Text(league.pps != null ? f2.format(league.pps) : "-.--", textAlign: TextAlign.right, style: TextStyle(fontSize: 21, color: league.pps != null ? getStatColor(league.pps!, averages?.pps, true) : Colors.grey)),
Text(" PPS", style: TextStyle(fontSize: 21, color: league.pps != null ? getStatColor(league.pps!, averages?.pps, true) : Colors.grey)),
if (toCompare != null) Text(" (${comparef2.format(league.pps!-toCompare!.pps!)})", textAlign: TextAlign.right, style: TextStyle(fontSize: 21, color: getDifferenceColor(league.pps!-toCompare!.pps!)))
if (toCompare != null) Text(" (${comparef2.format(league.pps!-toCompare!.pps!)})", textAlign: TextAlign.right, style: TextStyle(fontSize: 21, color: getDifferenceColor(league.pps!-toCompare!.pps!))),
if (lbPos != null) Text(lbPos?.pps != null ? (lbPos!.pps!.position >= 1000 ? " (${t.top} ${f2.format(lbPos!.pps!.percentage*100)}%)" : " (№ ${lbPos!.pps!.position})") : "(№ ---)", style: TextStyle(color: lbPos?.pps != null ? getColorOfRank(lbPos!.pps!.position) : null))
]),
TableRow(children: [
Text(league.vs != null ? f2.format(league.vs) : "-.--", textAlign: TextAlign.right, style: TextStyle(fontSize: 21, color: league.vs != null ? getStatColor(league.vs!, averages?.vs, true) : Colors.grey)),
Text(" VS", style: TextStyle(fontSize: 21, color: league.vs != null ? getStatColor(league.vs!, averages?.vs, true) : Colors.grey)),
if (toCompare != null) Text(" (${comparef2.format(league.vs!-toCompare!.vs!)})", textAlign: TextAlign.right, style: TextStyle(fontSize: 21, color: getDifferenceColor(league.vs!-toCompare!.vs!)))
if (toCompare != null) Text(" (${comparef2.format(league.vs!-toCompare!.vs!)})", textAlign: TextAlign.right, style: TextStyle(fontSize: 21, color: getDifferenceColor(league.vs!-toCompare!.vs!))),
if (lbPos != null) Text(lbPos?.vs != null ? (lbPos!.vs!.position >= 1000 ? " (${t.top} ${f2.format(lbPos!.vs!.percentage*100)}%)" : " (№ ${lbPos!.vs!.position})") : "(№ ---)", style: TextStyle(color: lbPos?.vs != null ? getColorOfRank(lbPos!.vs!.position) : null))
])
],
),
@ -1207,25 +1245,30 @@ class TetraLeagueThingy extends StatelessWidget{
Expanded(
child: Center(
child: Table(
defaultVerticalAlignment: TableCellVerticalAlignment.baseline,
textBaseline: TextBaseline.alphabetic,
defaultColumnWidth:const IntrinsicColumnWidth(),
children: [
TableRow(children: [
//Text("APM: ", style: TextStyle(fontSize: 21)),
Text(intf.format(league.gamesPlayed), textAlign: TextAlign.right, style: const TextStyle(fontSize: 21)),
const Text(" Games", style: TextStyle(fontSize: 21)),
if (toCompare != null) Text(" (${comparef2.format(league.gamesPlayed-toCompare!.gamesPlayed)})", textAlign: TextAlign.right, style: TextStyle(fontSize: 21, color: Colors.grey))
if (toCompare != null) Text(" (${comparef2.format(league.gamesPlayed-toCompare!.gamesPlayed)})", textAlign: TextAlign.right, style: TextStyle(fontSize: 21, color: Colors.grey)),
if (lbPos != null) Text(lbPos?.gamesPlayed != null ? (lbPos!.gamesPlayed!.position >= 1000 ? " (${t.top} ${f2.format(lbPos!.gamesPlayed!.percentage*100)}%)" : " (№ ${lbPos!.gamesPlayed!.position})") : "(№ ---)", style: TextStyle(color: lbPos?.gamesPlayed != null ? getColorOfRank(lbPos!.gamesPlayed!.position) : null))
]),
TableRow(children: [
//Text("PPS: ", style: TextStyle(fontSize: 21)),
Text(intf.format(league.gamesWon), textAlign: TextAlign.right, style: const TextStyle(fontSize: 21)),
const Text(" Won", style: TextStyle(fontSize: 21)),
if (toCompare != null) Text(" (${comparef2.format(league.gamesWon-toCompare!.gamesWon)})", textAlign: TextAlign.right, style: TextStyle(fontSize: 21, color: Colors.grey))
if (toCompare != null) Text(" (${comparef2.format(league.gamesWon-toCompare!.gamesWon)})", textAlign: TextAlign.right, style: TextStyle(fontSize: 21, color: Colors.grey)),
if (lbPos != null) Text(lbPos?.gamesWon != null ? (lbPos!.gamesWon!.position >= 1000 ? " (${t.top} ${f2.format(lbPos!.gamesWon!.percentage*100)}%)" : " (№ ${lbPos!.gamesWon!.position})") : "(№ ---)", style: TextStyle(color: lbPos?.gamesWon != null ? getColorOfRank(lbPos!.gamesWon!.position) : null))
]),
TableRow(children: [
//Text("VS: ", style: TextStyle(fontSize: 21)),
Tooltip(child: Text("${league.gxe.isNegative ? "---" : f3.format(league.gxe)}", textAlign: TextAlign.right, style: TextStyle(fontSize: 21, color: league.standingLocal.isNegative ? Colors.grey : Colors.white)), message: "${f2.format(league.s1tr)}",),
Text(" GLIXARE", style: TextStyle(fontSize: 21, color: league.standingLocal.isNegative ? Colors.grey : Colors.white)),
if (toCompare != null) Text(" (${comparef.format(league.gxe-toCompare!.gxe)})", textAlign: TextAlign.right, style: TextStyle(fontSize: 21, color: getDifferenceColor(league.standingLocal-toCompare!.standingLocal)))
Tooltip(child: Text("${league.gxe.isNegative ? "---" : f3.format(league.gxe)}", textAlign: TextAlign.right, style: TextStyle(fontSize: 21, color: league.gxe.isNegative ? Colors.grey : Colors.white)), message: "${f2.format(league.s1tr)}",),
Text(" GLIXARE", style: TextStyle(fontSize: 21, color: league.gxe.isNegative ? Colors.grey : Colors.white)),
if (toCompare != null) Text(" (${comparef.format(league.gxe-toCompare!.gxe)})", textAlign: TextAlign.right, style: TextStyle(fontSize: 21, color: getDifferenceColor(league.gxe-toCompare!.gxe))),
if (lbPos != null) Text(lbPos?.glixare != null ? (lbPos!.glixare!.position >= 1000 ? " (${t.top} ${f2.format(lbPos!.glixare!.percentage*100)}%)" : " (№ ${lbPos!.glixare!.position})") : "(№ ---)", style: TextStyle(color: lbPos?.glixare != null ? getColorOfRank(lbPos!.glixare!.position) : null))
]),
],
),

View File

@ -571,7 +571,10 @@ class TlMatchResultState extends State<TlMatchResultView> {
final t = Translations.of(context);
return Scaffold(
appBar: AppBar(
title: Text("${widget.record.results.leaderboard[greenSidePlayer].username.toUpperCase()} ${t.vs} ${widget.record.results.leaderboard[redSidePlayer].username.toUpperCase()} ${t.inTLmatch} ${widget.record.gamemode} ${timestamp(widget.record.ts)}"),
title: Text(
"${widget.record.results.leaderboard[greenSidePlayer].username.toUpperCase()} ${t.vs} ${widget.record.results.leaderboard[redSidePlayer].username.toUpperCase()} ${t.inTLmatch} ${widget.record.gamemode} ${timestamp(widget.record.ts)}",
style: Theme.of(context).textTheme.titleMedium!.copyWith(fontSize: 28),
),
actions: [
PopupMenuButton(
enabled: widget.record.gamemode == "league",

View File

@ -46,7 +46,7 @@ class UserState extends State<UserView> {
backgroundColor: Colors.black,
floatingActionButtonLocation: FloatingActionButtonLocation.startTop,
floatingActionButton: Padding(
padding: const EdgeInsets.all(8.0),
padding: const EdgeInsets.fromLTRB(0.0, 12.0, 0.0, 0.0),
child: FloatingActionButton(
onPressed: () => Navigator.pop(context),
tooltip: 'Fuck go back',
@ -56,18 +56,7 @@ class UserState extends State<UserView> {
body: SafeArea(
child: LayoutBuilder(
builder: (BuildContext context, BoxConstraints constraints) {
return Row(
children: [
Card(
child: Column(
children: [
Text("oskagalove", style: TextStyle(),)
]
),
),
DestinationHome(searchFor: widget.searchFor, dataFuture: getData(widget.searchFor), newsFuture: teto.fetchNews(widget.searchFor), constraints: constraints),
],
);
return DestinationHome(searchFor: widget.searchFor, dataFuture: getData(widget.searchFor), newsFuture: teto.fetchNews(widget.searchFor), constraints: constraints, noSidebar: true);
}
)
)