Compare view improvements, win chance implemented
Also now you can delete states and players from db Numbers formatting Ready for v0.1.0
This commit is contained in:
parent
b72d47e202
commit
daefbb9504
|
@ -148,6 +148,23 @@ class TetrioService extends DB {
|
|||
_tetrioStreamController.add(_players);
|
||||
}
|
||||
|
||||
Future<void> deleteState(TetrioPlayer tetrioPlayer) async {
|
||||
ensureDbIsOpen();
|
||||
final db = getDatabaseOrThrow();
|
||||
late List<TetrioPlayer> states;
|
||||
states = await getPlayer(tetrioPlayer.userId);
|
||||
_players[tetrioPlayer.userId]!.removeWhere((element) => element.state == tetrioPlayer.state);
|
||||
states = _players[tetrioPlayer.userId]!;
|
||||
final Map<String, dynamic> statesJson = {};
|
||||
for (var e in states) {
|
||||
statesJson.addEntries({e.state.millisecondsSinceEpoch.toString(): e.toJson()}.entries);
|
||||
}
|
||||
db.update(tetrioUsersTable, {idCol: tetrioPlayer.userId, nickCol: tetrioPlayer.username, statesCol: jsonEncode(statesJson)},
|
||||
where: '$idCol = ?', whereArgs: [tetrioPlayer.userId]);
|
||||
_players[tetrioPlayer.userId]!.add(tetrioPlayer);
|
||||
_tetrioStreamController.add(_players);
|
||||
}
|
||||
|
||||
Future<List<TetrioPlayer>> getPlayer(String id) async {
|
||||
ensureDbIsOpen();
|
||||
final db = getDatabaseOrThrow();
|
||||
|
|
|
@ -15,7 +15,7 @@ class CalcState extends State<CalcView> {
|
|||
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")),
|
||||
body: const SafeArea(child: Text("Next build")),
|
||||
);
|
||||
}
|
||||
}
|
||||
|
|
|
@ -1,3 +1,4 @@
|
|||
import 'dart:math';
|
||||
import 'package:fl_chart/fl_chart.dart';
|
||||
import 'package:flutter/material.dart';
|
||||
import 'package:intl/intl.dart';
|
||||
|
@ -8,6 +9,9 @@ TetrioPlayer? theGreenSide;
|
|||
TetrioPlayer? theRedSide;
|
||||
final TetrioService teto = TetrioService();
|
||||
|
||||
FocusNode greenFocusNode = FocusNode();
|
||||
FocusNode redFocusNode = FocusNode();
|
||||
|
||||
class CompareView extends StatefulWidget {
|
||||
final TetrioPlayer greenSide;
|
||||
final TetrioPlayer? redSide;
|
||||
|
@ -46,6 +50,16 @@ class CompareState extends State<CompareView> {
|
|||
setState(() {});
|
||||
}
|
||||
|
||||
double getWinrateByTR(double yourGlicko, double yourRD, double notyourGlicko, double notyourRD) {
|
||||
double q = 400 * sqrt(1 + 3 * pow(log(10) / (400 * pi), 2));
|
||||
double k = (notyourGlicko - yourGlicko) / (q * sqrt(pow(yourRD, 2) + pow(notyourRD, 2)));
|
||||
//return 1 / (1 + pow(10, (notyourGlicko - yourGlicko)) / (400 * sqrt(1 + (3 * pow(0.00575646273, 2) * (pow(yourRD, 2) + pow(notyourRD, 2))) / pow(pi, 2))));
|
||||
return ((1 /
|
||||
(1 + pow(10, (notyourGlicko - yourGlicko) / (400 * sqrt(1 + (3 * pow(0.0057564273, 2) * (pow(yourRD, 2) + pow(notyourRD, 2)) / pow(pi, 2))))))));
|
||||
//return 1 / (1 + pow(10, k));
|
||||
}
|
||||
|
||||
// 1/(1+10^(rating[1]-rating[0])/(400*sqrt(1+(3*Q^2*(RD[0]^2+RD[1]^2))/PI^2)))) wtf where is
|
||||
void _justUpdate() {
|
||||
setState(() {});
|
||||
}
|
||||
|
@ -72,9 +86,22 @@ class CompareState extends State<CompareView> {
|
|||
crossAxisAlignment: CrossAxisAlignment.start,
|
||||
children: [
|
||||
Expanded(
|
||||
child: Padding(
|
||||
padding: const EdgeInsets.fromLTRB(8, 0, 8, 0),
|
||||
child: PlayerSelector(player: theGreenSide, change: fetchGreenSide, updateState: _justUpdate),
|
||||
child: Container(
|
||||
decoration: BoxDecoration(
|
||||
gradient: LinearGradient(
|
||||
colors: [Colors.green, Colors.transparent],
|
||||
begin: Alignment.bottomCenter,
|
||||
end: Alignment.topCenter,
|
||||
stops: [0.0, 0.4],
|
||||
)),
|
||||
child: Padding(
|
||||
padding: const EdgeInsets.fromLTRB(8, 0, 8, 0),
|
||||
child: PlayerSelector(
|
||||
player: theGreenSide,
|
||||
change: fetchGreenSide,
|
||||
updateState: _justUpdate,
|
||||
),
|
||||
),
|
||||
),
|
||||
),
|
||||
const Padding(
|
||||
|
@ -82,9 +109,22 @@ class CompareState extends State<CompareView> {
|
|||
child: Text("VS"),
|
||||
),
|
||||
Expanded(
|
||||
child: Padding(
|
||||
padding: const EdgeInsets.fromLTRB(8, 0, 8, 0),
|
||||
child: PlayerSelector(player: theRedSide, change: fetchRedSide, updateState: _justUpdate),
|
||||
child: Container(
|
||||
decoration: BoxDecoration(
|
||||
gradient: LinearGradient(
|
||||
colors: [Colors.red, Colors.transparent],
|
||||
begin: Alignment.bottomCenter,
|
||||
end: Alignment.topCenter,
|
||||
stops: [0.0, 0.4],
|
||||
)),
|
||||
child: Padding(
|
||||
padding: const EdgeInsets.fromLTRB(8, 0, 8, 0),
|
||||
child: PlayerSelector(
|
||||
player: theRedSide,
|
||||
change: fetchRedSide,
|
||||
updateState: _justUpdate,
|
||||
),
|
||||
),
|
||||
),
|
||||
),
|
||||
],
|
||||
|
@ -99,33 +139,49 @@ class CompareState extends State<CompareView> {
|
|||
body: theGreenSide != null && theRedSide != null
|
||||
? ListView(
|
||||
children: [
|
||||
CompareThingy(
|
||||
label: "Level",
|
||||
greenSide: theGreenSide!.level,
|
||||
redSide: theRedSide!.level,
|
||||
higherIsBetter: true,
|
||||
fractionDigits: 2,
|
||||
),
|
||||
if (theGreenSide!.gamesPlayed >= 0 && theRedSide!.gamesPlayed >= 0)
|
||||
CompareThingy(
|
||||
label: "Online Games",
|
||||
greenSide: theGreenSide!.gamesPlayed,
|
||||
redSide: theRedSide!.gamesPlayed,
|
||||
higherIsBetter: true,
|
||||
),
|
||||
if (theGreenSide!.gamesWon >= 0 && theRedSide!.gamesWon >= 0)
|
||||
CompareThingy(
|
||||
label: "Games Won",
|
||||
greenSide: theGreenSide!.gamesWon,
|
||||
redSide: theRedSide!.gamesWon,
|
||||
higherIsBetter: true,
|
||||
),
|
||||
CompareThingy(
|
||||
label: "Friends",
|
||||
greenSide: theGreenSide!.friendCount,
|
||||
redSide: theRedSide!.friendCount,
|
||||
higherIsBetter: true,
|
||||
),
|
||||
if (theGreenSide!.role != "banned" && theRedSide!.role != "banned")
|
||||
Column(
|
||||
children: [
|
||||
CompareRegTimeThingy(greenSide: theGreenSide!.registrationTime, redSide: theRedSide!.registrationTime, label: "Registred"),
|
||||
CompareThingy(
|
||||
label: "Level",
|
||||
greenSide: theGreenSide!.level,
|
||||
redSide: theRedSide!.level,
|
||||
higherIsBetter: true,
|
||||
fractionDigits: 2,
|
||||
),
|
||||
if (!theGreenSide!.gameTime.isNegative && !theRedSide!.gameTime.isNegative)
|
||||
CompareThingy(
|
||||
greenSide: theGreenSide!.gameTime.inMicroseconds / 1000000 / 60 / 60,
|
||||
redSide: theRedSide!.gameTime.inMicroseconds / 1000000 / 60 / 60,
|
||||
label: "Hours Played",
|
||||
higherIsBetter: true,
|
||||
fractionDigits: 2,
|
||||
),
|
||||
if (theGreenSide!.gamesPlayed >= 0 && theRedSide!.gamesPlayed >= 0)
|
||||
CompareThingy(
|
||||
label: "Online Games",
|
||||
greenSide: theGreenSide!.gamesPlayed,
|
||||
redSide: theRedSide!.gamesPlayed,
|
||||
higherIsBetter: true,
|
||||
),
|
||||
if (theGreenSide!.gamesWon >= 0 && theRedSide!.gamesWon >= 0)
|
||||
CompareThingy(
|
||||
label: "Games Won",
|
||||
greenSide: theGreenSide!.gamesWon,
|
||||
redSide: theRedSide!.gamesWon,
|
||||
higherIsBetter: true,
|
||||
),
|
||||
CompareThingy(
|
||||
label: "Friends",
|
||||
greenSide: theGreenSide!.friendCount,
|
||||
redSide: theRedSide!.friendCount,
|
||||
higherIsBetter: true,
|
||||
),
|
||||
],
|
||||
)
|
||||
else
|
||||
CompareBoolThingy(greenSide: theGreenSide!.role == "banned", redSide: theRedSide!.role == "banned", label: "Banned", trueIsBetter: false),
|
||||
const Divider(),
|
||||
theGreenSide!.tlSeason1.gamesPlayed > 0 && theRedSide!.tlSeason1.gamesPlayed > 0
|
||||
? Column(
|
||||
|
@ -217,37 +273,11 @@ class CompareState extends State<CompareView> {
|
|||
),
|
||||
],
|
||||
)
|
||||
: Padding(
|
||||
padding: const EdgeInsets.fromLTRB(16, 2, 16, 2),
|
||||
child: Row(children: [
|
||||
Expanded(
|
||||
child: Text(
|
||||
theGreenSide!.tlSeason1.gamesPlayed > 0 ? "Yes" : "No",
|
||||
style: const TextStyle(fontSize: 22),
|
||||
textAlign: TextAlign.start,
|
||||
)),
|
||||
Column(
|
||||
children: const [
|
||||
Text(
|
||||
"Played Tetra League",
|
||||
style: TextStyle(fontSize: 22),
|
||||
textAlign: TextAlign.center,
|
||||
),
|
||||
Text(
|
||||
"---",
|
||||
style: TextStyle(fontSize: 16),
|
||||
textAlign: TextAlign.center,
|
||||
)
|
||||
],
|
||||
),
|
||||
Expanded(
|
||||
child: Text(
|
||||
theRedSide!.tlSeason1.gamesPlayed > 0 ? "Yes" : "No",
|
||||
style: const TextStyle(fontSize: 22),
|
||||
textAlign: TextAlign.end,
|
||||
)),
|
||||
]),
|
||||
),
|
||||
: CompareBoolThingy(
|
||||
greenSide: theGreenSide!.tlSeason1.gamesPlayed > 0,
|
||||
redSide: theRedSide!.tlSeason1.gamesPlayed > 0,
|
||||
label: "Played Tetra League",
|
||||
trueIsBetter: false),
|
||||
const Divider(),
|
||||
if (theGreenSide!.tlSeason1.apm != null &&
|
||||
theRedSide!.tlSeason1.apm != null &&
|
||||
|
@ -393,8 +423,8 @@ class CompareState extends State<CompareView> {
|
|||
},
|
||||
dataSets: [
|
||||
RadarDataSet(
|
||||
fillColor: const Color.fromARGB(117, 105, 240, 175),
|
||||
borderColor: Colors.greenAccent,
|
||||
fillColor: const Color.fromARGB(115, 76, 175, 79),
|
||||
borderColor: Colors.green,
|
||||
dataEntries: [
|
||||
RadarEntry(value: theGreenSide!.tlSeason1.apm! * 1),
|
||||
RadarEntry(value: theGreenSide!.tlSeason1.pps! * 45),
|
||||
|
@ -409,8 +439,8 @@ class CompareState extends State<CompareView> {
|
|||
],
|
||||
),
|
||||
RadarDataSet(
|
||||
fillColor: const Color.fromARGB(117, 255, 82, 82),
|
||||
borderColor: Colors.redAccent,
|
||||
fillColor: const Color.fromARGB(115, 244, 67, 54),
|
||||
borderColor: Colors.red,
|
||||
dataEntries: [
|
||||
RadarEntry(value: theRedSide!.tlSeason1.apm! * 1),
|
||||
RadarEntry(value: theRedSide!.tlSeason1.pps! * 45),
|
||||
|
@ -482,8 +512,8 @@ class CompareState extends State<CompareView> {
|
|||
},
|
||||
dataSets: [
|
||||
RadarDataSet(
|
||||
fillColor: const Color.fromARGB(117, 105, 240, 175),
|
||||
borderColor: Colors.greenAccent,
|
||||
fillColor: Color.fromARGB(115, 76, 175, 79),
|
||||
borderColor: Colors.green,
|
||||
dataEntries: [
|
||||
RadarEntry(value: theGreenSide!.tlSeason1.playstyle!.opener),
|
||||
RadarEntry(value: theGreenSide!.tlSeason1.playstyle!.stride),
|
||||
|
@ -492,8 +522,8 @@ class CompareState extends State<CompareView> {
|
|||
],
|
||||
),
|
||||
RadarDataSet(
|
||||
fillColor: const Color.fromARGB(117, 255, 82, 82),
|
||||
borderColor: Colors.redAccent,
|
||||
fillColor: Color.fromARGB(115, 244, 67, 54),
|
||||
borderColor: Colors.red,
|
||||
dataEntries: [
|
||||
RadarEntry(value: theRedSide!.tlSeason1.playstyle!.opener),
|
||||
RadarEntry(value: theRedSide!.tlSeason1.playstyle!.stride),
|
||||
|
@ -533,6 +563,17 @@ class CompareState extends State<CompareView> {
|
|||
padding: const EdgeInsets.only(bottom: 16),
|
||||
child: Text("Win Chance", style: TextStyle(fontFamily: "Eurostile Round Extended", fontSize: bigScreen ? 42 : 28)),
|
||||
),
|
||||
CompareThingy(
|
||||
label: "By Glicko",
|
||||
greenSide: getWinrateByTR(theGreenSide!.tlSeason1.glicko!, theGreenSide!.tlSeason1.rd!, theRedSide!.tlSeason1.glicko!,
|
||||
theRedSide!.tlSeason1.rd!) *
|
||||
100,
|
||||
redSide: getWinrateByTR(theRedSide!.tlSeason1.glicko!, theRedSide!.tlSeason1.rd!, theGreenSide!.tlSeason1.glicko!,
|
||||
theGreenSide!.tlSeason1.rd!) *
|
||||
100,
|
||||
fractionDigits: 2,
|
||||
higherIsBetter: true,
|
||||
),
|
||||
],
|
||||
)
|
||||
],
|
||||
|
@ -559,16 +600,32 @@ class PlayerSelector extends StatelessWidget {
|
|||
return Column(
|
||||
children: [
|
||||
TextField(
|
||||
autocorrect: false,
|
||||
enableSuggestions: false,
|
||||
maxLength: 25,
|
||||
controller: playerController,
|
||||
decoration: const InputDecoration(counter: Offstage()),
|
||||
onSubmitted: (String value) {
|
||||
change(value);
|
||||
},
|
||||
),
|
||||
if (player != null) Text(player!.toString())
|
||||
autocorrect: false,
|
||||
enableSuggestions: false,
|
||||
maxLength: 25,
|
||||
controller: playerController,
|
||||
decoration: const InputDecoration(counter: Offstage()),
|
||||
onSubmitted: (String value) {
|
||||
change(value);
|
||||
}),
|
||||
if (player != null)
|
||||
Text(
|
||||
player!.toString(),
|
||||
style: TextStyle(
|
||||
shadows: <Shadow>[
|
||||
Shadow(
|
||||
offset: Offset(0.0, 0.0),
|
||||
blurRadius: 3.0,
|
||||
color: Colors.black,
|
||||
),
|
||||
Shadow(
|
||||
offset: Offset(0.0, 0.0),
|
||||
blurRadius: 8.0,
|
||||
color: Colors.black,
|
||||
),
|
||||
],
|
||||
),
|
||||
)
|
||||
],
|
||||
);
|
||||
}
|
||||
|
@ -598,12 +655,43 @@ class CompareThingy extends StatelessWidget {
|
|||
mainAxisAlignment: MainAxisAlignment.center,
|
||||
children: [
|
||||
Expanded(
|
||||
child: Text(
|
||||
f.format(greenSide),
|
||||
style: const TextStyle(
|
||||
fontSize: 22,
|
||||
child: Container(
|
||||
padding: EdgeInsets.all(4),
|
||||
decoration: BoxDecoration(
|
||||
gradient: LinearGradient(
|
||||
colors: [Colors.green, Colors.transparent],
|
||||
begin: Alignment.centerLeft,
|
||||
end: Alignment.centerRight,
|
||||
stops: [
|
||||
0.0,
|
||||
higherIsBetter
|
||||
? greenSide > redSide
|
||||
? 0.6
|
||||
: 0
|
||||
: greenSide < redSide
|
||||
? 0.6
|
||||
: 0
|
||||
],
|
||||
)),
|
||||
child: Text(
|
||||
f.format(greenSide),
|
||||
style: const TextStyle(
|
||||
fontSize: 22,
|
||||
shadows: <Shadow>[
|
||||
Shadow(
|
||||
offset: Offset(0.0, 0.0),
|
||||
blurRadius: 3.0,
|
||||
color: Colors.black,
|
||||
),
|
||||
Shadow(
|
||||
offset: Offset(0.0, 0.0),
|
||||
blurRadius: 8.0,
|
||||
color: Colors.black,
|
||||
),
|
||||
],
|
||||
),
|
||||
textAlign: TextAlign.start,
|
||||
),
|
||||
textAlign: TextAlign.start,
|
||||
)),
|
||||
Column(
|
||||
children: [
|
||||
|
@ -619,9 +707,217 @@ class CompareThingy extends StatelessWidget {
|
|||
)
|
||||
],
|
||||
),
|
||||
Expanded(
|
||||
child: Container(
|
||||
padding: EdgeInsets.all(4),
|
||||
decoration: BoxDecoration(
|
||||
gradient: LinearGradient(
|
||||
colors: [Colors.red, Colors.transparent],
|
||||
begin: Alignment.centerRight,
|
||||
end: Alignment.centerLeft,
|
||||
stops: [
|
||||
0.0,
|
||||
higherIsBetter
|
||||
? redSide > greenSide
|
||||
? 0.6
|
||||
: 0
|
||||
: redSide < greenSide
|
||||
? 0.6
|
||||
: 0
|
||||
],
|
||||
)),
|
||||
child: Text(
|
||||
f.format(redSide),
|
||||
style: const TextStyle(
|
||||
fontSize: 22,
|
||||
shadows: <Shadow>[
|
||||
Shadow(
|
||||
offset: Offset(0.0, 0.0),
|
||||
blurRadius: 3.0,
|
||||
color: Colors.black,
|
||||
),
|
||||
Shadow(
|
||||
offset: Offset(0.0, 0.0),
|
||||
blurRadius: 8.0,
|
||||
color: Colors.black,
|
||||
),
|
||||
],
|
||||
),
|
||||
textAlign: TextAlign.end,
|
||||
),
|
||||
)),
|
||||
],
|
||||
),
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
class CompareBoolThingy extends StatelessWidget {
|
||||
final bool greenSide;
|
||||
final bool redSide;
|
||||
final String label;
|
||||
final bool trueIsBetter;
|
||||
const CompareBoolThingy({super.key, required this.greenSide, required this.redSide, required this.label, required this.trueIsBetter});
|
||||
|
||||
@override
|
||||
Widget build(BuildContext context) {
|
||||
return Padding(
|
||||
padding: const EdgeInsets.fromLTRB(16, 2, 16, 2),
|
||||
child: Row(children: [
|
||||
Expanded(
|
||||
child: Container(
|
||||
padding: EdgeInsets.all(4),
|
||||
decoration: BoxDecoration(
|
||||
gradient: LinearGradient(
|
||||
colors: [Colors.green, Colors.transparent],
|
||||
begin: Alignment.centerLeft,
|
||||
end: Alignment.centerRight,
|
||||
stops: [
|
||||
0.0,
|
||||
trueIsBetter
|
||||
? greenSide
|
||||
? 0.6
|
||||
: 0
|
||||
: !greenSide
|
||||
? 0.6
|
||||
: 0
|
||||
],
|
||||
)),
|
||||
child: Text(
|
||||
greenSide ? "Yes" : "No",
|
||||
style: const TextStyle(
|
||||
fontSize: 22,
|
||||
shadows: <Shadow>[
|
||||
Shadow(
|
||||
offset: Offset(0.0, 0.0),
|
||||
blurRadius: 3.0,
|
||||
color: Colors.black,
|
||||
),
|
||||
Shadow(
|
||||
offset: Offset(0.0, 0.0),
|
||||
blurRadius: 8.0,
|
||||
color: Colors.black,
|
||||
),
|
||||
],
|
||||
),
|
||||
textAlign: TextAlign.start,
|
||||
),
|
||||
)),
|
||||
Column(
|
||||
children: [
|
||||
Text(
|
||||
label,
|
||||
style: const TextStyle(fontSize: 22),
|
||||
textAlign: TextAlign.center,
|
||||
),
|
||||
const Text(
|
||||
"---",
|
||||
style: TextStyle(fontSize: 16),
|
||||
textAlign: TextAlign.center,
|
||||
)
|
||||
],
|
||||
),
|
||||
Expanded(
|
||||
child: Container(
|
||||
padding: EdgeInsets.all(4),
|
||||
decoration: BoxDecoration(
|
||||
gradient: LinearGradient(
|
||||
colors: [Colors.red, Colors.transparent],
|
||||
begin: Alignment.centerRight,
|
||||
end: Alignment.centerLeft,
|
||||
stops: [
|
||||
0.0,
|
||||
trueIsBetter
|
||||
? redSide
|
||||
? 0.6
|
||||
: 0
|
||||
: !redSide
|
||||
? 0.6
|
||||
: 0
|
||||
],
|
||||
)),
|
||||
child: Text(
|
||||
redSide ? "Yes" : "No",
|
||||
style: const TextStyle(
|
||||
fontSize: 22,
|
||||
shadows: <Shadow>[
|
||||
Shadow(
|
||||
offset: Offset(0.0, 0.0),
|
||||
blurRadius: 3.0,
|
||||
color: Colors.black,
|
||||
),
|
||||
Shadow(
|
||||
offset: Offset(0.0, 0.0),
|
||||
blurRadius: 8.0,
|
||||
color: Colors.black,
|
||||
),
|
||||
],
|
||||
),
|
||||
textAlign: TextAlign.end,
|
||||
),
|
||||
)),
|
||||
]),
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
class CompareDurationThingy extends StatelessWidget {
|
||||
final Duration greenSide;
|
||||
final Duration redSide;
|
||||
final String label;
|
||||
final bool higherIsBetter;
|
||||
const CompareDurationThingy({super.key, required this.greenSide, required this.redSide, required this.label, required this.higherIsBetter});
|
||||
|
||||
Duration verdict(Duration greenSide, Duration redSide) {
|
||||
return greenSide - redSide;
|
||||
}
|
||||
|
||||
@override
|
||||
Widget build(BuildContext context) {
|
||||
return Padding(
|
||||
padding: const EdgeInsets.fromLTRB(16, 2, 16, 2),
|
||||
child: Row(
|
||||
mainAxisAlignment: MainAxisAlignment.center,
|
||||
children: [
|
||||
Expanded(
|
||||
child: Text(
|
||||
f.format(redSide),
|
||||
greenSide.toString(),
|
||||
style: const TextStyle(
|
||||
fontSize: 22,
|
||||
),
|
||||
textAlign: TextAlign.start,
|
||||
)),
|
||||
Column(
|
||||
children: [
|
||||
Text(
|
||||
label,
|
||||
style: const TextStyle(
|
||||
fontSize: 22,
|
||||
shadows: <Shadow>[
|
||||
Shadow(
|
||||
offset: Offset(0.0, 0.0),
|
||||
blurRadius: 3.0,
|
||||
color: Colors.black,
|
||||
),
|
||||
Shadow(
|
||||
offset: Offset(0.0, 0.0),
|
||||
blurRadius: 8.0,
|
||||
color: Colors.black,
|
||||
),
|
||||
],
|
||||
),
|
||||
textAlign: TextAlign.center,
|
||||
),
|
||||
Text(
|
||||
verdict(greenSide, redSide).toString(),
|
||||
style: const TextStyle(fontSize: 16),
|
||||
textAlign: TextAlign.center,
|
||||
)
|
||||
],
|
||||
),
|
||||
Expanded(
|
||||
child: Text(
|
||||
redSide.toString(),
|
||||
style: const TextStyle(fontSize: 22),
|
||||
textAlign: TextAlign.end,
|
||||
)),
|
||||
|
@ -630,3 +926,119 @@ class CompareThingy extends StatelessWidget {
|
|||
);
|
||||
}
|
||||
}
|
||||
|
||||
class CompareRegTimeThingy extends StatelessWidget {
|
||||
final DateTime? greenSide;
|
||||
final DateTime? redSide;
|
||||
final String label;
|
||||
final int? fractionDigits;
|
||||
const CompareRegTimeThingy({super.key, required this.greenSide, required this.redSide, required this.label, this.fractionDigits});
|
||||
|
||||
String verdict(DateTime? greenSide, DateTime? redSide) {
|
||||
var f = NumberFormat("#,### days later;#,### days before");
|
||||
String result = "---";
|
||||
if (greenSide != null && redSide != null) result = f.format(greenSide.difference(redSide).inDays);
|
||||
return result;
|
||||
}
|
||||
|
||||
@override
|
||||
Widget build(BuildContext context) {
|
||||
DateFormat f = DateFormat.yMMMd();
|
||||
return Padding(
|
||||
padding: const EdgeInsets.fromLTRB(16, 2, 16, 2),
|
||||
child: Row(
|
||||
mainAxisAlignment: MainAxisAlignment.center,
|
||||
children: [
|
||||
Expanded(
|
||||
child: Container(
|
||||
padding: EdgeInsets.all(4),
|
||||
decoration: BoxDecoration(
|
||||
gradient: LinearGradient(
|
||||
colors: [Colors.green, Colors.transparent],
|
||||
begin: Alignment.centerLeft,
|
||||
end: Alignment.centerRight,
|
||||
stops: [
|
||||
0.0,
|
||||
greenSide == null
|
||||
? 0.6
|
||||
: redSide != null && greenSide!.isBefore(redSide!)
|
||||
? 0.6
|
||||
: 0
|
||||
],
|
||||
)),
|
||||
child: Text(
|
||||
greenSide != null ? f.format(greenSide!) : "From beginning",
|
||||
style: const TextStyle(
|
||||
fontSize: 22,
|
||||
shadows: <Shadow>[
|
||||
Shadow(
|
||||
offset: Offset(0.0, 0.0),
|
||||
blurRadius: 3.0,
|
||||
color: Colors.black,
|
||||
),
|
||||
Shadow(
|
||||
offset: Offset(0.0, 0.0),
|
||||
blurRadius: 8.0,
|
||||
color: Colors.black,
|
||||
),
|
||||
],
|
||||
),
|
||||
textAlign: TextAlign.start,
|
||||
),
|
||||
)),
|
||||
Column(
|
||||
children: [
|
||||
Text(
|
||||
label,
|
||||
style: const TextStyle(fontSize: 22),
|
||||
textAlign: TextAlign.center,
|
||||
),
|
||||
Text(
|
||||
verdict(greenSide, redSide),
|
||||
style: const TextStyle(fontSize: 16),
|
||||
textAlign: TextAlign.center,
|
||||
)
|
||||
],
|
||||
),
|
||||
Expanded(
|
||||
child: Container(
|
||||
padding: EdgeInsets.all(4),
|
||||
decoration: BoxDecoration(
|
||||
gradient: LinearGradient(
|
||||
colors: [Colors.red, Colors.transparent],
|
||||
begin: Alignment.centerRight,
|
||||
end: Alignment.centerLeft,
|
||||
stops: [
|
||||
0.0,
|
||||
redSide == null
|
||||
? 0.6
|
||||
: greenSide != null && redSide!.isBefore(greenSide!)
|
||||
? 0.6
|
||||
: 0
|
||||
],
|
||||
)),
|
||||
child: Text(
|
||||
redSide != null ? f.format(redSide!) : "From beginning",
|
||||
style: const TextStyle(
|
||||
fontSize: 22,
|
||||
shadows: <Shadow>[
|
||||
Shadow(
|
||||
offset: Offset(0.0, 0.0),
|
||||
blurRadius: 3.0,
|
||||
color: Colors.black,
|
||||
),
|
||||
Shadow(
|
||||
offset: Offset(0.0, 0.0),
|
||||
blurRadius: 8.0,
|
||||
color: Colors.black,
|
||||
),
|
||||
],
|
||||
),
|
||||
textAlign: TextAlign.end,
|
||||
),
|
||||
)),
|
||||
],
|
||||
),
|
||||
);
|
||||
}
|
||||
}
|
||||
|
|
|
@ -1,4 +1,5 @@
|
|||
import 'package:flutter/material.dart';
|
||||
import 'package:intl/intl.dart';
|
||||
import 'package:shared_preferences/shared_preferences.dart';
|
||||
import 'dart:developer' as developer;
|
||||
import 'package:flutter/services.dart';
|
||||
|
@ -16,6 +17,8 @@ late SharedPreferences prefs;
|
|||
const allowedHeightForPlayerIdInPixels = 40.0;
|
||||
const allowedHeightForPlayerBioInPixels = 30.0;
|
||||
const givenTextHeightByScreenPercentage = 0.3;
|
||||
final NumberFormat timeInSec = NumberFormat("#,###.###s.");
|
||||
final DateFormat dateFormat = DateFormat.yMMMd().add_Hms();
|
||||
|
||||
class MainView extends StatefulWidget {
|
||||
const MainView({Key? key}) : super(key: key);
|
||||
|
@ -364,10 +367,18 @@ class _RecordThingy extends StatelessWidget {
|
|||
else if (record!.stream.contains("blitz"))
|
||||
Text("Blitz", style: TextStyle(fontFamily: "Eurostile Round Extended", fontSize: bigScreen ? 42 : 28)),
|
||||
if (record!.stream.contains("40l"))
|
||||
Text(record!.endContext!.finalTime.toString(), style: TextStyle(fontFamily: "Eurostile Round Extended", fontSize: bigScreen ? 42 : 28))
|
||||
Text(timeInSec.format(record!.endContext!.finalTime.inMicroseconds / 1000000),
|
||||
style: TextStyle(fontFamily: "Eurostile Round Extended", fontSize: bigScreen ? 42 : 28))
|
||||
else if (record!.stream.contains("blitz"))
|
||||
Text(record!.endContext!.score.toString(), style: TextStyle(fontFamily: "Eurostile Round Extended", fontSize: bigScreen ? 42 : 28)),
|
||||
Text(NumberFormat.decimalPattern().format(record!.endContext!.score),
|
||||
style: TextStyle(fontFamily: "Eurostile Round Extended", fontSize: bigScreen ? 42 : 28)),
|
||||
if (record!.rank != null) StatCellNum(playerStat: record!.rank!, playerStatLabel: "Leaderboard Placement", isScreenBig: bigScreen),
|
||||
Text("Obtained ${dateFormat.format(record!.timestamp!)}",
|
||||
textAlign: TextAlign.center,
|
||||
style: const TextStyle(
|
||||
fontFamily: "Eurostile Round",
|
||||
fontSize: 16,
|
||||
)),
|
||||
Padding(
|
||||
padding: const EdgeInsets.fromLTRB(0, 48, 0, 48),
|
||||
child: Wrap(
|
||||
|
@ -586,11 +597,9 @@ class _OtherThingy extends StatelessWidget {
|
|||
child: Column(
|
||||
children: [
|
||||
Text("Zen", style: TextStyle(fontFamily: "Eurostile Round Extended", fontSize: bigScreen ? 42 : 28)),
|
||||
Text("Level ${zen!.level}", style: TextStyle(fontFamily: "Eurostile Round Extended", fontSize: bigScreen ? 42 : 28)),
|
||||
Text(
|
||||
"Score ${zen!.score}",
|
||||
style: const TextStyle(fontSize: 18),
|
||||
),
|
||||
Text("Level ${NumberFormat.decimalPattern().format(zen!.level)}",
|
||||
style: TextStyle(fontFamily: "Eurostile Round Extended", fontSize: bigScreen ? 42 : 28)),
|
||||
Text("Score ${NumberFormat.decimalPattern().format(zen!.score)}", style: const TextStyle(fontSize: 18)),
|
||||
],
|
||||
),
|
||||
),
|
||||
|
|
|
@ -108,7 +108,12 @@ class SettingsState extends State<SettingsView> {
|
|||
const Divider(),
|
||||
ListTile(
|
||||
title: const Text("About app"),
|
||||
subtitle: Text("${_packageInfo.appName} (${_packageInfo.packageName}) Version ${_packageInfo.version} Build ${_packageInfo.buildNumber}"),
|
||||
subtitle: Text("""
|
||||
${_packageInfo.appName} (${_packageInfo.packageName}) Version ${_packageInfo.version} Build ${_packageInfo.buildNumber}
|
||||
|
||||
Developed by dan63047
|
||||
Formulas provided by kerrmunism
|
||||
"""),
|
||||
),
|
||||
],
|
||||
)),
|
||||
|
|
|
@ -1,5 +1,7 @@
|
|||
import 'package:flutter/material.dart';
|
||||
import 'package:intl/intl.dart';
|
||||
import 'package:tetra_stats/data_objects/tetrio.dart';
|
||||
import 'package:tetra_stats/views/compare_view.dart';
|
||||
import 'package:tetra_stats/views/state_view.dart';
|
||||
|
||||
class StatesView extends StatefulWidget {
|
||||
|
@ -10,6 +12,8 @@ class StatesView extends StatefulWidget {
|
|||
State<StatefulWidget> createState() => StatesState();
|
||||
}
|
||||
|
||||
final DateFormat dateFormat = DateFormat.yMMMd().add_Hms();
|
||||
|
||||
class StatesState extends State<StatesView> {
|
||||
@override
|
||||
Widget build(BuildContext context) {
|
||||
|
@ -23,11 +27,16 @@ class StatesState extends State<StatesView> {
|
|||
itemCount: widget.states.length,
|
||||
itemBuilder: (context, index) {
|
||||
return ListTile(
|
||||
title: Text("On ${widget.states[index].state}"),
|
||||
title: Text("On ${dateFormat.format(widget.states[index].state)}"),
|
||||
subtitle: Text("Level ${widget.states[index].level.toStringAsFixed(2)} level, ${widget.states[index].gameTime} of gametime"),
|
||||
trailing: IconButton(
|
||||
icon: const Icon(Icons.delete_forever),
|
||||
onPressed: () {},
|
||||
onPressed: () {
|
||||
DateTime nn = widget.states[index].state;
|
||||
teto.deleteState(widget.states[index]).then((value) => setState(() {
|
||||
ScaffoldMessenger.of(context).showSnackBar(SnackBar(content: Text("${dateFormat.format(nn)} state was removed from database!")));
|
||||
}));
|
||||
},
|
||||
),
|
||||
onTap: () {
|
||||
Navigator.push(
|
||||
|
|
|
@ -1,4 +1,5 @@
|
|||
import 'package:flutter/material.dart';
|
||||
import 'package:intl/intl.dart';
|
||||
import 'package:tetra_stats/data_objects/tetrio.dart';
|
||||
import 'package:tetra_stats/services/tetrio_crud.dart';
|
||||
import 'package:tetra_stats/views/states_view.dart';
|
||||
|
@ -12,6 +13,8 @@ class TrackedPlayersView extends StatefulWidget {
|
|||
State<StatefulWidget> createState() => TrackedPlayersState();
|
||||
}
|
||||
|
||||
final DateFormat dateFormat = DateFormat.yMMMd().add_Hms();
|
||||
|
||||
class TrackedPlayersState extends State<TrackedPlayersView> {
|
||||
@override
|
||||
Widget build(BuildContext context) {
|
||||
|
@ -33,12 +36,22 @@ class TrackedPlayersState extends State<TrackedPlayersView> {
|
|||
List<String> keys = allPlayers.keys.toList();
|
||||
return NestedScrollView(
|
||||
headerSliverBuilder: (context, value) {
|
||||
String howManyPlayers(int numberOfPlayers) => Intl.plural(
|
||||
numberOfPlayers,
|
||||
zero: 'Empty list. Press "Track" button in previous view to add current player here',
|
||||
one: 'There is only one player',
|
||||
other: 'There are $numberOfPlayers players',
|
||||
name: 'howManyPeople',
|
||||
args: [numberOfPlayers],
|
||||
desc: 'Description of how many people are seen in a place.',
|
||||
examples: const {'numberOfPeople': 3},
|
||||
);
|
||||
return [
|
||||
SliverToBoxAdapter(
|
||||
child: Padding(
|
||||
padding: const EdgeInsets.only(left: 16),
|
||||
child: Text(
|
||||
'There are ${allPlayers.length} players',
|
||||
howManyPlayers(allPlayers.length),
|
||||
style: const TextStyle(color: Colors.white, fontSize: 25),
|
||||
),
|
||||
)),
|
||||
|
@ -50,10 +63,15 @@ class TrackedPlayersState extends State<TrackedPlayersView> {
|
|||
itemBuilder: (context, index) {
|
||||
return ListTile(
|
||||
title: Text("${allPlayers[keys[index]]?.last.username}: ${allPlayers[keys[index]]?.length} states"),
|
||||
subtitle: Text("From ${allPlayers[keys[index]]?.first.state} until ${allPlayers[keys[index]]?.last.state}"),
|
||||
subtitle: Text(
|
||||
"From ${dateFormat.format(allPlayers[keys[index]]!.first.state)} until ${dateFormat.format(allPlayers[keys[index]]!.last.state)}"),
|
||||
trailing: IconButton(
|
||||
icon: const Icon(Icons.delete_forever),
|
||||
onPressed: () {},
|
||||
onPressed: () {
|
||||
String nn = allPlayers[keys[index]]!.last.username;
|
||||
teto.deletePlayer(keys[index]);
|
||||
ScaffoldMessenger.of(context).showSnackBar(SnackBar(content: Text("$nn states was removed from database!")));
|
||||
},
|
||||
),
|
||||
onTap: () {
|
||||
Navigator.push(
|
||||
|
|
|
@ -1,4 +1,5 @@
|
|||
import 'package:flutter/material.dart';
|
||||
import 'package:intl/intl.dart';
|
||||
|
||||
class StatCellNum extends StatelessWidget {
|
||||
const StatCellNum({super.key, required this.playerStat, required this.playerStatLabel, required this.isScreenBig, this.snackBar, this.fractionDigits});
|
||||
|
@ -11,10 +12,11 @@ class StatCellNum extends StatelessWidget {
|
|||
|
||||
@override
|
||||
Widget build(BuildContext context) {
|
||||
NumberFormat f = NumberFormat.decimalPatternDigits(decimalDigits: fractionDigits ?? 0);
|
||||
return Column(
|
||||
children: [
|
||||
Text(
|
||||
fractionDigits != null ? playerStat.toStringAsFixed(fractionDigits!) : playerStat.floor().toString(),
|
||||
f.format(playerStat),
|
||||
style: TextStyle(
|
||||
fontFamily: "Eurostile Round Extended",
|
||||
fontSize: isScreenBig ? 32 : 24,
|
||||
|
|
|
@ -1,8 +1,12 @@
|
|||
import 'package:flutter/material.dart';
|
||||
import 'package:intl/intl.dart';
|
||||
import 'package:tetra_stats/data_objects/tetrio.dart';
|
||||
import 'package:fl_chart/fl_chart.dart';
|
||||
import 'package:tetra_stats/widgets/stat_sell_num.dart';
|
||||
|
||||
var fDiff = NumberFormat("+#,###.###;-#,###.###");
|
||||
final NumberFormat f2 = NumberFormat.decimalPatternDigits(decimalDigits: 2);
|
||||
|
||||
class TLThingy extends StatelessWidget {
|
||||
final TetraLeagueAlpha tl;
|
||||
final String userID;
|
||||
|
@ -32,10 +36,9 @@ class TLThingy extends StatelessWidget {
|
|||
: Image.asset("res/tetrio_tl_alpha_ranks/${tl.rank}.png", height: 128),
|
||||
Column(
|
||||
children: [
|
||||
Text("${tl.rating.toStringAsFixed(2)} TR",
|
||||
style: TextStyle(fontFamily: "Eurostile Round Extended", fontSize: bigScreen ? 42 : 28)),
|
||||
Text("${f2.format(tl.rating)} TR", style: TextStyle(fontFamily: "Eurostile Round Extended", fontSize: bigScreen ? 42 : 28)),
|
||||
Text(
|
||||
"Top ${(tl.percentile * 100).toStringAsFixed(2)}% (${tl.percentileRank.toUpperCase()}) • Top Rank: ${tl.bestRank.toUpperCase()} • Glicko: ${tl.glicko?.toStringAsFixed(2)}±${tl.rd?.toStringAsFixed(2)}${tl.decaying ? ' • Decaying' : ''}",
|
||||
"Top ${f2.format(tl.percentile * 100)}% (${tl.percentileRank.toUpperCase()}) • Top Rank: ${tl.bestRank.toUpperCase()} • Glicko: ${f2.format(tl.glicko!)}±${f2.format(tl.rd!)}${tl.decaying ? ' • Decaying' : ''}",
|
||||
textAlign: TextAlign.center,
|
||||
),
|
||||
],
|
||||
|
@ -45,6 +48,7 @@ class TLThingy extends StatelessWidget {
|
|||
else
|
||||
Text("${10 - tl.gamesPlayed} games until being ranked",
|
||||
softWrap: true,
|
||||
textAlign: TextAlign.center,
|
||||
style: TextStyle(
|
||||
fontFamily: "Eurostile Round Extended",
|
||||
fontSize: bigScreen ? 42 : 28,
|
||||
|
@ -116,7 +120,7 @@ class TLThingy extends StatelessWidget {
|
|||
style: TextStyle(fontSize: 24),
|
||||
),
|
||||
Text(
|
||||
tl.estTr!.esttr.toStringAsFixed(2),
|
||||
f2.format(tl.estTr!.esttr),
|
||||
style: const TextStyle(fontSize: 24),
|
||||
),
|
||||
],
|
||||
|
@ -130,7 +134,7 @@ class TLThingy extends StatelessWidget {
|
|||
style: TextStyle(fontSize: 24),
|
||||
),
|
||||
Text(
|
||||
tl.esttracc!.toStringAsFixed(2),
|
||||
fDiff.format(tl.esttracc!),
|
||||
style: const TextStyle(fontSize: 24),
|
||||
),
|
||||
],
|
||||
|
|
|
@ -2,6 +2,7 @@ import 'package:flutter/material.dart';
|
|||
import 'package:flutter/services.dart';
|
||||
import 'package:tetra_stats/data_objects/tetrio.dart';
|
||||
import 'package:tetra_stats/views/compare_view.dart';
|
||||
import 'package:intl/intl.dart';
|
||||
import 'dart:developer' as developer;
|
||||
import 'package:tetra_stats/widgets/stat_sell_num.dart';
|
||||
|
||||
|
@ -15,6 +16,8 @@ Future<void> copyToClipboard(String text) async {
|
|||
await Clipboard.setData(ClipboardData(text: text));
|
||||
}
|
||||
|
||||
final DateFormat dateFormat = DateFormat.yMMMd().add_Hms();
|
||||
|
||||
class UserThingy extends StatelessWidget {
|
||||
final TetrioPlayer player;
|
||||
final bool showStateTimestamp;
|
||||
|
@ -102,7 +105,7 @@ class UserThingy extends StatelessWidget {
|
|||
],
|
||||
)),
|
||||
showStateTimestamp
|
||||
? Text("Fetched ${player.state}")
|
||||
? Text("Fetched ${dateFormat.format(player.state)}")
|
||||
: Wrap(direction: Axis.horizontal, alignment: WrapAlignment.center, spacing: 25, crossAxisAlignment: WrapCrossAlignment.start, children: [
|
||||
FutureBuilder(
|
||||
future: teto.isPlayerTracking(player.userId),
|
||||
|
@ -209,7 +212,7 @@ class UserThingy extends StatelessWidget {
|
|||
children: [
|
||||
Expanded(
|
||||
child: Text(
|
||||
"${player.country != null ? "${player.country?.toUpperCase()} • " : ""}${player.role.capitalize()} account ${player.registrationTime == null ? "that was from very beginning" : 'created ${player.registrationTime}'}${player.botmaster != null ? " by ${player.botmaster}" : ""} • ${player.supporterTier == 0 ? "Not a supporter" : "Supporter tier ${player.supporterTier}"}",
|
||||
"${player.country != null ? "${player.country?.toUpperCase()} • " : ""}${player.role.capitalize()} account ${player.registrationTime == null ? "that was from very beginning" : 'created ${dateFormat.format(player.registrationTime!)}'}${player.botmaster != null ? " by ${player.botmaster}" : ""} • ${player.supporterTier == 0 ? "Not a supporter" : "Supporter tier ${player.supporterTier}"}",
|
||||
textAlign: TextAlign.center,
|
||||
style: const TextStyle(
|
||||
fontFamily: "Eurostile Round",
|
||||
|
@ -245,7 +248,9 @@ class UserThingy extends StatelessWidget {
|
|||
spacing: 25,
|
||||
children: [
|
||||
Image.asset("res/tetrio_badges/${badge.badgeId}.png"),
|
||||
Text(badge.ts != null ? "Obtained ${badge.ts}" : "That badge was assigned manualy by TETR.IO admins"),
|
||||
Text(badge.ts != null
|
||||
? "Obtained ${dateFormat.format(badge.ts!)}"
|
||||
: "That badge was assigned manualy by TETR.IO admins"),
|
||||
],
|
||||
)
|
||||
],
|
||||
|
|
|
@ -14,7 +14,7 @@ publish_to: 'none'
|
|||
# https://developer.apple.com/library/archive/documentation/General/Reference/InfoPlistKeyReference/Articles/CoreFoundationKeys.html
|
||||
# In Windows, build-name is used as the major, minor, and patch parts
|
||||
# of the product and file versions while build-number is used as the build suffix.
|
||||
version: 0.0.2+2
|
||||
version: 0.1.0+3
|
||||
|
||||
environment:
|
||||
sdk: '>=2.19.6 <3.0.0'
|
||||
|
|
Loading…
Reference in New Issue