40 Lines / Blitz grades and averages
+ another design changes
This commit is contained in:
parent
49c5dfdf5a
commit
0648ca9a5d
|
@ -117,6 +117,48 @@ const Map<String, Color> rankColors = { // thanks osk for const rankColors at ht
|
|||
'z': Color(0xFF375433)
|
||||
};
|
||||
|
||||
const Map<String, Duration> sprintAverages = { // based on https://discord.com/channels/673303546107658242/917098364787650590/1214231970259673098
|
||||
'x': Duration(seconds: 25, milliseconds: 413),
|
||||
'u': Duration(seconds: 34, milliseconds: 549),
|
||||
'ss': Duration(seconds: 43, milliseconds: 373),
|
||||
's+': Duration(seconds: 54, milliseconds: 027),
|
||||
's': Duration(seconds: 60, milliseconds: 412),
|
||||
's-': Duration(seconds: 67, milliseconds: 381),
|
||||
'a+': Duration(seconds: 73, milliseconds: 694),
|
||||
'a': Duration(seconds: 81, milliseconds: 166),
|
||||
'a-': Duration(seconds: 88, milliseconds: 334),
|
||||
'b+': Duration(seconds: 93, milliseconds: 741),
|
||||
'b': Duration(seconds: 98, milliseconds: 354),
|
||||
'b-': Duration(seconds: 109, milliseconds: 610),
|
||||
'c+': Duration(seconds: 124, milliseconds: 641),
|
||||
'c': Duration(seconds: 126, milliseconds: 104),
|
||||
'c-': Duration(seconds: 145, milliseconds: 865),
|
||||
'd+': Duration(seconds: 154, milliseconds: 338),
|
||||
'd': Duration(seconds: 162, milliseconds: 063),
|
||||
//'z': Duration(seconds: 66, milliseconds: 802)
|
||||
};
|
||||
|
||||
const Map<String, int> blitzAverages = {
|
||||
'x': 626494,
|
||||
'u': 406059,
|
||||
'ss': 243166,
|
||||
's+': 168636,
|
||||
's': 121594,
|
||||
's-': 107845,
|
||||
'a+': 87142,
|
||||
'a': 73413,
|
||||
'a-': 60799,
|
||||
'b+': 55417,
|
||||
'b': 47608,
|
||||
'b-': 40534,
|
||||
'c+': 34200,
|
||||
'c': 32535,
|
||||
'c-': 25808,
|
||||
'd+': 23345,
|
||||
'd': 23063,
|
||||
//'z': 72084
|
||||
};
|
||||
|
||||
String getStatNameByEnum(Stats stat){
|
||||
return t[stat.name];
|
||||
}
|
||||
|
|
|
@ -535,6 +535,12 @@ class TetrioService extends DB {
|
|||
}
|
||||
}
|
||||
|
||||
TetrioPlayersLeaderboard? getCachedLeaderboard(){
|
||||
return _leaderboardsCache.entries.firstOrNull?.value;
|
||||
// That function will break if i decide to recive other leaderboards
|
||||
// TODO: Think about better solution
|
||||
}
|
||||
|
||||
/// Retrieves and returns 100 latest news entries from Tetra Channel api for given [userID]. Throws an exception if fails to retrieve.
|
||||
Future<List<News>> fetchNews(String userID) async{
|
||||
try{
|
||||
|
|
|
@ -30,6 +30,7 @@ import 'package:flutter_markdown/flutter_markdown.dart';
|
|||
import 'package:go_router/go_router.dart';
|
||||
|
||||
Future<List> me = Future.delayed(const Duration(seconds: 60), () => [null, null, null, null, null, null]); // I love lists shut up
|
||||
TetrioPlayersLeaderboard? everyone;
|
||||
String _searchFor = "6098518e3d5155e6ec429cdc"; // who we looking for
|
||||
String _titleNickname = "dan63047";
|
||||
final TetrioService teto = TetrioService(); // thing, that manadge our local DB
|
||||
|
@ -38,8 +39,8 @@ var chartsData = <DropdownMenuItem<List<FlSpot>>>[];
|
|||
int _chartsIndex = 0;
|
||||
List _historyShortTitles = ["TR", "Glicko", "RD", "APM", "PPS", "VS", "APP", "DS/S", "DS/P", "APP + DS/P", "VS/APM", "Cheese", "GbE", "wAPP", "Area", "eTR", "±eTR", "Opener", "Plonk", "Inf. DS", "Stride"];
|
||||
late ScrollController _scrollController;
|
||||
final NumberFormat _timeInSec = NumberFormat("#,###.###s.");
|
||||
final NumberFormat secs = NumberFormat("00.###");
|
||||
final NumberFormat _timeInSec = NumberFormat("#,###.###s.", LocaleSettings.currentLocale.languageCode);
|
||||
final NumberFormat secs = NumberFormat("00.###", LocaleSettings.currentLocale.languageCode);
|
||||
final NumberFormat _f2 = NumberFormat.decimalPatternDigits(locale: LocaleSettings.currentLocale.languageCode, decimalDigits: 2);
|
||||
final NumberFormat _f4 = NumberFormat.decimalPatternDigits(locale: LocaleSettings.currentLocale.languageCode, decimalDigits: 4);
|
||||
final DateFormat _dateFormat = DateFormat.yMMMd(LocaleSettings.currentLocale.languageCode).add_Hms();
|
||||
|
@ -67,6 +68,20 @@ String get40lTime(int microseconds){
|
|||
return microseconds > 60000000 ? "${(microseconds/1000000/60).floor()}:${(secs.format(microseconds /1000000 % 60))}" : _timeInSec.format(microseconds / 1000000);
|
||||
}
|
||||
|
||||
/// Readable [a] - [b], without sign
|
||||
String readableTimeDifference(Duration a, Duration b){
|
||||
Duration result = a - b;
|
||||
|
||||
return "${NumberFormat("0.000s;0.000s", LocaleSettings.currentLocale.languageCode).format(result.inMilliseconds/1000)}";
|
||||
}
|
||||
|
||||
/// Readable [a] - [b], without sign
|
||||
String readableIntDifference(int a, int b){
|
||||
int result = a - b;
|
||||
|
||||
return "${NumberFormat("#,###;#,###", LocaleSettings.currentLocale.languageCode).format(result)}";
|
||||
}
|
||||
|
||||
class _MainState extends State<MainView> with TickerProviderStateMixin {
|
||||
final bodyGlobalKey = GlobalKey();
|
||||
bool _showSearchBar = false;
|
||||
|
@ -153,6 +168,9 @@ class _MainState extends State<MainView> with TickerProviderStateMixin {
|
|||
news = requests[2] as List<News>;
|
||||
topTR = requests.elementAtOrNull(3) as double?; // No TR - no Top TR
|
||||
|
||||
// Get tetra League leaderboard if needed
|
||||
// if(prefs.getBool("loadLeaderboard") == true) everyone = await teto.fetchTLLeaderboard();
|
||||
|
||||
// Making list of Tetra League matches
|
||||
List<TetraLeagueAlphaRecord> tlMatches = [];
|
||||
bool isTracking = await teto.isPlayerTracking(me.userId);
|
||||
|
@ -379,8 +397,8 @@ class _MainState extends State<MainView> with TickerProviderStateMixin {
|
|||
TLThingy(tl: snapshot.data![0].tlSeason1, userID: snapshot.data![0].userId, states: snapshot.data![2], topTR: snapshot.data![7], bot: snapshot.data![0].role == "bot", guest: snapshot.data![0].role == "anon"),
|
||||
_TLRecords(userID: snapshot.data![0].userId, data: snapshot.data![3]),
|
||||
_History(states: snapshot.data![2], update: _justUpdate),
|
||||
_RecordThingy(record: snapshot.data![1]['sprint']),
|
||||
_RecordThingy(record: snapshot.data![1]['blitz']),
|
||||
_RecordThingy(record: snapshot.data![1]['sprint'], rank: snapshot.data![0].tlSeason1.percentileRank),
|
||||
_RecordThingy(record: snapshot.data![1]['blitz'], rank: snapshot.data![0].tlSeason1.percentileRank),
|
||||
_OtherThingy(zen: snapshot.data![1]['zen'], bio: snapshot.data![0].bio, distinguishment: snapshot.data![0].distinguishment, newsletter: snapshot.data![6],)
|
||||
],
|
||||
),
|
||||
|
@ -906,13 +924,27 @@ class _HistoryChartThigyState extends State<_HistoryChartThigy> {
|
|||
|
||||
class _RecordThingy extends StatelessWidget {
|
||||
final RecordSingle? record;
|
||||
final String? rank;
|
||||
|
||||
/// Widget that displays data from [record]
|
||||
const _RecordThingy({required this.record});
|
||||
const _RecordThingy({required this.record, this.rank});
|
||||
|
||||
@override
|
||||
Widget build(BuildContext context) {
|
||||
if (record == null) return Center(child: Text(t.noRecord, textAlign: TextAlign.center, style: const TextStyle(fontFamily: "Eurostile Round", fontSize: 28)));
|
||||
late MapEntry closestAverageBlitz;
|
||||
late bool blitzBetterThanClosestAverage;
|
||||
bool? blitzBetterThanRankAverage = (rank != null && rank != "z") ? record!.endContext!.score > blitzAverages[rank]! : null;
|
||||
late MapEntry closestAverageSprint;
|
||||
late bool sprintBetterThanClosestAverage;
|
||||
bool? sprintBetterThanRankAverage = (rank != null && rank != "z") ? record!.endContext!.finalTime < sprintAverages[rank]! : null;
|
||||
if (record!.stream.contains("40l")) {
|
||||
closestAverageSprint = sprintAverages.entries.singleWhere((element) => element.value == sprintAverages.values.reduce((a, b) => (a-record!.endContext!.finalTime).abs() < (b -record!.endContext!.finalTime).abs() ? a : b));
|
||||
sprintBetterThanClosestAverage = record!.endContext!.finalTime < closestAverageSprint.value;
|
||||
}else if (record!.stream.contains("blitz")){
|
||||
closestAverageBlitz = blitzAverages.entries.singleWhere((element) => element.value == blitzAverages.values.reduce((a, b) => (a-record!.endContext!.score).abs() < (b -record!.endContext!.score).abs() ? a : b));
|
||||
blitzBetterThanClosestAverage = record!.endContext!.score > closestAverageBlitz.value;
|
||||
}
|
||||
return LayoutBuilder(builder: (context, constraints) {
|
||||
bool bigScreen = constraints.maxWidth > 768;
|
||||
return ListView.builder(
|
||||
|
@ -926,9 +958,72 @@ class _RecordThingy extends StatelessWidget {
|
|||
else if (record!.stream.contains("blitz")) Text(t.blitz, style: TextStyle(fontFamily: "Eurostile Round Extended", fontSize: bigScreen ? 42 : 28)),
|
||||
|
||||
// show main metric
|
||||
Wrap(
|
||||
direction: Axis.horizontal,
|
||||
alignment: WrapAlignment.spaceAround,
|
||||
crossAxisAlignment: WrapCrossAlignment.center,
|
||||
clipBehavior: Clip.hardEdge,
|
||||
children: [
|
||||
// Show grade based on closest rank average
|
||||
if (record!.stream.contains("40l")) Image.asset("res/tetrio_tl_alpha_ranks/${closestAverageSprint.key}.png", height: 96)
|
||||
else if (record!.stream.contains("blitz")) Image.asset("res/tetrio_tl_alpha_ranks/${closestAverageBlitz.key}.png", height: 96),
|
||||
|
||||
// TODO: I'm not sure abour that element. Maybe, it could be done differenly
|
||||
Column(
|
||||
children: [
|
||||
// Show result
|
||||
if (record!.stream.contains("40l")) Text(get40lTime(record!.endContext!.finalTime.inMicroseconds), style: TextStyle(fontFamily: "Eurostile Round Extended", fontSize: bigScreen ? 42 : 28))
|
||||
else if (record!.stream.contains("blitz")) Text(NumberFormat.decimalPattern().format(record!.endContext!.score), style: TextStyle(fontFamily: "Eurostile Round Extended", fontSize: bigScreen ? 42 : 28)),
|
||||
|
||||
// Show difference between rank average
|
||||
if (record!.stream.contains("40l") && (rank != null && rank != "z")) Text(
|
||||
"${readableTimeDifference(record!.endContext!.finalTime, sprintAverages[rank]!)} ${sprintBetterThanRankAverage??false ? "better" : "worse"} than ${rank!.toUpperCase()} rank average",
|
||||
textAlign: TextAlign.center,
|
||||
style: TextStyle(
|
||||
color: sprintBetterThanRankAverage??false ?
|
||||
Colors.greenAccent :
|
||||
Colors.redAccent
|
||||
)
|
||||
)
|
||||
else if (record!.stream.contains("40l") && (rank == null || rank == "z")) Text(
|
||||
"${readableTimeDifference(record!.endContext!.finalTime, closestAverageSprint.value)} ${sprintBetterThanClosestAverage ? "better" : "worse"} than ${closestAverageSprint.key!.toUpperCase()} rank average",
|
||||
textAlign: TextAlign.center,
|
||||
style: TextStyle(
|
||||
color: sprintBetterThanClosestAverage ?
|
||||
Colors.greenAccent :
|
||||
Colors.redAccent
|
||||
)
|
||||
)
|
||||
else if (record!.stream.contains("blitz") && (rank != null && rank != "z")) Text(
|
||||
"${readableIntDifference(record!.endContext!.score, blitzAverages[rank]!)} ${blitzBetterThanRankAverage??false ? "better" : "worse"} than ${rank!.toUpperCase()} rank average",
|
||||
textAlign: TextAlign.center,
|
||||
style: TextStyle(
|
||||
color: blitzBetterThanRankAverage??false ?
|
||||
Colors.greenAccent :
|
||||
Colors.redAccent
|
||||
)
|
||||
)
|
||||
else if (record!.stream.contains("blitz") && (rank == null || rank == "z")) Text(
|
||||
"${readableIntDifference(record!.endContext!.score, closestAverageBlitz.value)} ${blitzBetterThanClosestAverage ? "better" : "worse"} than ${closestAverageBlitz.key!.toUpperCase()} rank average",
|
||||
textAlign: TextAlign.center,
|
||||
style: TextStyle(
|
||||
color: blitzBetterThanClosestAverage ?
|
||||
Colors.greenAccent :
|
||||
Colors.redAccent
|
||||
)
|
||||
),
|
||||
],
|
||||
),
|
||||
],
|
||||
),
|
||||
// if (record!.stream.contains("40l")) Text(get40lTime(record!.endContext!.finalTime.inMicroseconds), style: TextStyle(fontFamily: "Eurostile Round Extended", fontSize: bigScreen ? 42 : 28))
|
||||
// else if (record!.stream.contains("blitz")) Text(NumberFormat.decimalPattern().format(record!.endContext!.score), style: TextStyle(fontFamily: "Eurostile Round Extended", fontSize: bigScreen ? 42 : 28)),
|
||||
|
||||
// // Compare with averages
|
||||
// if (record!.stream.contains("40l") && rank != null) RichText(text: TextSpan(text: "${readableTimeDifference(record!.endContext!.finalTime, sprintAverages[rank]!)} ${sprintBetterThanRankAverage??false ? "better" : "worse"} than ${rank!.toUpperCase()} rank average", style: TextStyle(fontFamily: "Eurostile Round", color: sprintBetterThanRankAverage??false ? Colors.green : Colors.red)))
|
||||
// //Text("${record!.endContext!.finalTime - sprintAverages[rank]!}; ${sprintAverages[rank]}; ${get40lTime((record!.endContext!.finalTime - sprintAverages[rank]!).inMicroseconds)}")
|
||||
// else if (record!.stream.contains("blitz")) Text("${closestAverageBlitz}; ${blitzAverages[rank]}"),
|
||||
|
||||
// Show rank if presented
|
||||
if (record!.rank != null) StatCellNum(playerStat: record!.rank!, playerStatLabel: "Leaderboard Placement", isScreenBig: bigScreen, higherIsBetter: false),
|
||||
|
||||
|
|
|
@ -26,6 +26,7 @@ class SettingsState extends State<SettingsView> {
|
|||
late SharedPreferences prefs;
|
||||
final TetrioService teto = TetrioService();
|
||||
String defaultNickname = "Checking...";
|
||||
late bool loadLeaderboard;
|
||||
final TextEditingController _playertext = TextEditingController();
|
||||
|
||||
@override
|
||||
|
@ -46,6 +47,11 @@ class SettingsState extends State<SettingsView> {
|
|||
|
||||
Future<void> _getPreferences() async {
|
||||
prefs = await SharedPreferences.getInstance();
|
||||
if (prefs.getBool("loadLeaderboard") != null) {
|
||||
loadLeaderboard = prefs.getBool("loadLeaderboard")!;
|
||||
} else {
|
||||
loadLeaderboard = false;
|
||||
}
|
||||
_setDefaultNickname(prefs.getString("player"));
|
||||
}
|
||||
|
||||
|
@ -260,6 +266,14 @@ class SettingsState extends State<SettingsView> {
|
|||
onTap: () {
|
||||
Navigator.pushNamed(context, "/customization");
|
||||
},),
|
||||
ListTile(title: Text("Load leaderboard on startup"),
|
||||
subtitle: Text("That will allow app to show additional stats, like..."),
|
||||
trailing: Switch(value: loadLeaderboard, onChanged: (bool value){
|
||||
prefs.setBool("loadLeaderboard", value);
|
||||
setState(() {
|
||||
loadLeaderboard = value;
|
||||
});
|
||||
}),),
|
||||
const Divider(),
|
||||
ListTile(
|
||||
onTap: (){
|
||||
|
|
|
@ -15,6 +15,7 @@ class TrailingStats extends StatelessWidget{
|
|||
@override
|
||||
Widget build(BuildContext context) {
|
||||
final NumberFormat f2 = NumberFormat.decimalPatternDigits(locale: LocaleSettings.currentLocale.languageCode, decimalDigits: 2);
|
||||
const TextStyle style = TextStyle(height: 1.1, fontWeight: FontWeight.w100);
|
||||
return Table(
|
||||
defaultColumnWidth: const IntrinsicColumnWidth(),
|
||||
defaultVerticalAlignment: TableCellVerticalAlignment.baseline,
|
||||
|
@ -24,9 +25,9 @@ class TrailingStats extends StatelessWidget{
|
|||
2: FixedColumnWidth(42),
|
||||
},
|
||||
children: [
|
||||
TableRow(children: [Text(f2.format(yourAPM), textAlign: TextAlign.right, style: const TextStyle(height: 1.1)), const Text(" :", style: TextStyle(height: 1.1)), Text(f2.format(notyourAPM), textAlign: TextAlign.right, style: const TextStyle(height: 1.1)), const Text(" APM", textAlign: TextAlign.right, style: TextStyle(height: 1.1))]),
|
||||
TableRow(children: [Text(f2.format(yourPPS), textAlign: TextAlign.right, style: const TextStyle(height: 1.1)), const Text(" :", style: TextStyle(height: 1.1)), Text(f2.format(notyourPPS), textAlign: TextAlign.right, style: const TextStyle(height: 1.1)), const Text(" PPS", textAlign: TextAlign.right, style: TextStyle(height: 1.1))]),
|
||||
TableRow(children: [Text(f2.format(yourVS), textAlign: TextAlign.right, style: const TextStyle(height: 1.1)), const Text(" :", style: TextStyle(height: 1.1)), Text(f2.format(notyourVS), textAlign: TextAlign.right, style: const TextStyle(height: 1.1)), const Text(" VS", textAlign: TextAlign.right, style: TextStyle(height: 1.1))]),
|
||||
TableRow(children: [Text(f2.format(yourAPM), textAlign: TextAlign.right, style: style), const Text(" :", style: style), Text(f2.format(notyourAPM), textAlign: TextAlign.right, style: style), const Text(" APM", textAlign: TextAlign.right, style: style)]),
|
||||
TableRow(children: [Text(f2.format(yourPPS), textAlign: TextAlign.right, style: style), const Text(" :", style: style), Text(f2.format(notyourPPS), textAlign: TextAlign.right, style: style), const Text(" PPS", textAlign: TextAlign.right, style: style)]),
|
||||
TableRow(children: [Text(f2.format(yourVS), textAlign: TextAlign.right, style: style), const Text(" :", style: style), Text(f2.format(notyourVS), textAlign: TextAlign.right, style: style), const Text(" VS", textAlign: TextAlign.right, style: style)]),
|
||||
],
|
||||
);
|
||||
}
|
||||
|
|
|
@ -50,8 +50,8 @@ class StatCellNum extends StatelessWidget {
|
|||
),
|
||||
if (oldPlayerStat != null) Text(comparef.format(playerStat - oldPlayerStat!), style: TextStyle(
|
||||
color: higherIsBetter ?
|
||||
oldPlayerStat! > playerStat ? Colors.red : Colors.green :
|
||||
oldPlayerStat! < playerStat ? Colors.red : Colors.green
|
||||
oldPlayerStat! > playerStat ? Colors.redAccent : Colors.greenAccent :
|
||||
oldPlayerStat! < playerStat ? Colors.redAccent : Colors.greenAccent
|
||||
),),
|
||||
alertWidgets == null
|
||||
? Text(
|
||||
|
|
|
@ -241,8 +241,8 @@ class _TLThingyState extends State<TLThingy> {
|
|||
},), verticalAlignment: GaugeAlignment.far, positionFactor: 0.05,),
|
||||
if (oldTl != null && oldTl!.gamesPlayed > 0) GaugeAnnotation(widget: Text(fDiff.format(currentTl.nerdStats!.app - oldTl!.nerdStats!.app), style: TextStyle(
|
||||
color: currentTl.nerdStats!.app - oldTl!.nerdStats!.app < 0 ?
|
||||
Colors.red :
|
||||
Colors.green
|
||||
Colors.redAccent :
|
||||
Colors.greenAccent
|
||||
),), positionFactor: 0.05,)],
|
||||
)],),
|
||||
),
|
||||
|
@ -303,8 +303,8 @@ class _TLThingyState extends State<TLThingy> {
|
|||
},), verticalAlignment: GaugeAlignment.far, positionFactor: 0.05),
|
||||
if (oldTl != null && oldTl!.gamesPlayed > 0) GaugeAnnotation(widget: Text(fDiff.format(currentTl.nerdStats!.vsapm - oldTl!.nerdStats!.vsapm), style: TextStyle(
|
||||
color: currentTl.nerdStats!.vsapm - oldTl!.nerdStats!.vsapm < 0 ?
|
||||
Colors.red :
|
||||
Colors.green
|
||||
Colors.redAccent :
|
||||
Colors.greenAccent
|
||||
),), positionFactor: 0.05,)],
|
||||
)],),
|
||||
),]),
|
||||
|
|
Loading…
Reference in New Issue