TL records are now stored in the database
for tracked players only. Also fixed variety of shit
This commit is contained in:
parent
5d5ac32a8b
commit
8770d5dca8
|
@ -12,8 +12,8 @@
|
||||||
- ~~Ability to compare 2 players~~ *v0.1.0, we are here*
|
- ~~Ability to compare 2 players~~ *v0.1.0, we are here*
|
||||||
- ~~Stats Calculator~~
|
- ~~Stats Calculator~~
|
||||||
- ~~Ability to compare player with himself in past~~
|
- ~~Ability to compare player with himself in past~~
|
||||||
- ~~Tetra League matches history~~ *dev build are here*
|
- ~~Tetra League matches history~~
|
||||||
- ~~Tetra League historic charts for tracked players~~ (bit mess idk)
|
- ~~Tetra League historic charts for tracked players~~ *dev build are here*
|
||||||
- Better UI with delta and hints for stats *that will be v0.2.0*
|
- Better UI with delta and hints for stats *that will be v0.2.0*
|
||||||
- Ability to compare player with APM-PPS-VS stats
|
- Ability to compare player with APM-PPS-VS stats
|
||||||
- Ability to fetch Tetra League leaderboard
|
- Ability to fetch Tetra League leaderboard
|
||||||
|
@ -22,7 +22,7 @@
|
||||||
- UI Animations
|
- UI Animations
|
||||||
- i18n, EN and RU locales
|
- i18n, EN and RU locales
|
||||||
- Talk with osk about CORS and EndContext in TL matches
|
- Talk with osk about CORS and EndContext in TL matches
|
||||||
- RELEASE ???
|
- RELEASE ??? *that will be v1.0.0*
|
||||||
|
|
||||||
---
|
---
|
||||||
|
|
||||||
|
|
|
@ -1,31 +1,31 @@
|
||||||
buildscript {
|
buildscript {
|
||||||
ext.kotlin_version = '1.7.10'
|
ext.kotlin_version = '1.7.10'
|
||||||
repositories {
|
repositories {
|
||||||
google()
|
google()
|
||||||
mavenCentral()
|
mavenCentral()
|
||||||
}
|
}
|
||||||
|
|
||||||
dependencies {
|
dependencies {
|
||||||
classpath 'com.android.tools.build:gradle:7.2.0'
|
classpath 'com.android.tools.build:gradle:7.2.0'
|
||||||
classpath "org.jetbrains.kotlin:kotlin-gradle-plugin:$kotlin_version"
|
classpath "org.jetbrains.kotlin:kotlin-gradle-plugin:$kotlin_version"
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
allprojects {
|
allprojects {
|
||||||
repositories {
|
repositories {
|
||||||
google()
|
google()
|
||||||
mavenCentral()
|
mavenCentral()
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
rootProject.buildDir = '../build'
|
rootProject.buildDir = '../build'
|
||||||
subprojects {
|
subprojects {
|
||||||
project.buildDir = "${rootProject.buildDir}/${project.name}"
|
project.buildDir = "${rootProject.buildDir}/${project.name}"
|
||||||
}
|
}
|
||||||
subprojects {
|
subprojects {
|
||||||
project.evaluationDependsOn(':app')
|
project.evaluationDependsOn(':app')
|
||||||
}
|
}
|
||||||
|
|
||||||
task clean(type: Delete) {
|
tasks.register("clean", Delete) {
|
||||||
delete rootProject.buildDir
|
delete rootProject.buildDir
|
||||||
}
|
}
|
||||||
|
|
|
@ -430,10 +430,10 @@ class Handling {
|
||||||
|
|
||||||
Map<String, dynamic> toJson() {
|
Map<String, dynamic> toJson() {
|
||||||
final Map<String, dynamic> data = <String, dynamic>{};
|
final Map<String, dynamic> data = <String, dynamic>{};
|
||||||
data['arr'] = arr;
|
data['arr'] = arr.toDouble();
|
||||||
data['das'] = das;
|
data['das'] = das.toDouble();
|
||||||
data['dcd'] = dcd;
|
data['dcd'] = dcd.toDouble();
|
||||||
data['sdf'] = sdf;
|
data['sdf'] = sdf.toDouble();
|
||||||
data['safelock'] = safeLock;
|
data['safelock'] = safeLock;
|
||||||
data['cancel'] = cancel;
|
data['cancel'] = cancel;
|
||||||
return data;
|
return data;
|
||||||
|
@ -526,24 +526,24 @@ class Playstyle {
|
||||||
|
|
||||||
class TetraLeagueAlphaStream{
|
class TetraLeagueAlphaStream{
|
||||||
late String userId;
|
late String userId;
|
||||||
List<TetraLeagueAlphaRecord>? records;
|
late List<TetraLeagueAlphaRecord> records;
|
||||||
|
|
||||||
TetraLeagueAlphaStream({required this.userId, this.records});
|
TetraLeagueAlphaStream({required this.userId, required this.records});
|
||||||
|
|
||||||
TetraLeagueAlphaStream.fromJson(List<dynamic> json, String userID) {
|
TetraLeagueAlphaStream.fromJson(List<dynamic> json, String userID) {
|
||||||
userId = userID;
|
userId = userID;
|
||||||
records = [];
|
records = [];
|
||||||
for (var value in json) {records!.add(TetraLeagueAlphaRecord.fromJson(value));}
|
for (var value in json) {records.add(TetraLeagueAlphaRecord.fromJson(value));}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
class TetraLeagueAlphaRecord{
|
class TetraLeagueAlphaRecord{
|
||||||
late String replayId;
|
late String replayId;
|
||||||
late String ownId;
|
late String ownId;
|
||||||
DateTime? timestamp;
|
late DateTime timestamp;
|
||||||
late List<EndContextMulti> endContext;
|
late List<EndContextMulti> endContext;
|
||||||
|
|
||||||
TetraLeagueAlphaRecord({required this.replayId, required this.ownId, this.timestamp, required this.endContext});
|
TetraLeagueAlphaRecord({required this.replayId, required this.ownId, required this.timestamp, required this.endContext});
|
||||||
|
|
||||||
TetraLeagueAlphaRecord.fromJson(Map<String, dynamic> json) {
|
TetraLeagueAlphaRecord.fromJson(Map<String, dynamic> json) {
|
||||||
ownId = json['_id'];
|
ownId = json['_id'];
|
||||||
|
@ -561,6 +561,10 @@ class TetraLeagueAlphaRecord{
|
||||||
data['ts'] = timestamp;
|
data['ts'] = timestamp;
|
||||||
return data;
|
return data;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@override
|
||||||
|
bool operator ==(covariant TetraLeagueAlphaRecord other) => ownId == other.ownId;
|
||||||
|
|
||||||
@override
|
@override
|
||||||
String toString() {
|
String toString() {
|
||||||
return "TetraLeagueAlphaRecord: ${endContext.first.userId} vs ${endContext.last.userId}";
|
return "TetraLeagueAlphaRecord: ${endContext.first.userId} vs ${endContext.last.userId}";
|
||||||
|
@ -577,11 +581,11 @@ class EndContextMulti {
|
||||||
late int points;
|
late int points;
|
||||||
late int wins;
|
late int wins;
|
||||||
late double secondary;
|
late double secondary;
|
||||||
late List<double> secondaryTracking;
|
late List secondaryTracking;
|
||||||
late double tertiary;
|
late double tertiary;
|
||||||
late List<double> tertiaryTracking;
|
late List tertiaryTracking;
|
||||||
late double extra;
|
late double extra;
|
||||||
late List<double> extraTracking;
|
late List extraTracking;
|
||||||
late bool success;
|
late bool success;
|
||||||
late NerdStats nerdStats;
|
late NerdStats nerdStats;
|
||||||
late EstTr estTr;
|
late EstTr estTr;
|
||||||
|
@ -616,10 +620,10 @@ class EndContextMulti {
|
||||||
points = json['points']['primary'];
|
points = json['points']['primary'];
|
||||||
secondary = json['points']['secondary'].toDouble();
|
secondary = json['points']['secondary'].toDouble();
|
||||||
tertiary = json['points']['tertiary'].toDouble();
|
tertiary = json['points']['tertiary'].toDouble();
|
||||||
secondaryTracking = json['points']['secondaryAvgTracking'].cast<double>();
|
secondaryTracking = json['points']['secondaryAvgTracking'].map((e) => e.toDouble()).toList();
|
||||||
tertiaryTracking = json['points']['tertiaryAvgTracking'].cast<double>();
|
tertiaryTracking = json['points']['tertiaryAvgTracking'].map((e) => e.toDouble()).toList();
|
||||||
extra = json['points']['extra']['vs'].toDouble();
|
extra = json['points']['extra']['vs'].toDouble();
|
||||||
extraTracking = json['points']['extraAvgTracking']['aggregatestats___vsscore'].cast<double>();
|
extraTracking = json['points']['extraAvgTracking']['aggregatestats___vsscore'].map((e) => e.toDouble()).toList();
|
||||||
nerdStats = NerdStats(secondary, tertiary, extra);
|
nerdStats = NerdStats(secondary, tertiary, extra);
|
||||||
estTr = EstTr(secondary, tertiary, extra, noTrRd, nerdStats.app, nerdStats.dss, nerdStats.dsp, nerdStats.gbe);
|
estTr = EstTr(secondary, tertiary, extra, noTrRd, nerdStats.app, nerdStats.dss, nerdStats.dsp, nerdStats.gbe);
|
||||||
playstyle = Playstyle(secondary, tertiary, nerdStats.app, nerdStats.vsapm, nerdStats.dsp, nerdStats.gbe, estTr.srarea, estTr.statrank);
|
playstyle = Playstyle(secondary, tertiary, nerdStats.app, nerdStats.vsapm, nerdStats.dsp, nerdStats.gbe, estTr.srarea, estTr.statrank);
|
||||||
|
@ -627,19 +631,14 @@ class EndContextMulti {
|
||||||
|
|
||||||
Map<String, dynamic> toJson() {
|
Map<String, dynamic> toJson() {
|
||||||
final Map<String, dynamic> data = <String, dynamic>{};
|
final Map<String, dynamic> data = <String, dynamic>{};
|
||||||
data['user']['_id'] = userId;
|
data['user'] = {'_id': userId, 'username': username};
|
||||||
data['user']['username'] = username;
|
|
||||||
data['handling'] = handling.toJson();
|
data['handling'] = handling.toJson();
|
||||||
data['success'] = success;
|
data['success'] = success;
|
||||||
data['inputs'] = inputs;
|
data['inputs'] = inputs;
|
||||||
data['piecesplaced'] = piecesPlaced;
|
data['piecesplaced'] = piecesPlaced;
|
||||||
data['naturalorder'] = naturalOrder;
|
data['naturalorder'] = naturalOrder;
|
||||||
data['wins'] = wins;
|
data['wins'] = wins;
|
||||||
data['points']['primary'] = points;
|
data['points'] = {'primary': points, 'secondary': secondary, 'tertiary':tertiary, 'extra': {'vs': extra}, 'secondaryAvgTracking': secondaryTracking, 'tertiaryAvgTracking': tertiaryTracking, 'extraAvgTracking': {'aggregatestats___vsscore': extraTracking}};
|
||||||
data['points']['secondary'] = secondary;
|
|
||||||
data['points']['tertiary'] = tertiary;
|
|
||||||
data['points']['extra']['vs'] = extra;
|
|
||||||
data['points']['extraAvgTracking']['aggregatestats___vsscore'] = extraTracking;
|
|
||||||
return data;
|
return data;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -20,6 +20,7 @@ class DB {
|
||||||
_db = db;
|
_db = db;
|
||||||
await db.execute(createTetrioUsersTable);
|
await db.execute(createTetrioUsersTable);
|
||||||
await db.execute(createTetrioUsersToTrack);
|
await db.execute(createTetrioUsersToTrack);
|
||||||
|
await db.execute(createTetrioTLRecordsTable);
|
||||||
} on MissingPlatformDirectoryException {
|
} on MissingPlatformDirectoryException {
|
||||||
throw UnableToGetDocuments();
|
throw UnableToGetDocuments();
|
||||||
}
|
}
|
||||||
|
|
|
@ -9,10 +9,16 @@ import 'package:tetra_stats/data_objects/tetrio.dart';
|
||||||
const String dbName = "TetraStats.db";
|
const String dbName = "TetraStats.db";
|
||||||
const String tetrioUsersTable = "tetrioUsers";
|
const String tetrioUsersTable = "tetrioUsers";
|
||||||
const String tetrioUsersToTrackTable = "tetrioUsersToTrack";
|
const String tetrioUsersToTrackTable = "tetrioUsersToTrack";
|
||||||
const String tetraLeagueMatchesTable = "tetraLeagueMatches";
|
const String tetraLeagueMatchesTable = "tetrioAlphaLeagueMathces";
|
||||||
const String idCol = "id";
|
const String idCol = "id";
|
||||||
|
const String replayID = "replayId";
|
||||||
const String nickCol = "nickname";
|
const String nickCol = "nickname";
|
||||||
|
const String timestamp = "timestamp";
|
||||||
|
const String endContext1 = "endContext1";
|
||||||
|
const String endContext2 = "endContext2";
|
||||||
const String statesCol = "jsonStates";
|
const String statesCol = "jsonStates";
|
||||||
|
const String player1id = "player1id";
|
||||||
|
const String player2id = "player2id";
|
||||||
const String createTetrioUsersTable = '''
|
const String createTetrioUsersTable = '''
|
||||||
CREATE TABLE IF NOT EXISTS "tetrioUsers" (
|
CREATE TABLE IF NOT EXISTS "tetrioUsers" (
|
||||||
"id" TEXT UNIQUE,
|
"id" TEXT UNIQUE,
|
||||||
|
@ -26,6 +32,17 @@ const String createTetrioUsersToTrack = '''
|
||||||
PRIMARY KEY("ID")
|
PRIMARY KEY("ID")
|
||||||
)
|
)
|
||||||
''';
|
''';
|
||||||
|
const String createTetrioTLRecordsTable = '''
|
||||||
|
CREATE TABLE IF NOT EXISTS "tetrioAlphaLeagueMathces" (
|
||||||
|
"id" TEXT,
|
||||||
|
"replayId" TEXT,
|
||||||
|
"player1id" TEXT,
|
||||||
|
"player2id" TEXT,
|
||||||
|
"timestamp" TEXT,
|
||||||
|
"endContext1" TEXT,
|
||||||
|
"endContext2" TEXT
|
||||||
|
)
|
||||||
|
''';
|
||||||
|
|
||||||
class TetrioService extends DB {
|
class TetrioService extends DB {
|
||||||
Map<String, List<TetrioPlayer>> _players = {};
|
Map<String, List<TetrioPlayer>> _players = {};
|
||||||
|
@ -108,6 +125,27 @@ class TetrioService extends DB {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
Future<void> saveTLMatchesFromStream(TetraLeagueAlphaStream stream) async {
|
||||||
|
ensureDbIsOpen();
|
||||||
|
final db = getDatabaseOrThrow();
|
||||||
|
for (TetraLeagueAlphaRecord match in stream.records) {
|
||||||
|
final results = await db.query(tetraLeagueMatchesTable, where: '$idCol = ?', whereArgs: [match.ownId]);
|
||||||
|
if (results.isNotEmpty) continue;
|
||||||
|
db.insert(tetraLeagueMatchesTable, {idCol: match.ownId, replayID: match.replayId, timestamp: match.timestamp.toString(), player1id: match.endContext.first.userId, player2id: match.endContext.last.userId, endContext1: jsonEncode(match.endContext.first.toJson()), endContext2: jsonEncode(match.endContext.last.toJson())});
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
Future<List<TetraLeagueAlphaRecord>> getTLMatchesbyPlayerID(String playerID) async {
|
||||||
|
ensureDbIsOpen();
|
||||||
|
final db = getDatabaseOrThrow();
|
||||||
|
List<TetraLeagueAlphaRecord> matches = [];
|
||||||
|
final results = await db.query(tetraLeagueMatchesTable, where: '($player1id = ?) OR ($player2id = ?)', whereArgs: [playerID, playerID]);
|
||||||
|
for (var match in results){
|
||||||
|
matches.add(TetraLeagueAlphaRecord(ownId: match[idCol].toString(), replayId: match[replayID].toString(), timestamp: DateTime.parse(match[timestamp].toString()), endContext:[EndContextMulti.fromJson(jsonDecode(match[endContext1].toString())), EndContextMulti.fromJson(jsonDecode(match[endContext2].toString()))]));
|
||||||
|
}
|
||||||
|
return matches;
|
||||||
|
}
|
||||||
|
|
||||||
Future<Map<String, dynamic>> fetchRecords(String userID) async {
|
Future<Map<String, dynamic>> fetchRecords(String userID) async {
|
||||||
try{
|
try{
|
||||||
var cached = _recordsCache.entries.firstWhere((element) => element.value['user'] == userID);
|
var cached = _recordsCache.entries.firstWhere((element) => element.value['user'] == userID);
|
||||||
|
|
|
@ -1194,8 +1194,9 @@ class CompareRegTimeThingy extends StatelessWidget {
|
||||||
String verdict(DateTime? greenSide, DateTime? redSide) {
|
String verdict(DateTime? greenSide, DateTime? redSide) {
|
||||||
var f = NumberFormat("#,### days later;#,### days before");
|
var f = NumberFormat("#,### days later;#,### days before");
|
||||||
String result = "---";
|
String result = "---";
|
||||||
if (greenSide != null && redSide != null)
|
if (greenSide != null && redSide != null) {
|
||||||
result = f.format(greenSide.difference(redSide).inDays);
|
result = f.format(greenSide.difference(redSide).inDays);
|
||||||
|
}
|
||||||
return result;
|
return result;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -1,5 +1,6 @@
|
||||||
import 'package:flutter/material.dart';
|
import 'package:flutter/material.dart';
|
||||||
import 'package:intl/intl.dart';
|
import 'package:intl/intl.dart';
|
||||||
|
import 'dart:math';
|
||||||
import 'package:fl_chart/fl_chart.dart';
|
import 'package:fl_chart/fl_chart.dart';
|
||||||
import 'package:shared_preferences/shared_preferences.dart';
|
import 'package:shared_preferences/shared_preferences.dart';
|
||||||
import 'package:flutter/services.dart';
|
import 'package:flutter/services.dart';
|
||||||
|
@ -21,6 +22,7 @@ const allowedHeightForPlayerBioInPixels = 30.0;
|
||||||
const givenTextHeightByScreenPercentage = 0.3;
|
const givenTextHeightByScreenPercentage = 0.3;
|
||||||
final NumberFormat timeInSec = NumberFormat("#,###.###s.");
|
final NumberFormat timeInSec = NumberFormat("#,###.###s.");
|
||||||
final NumberFormat f2 = NumberFormat.decimalPatternDigits(decimalDigits: 2);
|
final NumberFormat f2 = NumberFormat.decimalPatternDigits(decimalDigits: 2);
|
||||||
|
final NumberFormat f4 = NumberFormat.decimalPatternDigits(decimalDigits: 4);
|
||||||
final DateFormat dateFormat = DateFormat.yMMMd().add_Hms();
|
final DateFormat dateFormat = DateFormat.yMMMd().add_Hms();
|
||||||
|
|
||||||
class MainView extends StatefulWidget {
|
class MainView extends StatefulWidget {
|
||||||
|
@ -112,12 +114,31 @@ class _MainState extends State<MainView> with SingleTickerProviderStateMixin {
|
||||||
List<TetrioPlayer> states = [];
|
List<TetrioPlayer> states = [];
|
||||||
if (isTracking){
|
if (isTracking){
|
||||||
teto.storeState(me);
|
teto.storeState(me);
|
||||||
|
teto.saveTLMatchesFromStream(await teto.getTLStream(me.userId));
|
||||||
states.addAll(await teto.getPlayer(me.userId));
|
states.addAll(await teto.getPlayer(me.userId));
|
||||||
}
|
}
|
||||||
Map<String, dynamic> records = await teto.fetchRecords(me.userId);
|
Map<String, dynamic> records = await teto.fetchRecords(me.userId);
|
||||||
return [me, records, states, isTracking];
|
return [me, records, states, isTracking];
|
||||||
}
|
}
|
||||||
|
|
||||||
|
Future<List<TetraLeagueAlphaRecord>> getTLMatches(String userID) async {
|
||||||
|
var fetched = await teto.getTLStream(userID);
|
||||||
|
bool isTracked = await teto.isPlayerTracking(userID);
|
||||||
|
if (!isTracked) return fetched.records;
|
||||||
|
teto.saveTLMatchesFromStream(fetched);
|
||||||
|
var fromdb = await teto.getTLMatchesbyPlayerID(userID);
|
||||||
|
for (var match in fetched.records) {
|
||||||
|
if (!fromdb.contains(match)) fromdb.add(match);
|
||||||
|
}
|
||||||
|
fromdb.sort((a, b) {
|
||||||
|
if(a.timestamp.isBefore(b.timestamp)) return 1;
|
||||||
|
if(a.timestamp.isAtSameMomentAs(b.timestamp)) return 0;
|
||||||
|
if(a.timestamp.isAfter(b.timestamp)) return -1;
|
||||||
|
return 0;
|
||||||
|
});
|
||||||
|
return fromdb;
|
||||||
|
}
|
||||||
|
|
||||||
void _justUpdate() {
|
void _justUpdate() {
|
||||||
setState(() {});
|
setState(() {});
|
||||||
}
|
}
|
||||||
|
@ -238,7 +259,7 @@ class _MainState extends State<MainView> with SingleTickerProviderStateMixin {
|
||||||
TLThingy(
|
TLThingy(
|
||||||
tl: snapshot.data![0].tlSeason1,
|
tl: snapshot.data![0].tlSeason1,
|
||||||
userID: snapshot.data![0].userId),
|
userID: snapshot.data![0].userId),
|
||||||
_TLRecords(userID: snapshot.data![0].userId),
|
_TLRecords(userID: snapshot.data![0].userId, get: getTLMatches,),
|
||||||
_TLHistory(states: snapshot.data![2]),
|
_TLHistory(states: snapshot.data![2]),
|
||||||
_RecordThingy(
|
_RecordThingy(
|
||||||
record: (snapshot.data![1]['sprint'].isNotEmpty)
|
record: (snapshot.data![1]['sprint'].isNotEmpty)
|
||||||
|
@ -380,13 +401,14 @@ class _NavDrawerState extends State<NavDrawer> {
|
||||||
|
|
||||||
class _TLRecords extends StatelessWidget {
|
class _TLRecords extends StatelessWidget {
|
||||||
final String userID;
|
final String userID;
|
||||||
|
final Future<List<TetraLeagueAlphaRecord>> Function(String user) get;
|
||||||
|
|
||||||
const _TLRecords({required this.userID});
|
const _TLRecords({required this.userID, required this.get});
|
||||||
|
|
||||||
@override
|
@override
|
||||||
Widget build(BuildContext context) {
|
Widget build(BuildContext context) {
|
||||||
return FutureBuilder(
|
return FutureBuilder(
|
||||||
future: teto.getTLStream(userID),
|
future: get(userID),
|
||||||
builder: (context, snapshot) {
|
builder: (context, snapshot) {
|
||||||
switch (snapshot.connectionState) {
|
switch (snapshot.connectionState) {
|
||||||
case ConnectionState.none:
|
case ConnectionState.none:
|
||||||
|
@ -400,19 +422,19 @@ class _TLRecords extends StatelessWidget {
|
||||||
} else {
|
} else {
|
||||||
return ListView(
|
return ListView(
|
||||||
physics: const ClampingScrollPhysics(),
|
physics: const ClampingScrollPhysics(),
|
||||||
children: (snapshot.data!.records!.isNotEmpty)
|
children: (snapshot.data!.isNotEmpty)
|
||||||
? [for (var value in snapshot.data!.records!) ListTile(
|
? [for (var value in snapshot.data!) ListTile(
|
||||||
leading: Text("${value.endContext.firstWhere((element) => element.userId == userID).points} : ${value.endContext.firstWhere((element) => element.userId != userID).points}",
|
leading: Text("${value.endContext.firstWhere((element) => element.userId == userID).points} : ${value.endContext.firstWhere((element) => element.userId != userID).points}",
|
||||||
style: const TextStyle(
|
style: const TextStyle(
|
||||||
fontFamily: "Eurostile Round Extended",
|
fontFamily: "Eurostile Round Extended",
|
||||||
fontSize: 28,)),
|
fontSize: 28,)),
|
||||||
title: Text("vs. ${value.endContext.firstWhere((element) => element.userId != userID).username}"),
|
title: Text("vs. ${value.endContext.firstWhere((element) => element.userId != userID).username}"),
|
||||||
subtitle: Text(dateFormat.format(value.timestamp!)),
|
subtitle: Text(dateFormat.format(value.timestamp)),
|
||||||
trailing: Column(mainAxisAlignment: MainAxisAlignment.end,
|
trailing: Column(mainAxisAlignment: MainAxisAlignment.center,
|
||||||
children: [
|
children: [
|
||||||
Text("${f2.format(value.endContext.firstWhere((element) => element.userId == userID).secondary)} : ${f2.format(value.endContext.firstWhere((element) => element.userId != userID).secondary)} APM", style: TextStyle(height: 1.1)),
|
Text("${f2.format(value.endContext.firstWhere((element) => element.userId == userID).secondary)} : ${f2.format(value.endContext.firstWhere((element) => element.userId != userID).secondary)} APM", style: const TextStyle(height: 1.1)),
|
||||||
Text("${f2.format(value.endContext.firstWhere((element) => element.userId == userID).tertiary)} : ${f2.format(value.endContext.firstWhere((element) => element.userId != userID).tertiary)} PPS", style: TextStyle(height: 1.1)),
|
Text("${f2.format(value.endContext.firstWhere((element) => element.userId == userID).tertiary)} : ${f2.format(value.endContext.firstWhere((element) => element.userId != userID).tertiary)} PPS", style: const TextStyle(height: 1.1)),
|
||||||
Text("${f2.format(value.endContext.firstWhere((element) => element.userId == userID).extra)} : ${f2.format(value.endContext.firstWhere((element) => element.userId != userID).extra)} VS", style: TextStyle(height: 1.1)),
|
Text("${f2.format(value.endContext.firstWhere((element) => element.userId == userID).extra)} : ${f2.format(value.endContext.firstWhere((element) => element.userId != userID).extra)} VS", style: const TextStyle(height: 1.1)),
|
||||||
]),
|
]),
|
||||||
onTap: (){Navigator.push(
|
onTap: (){Navigator.push(
|
||||||
context,
|
context,
|
||||||
|
@ -431,23 +453,47 @@ class _TLRecords extends StatelessWidget {
|
||||||
|
|
||||||
class _TLHistory extends StatelessWidget{
|
class _TLHistory extends StatelessWidget{
|
||||||
final List<TetrioPlayer> states;
|
final List<TetrioPlayer> states;
|
||||||
const _TLHistory({super.key, required this.states});
|
const _TLHistory({required this.states});
|
||||||
|
|
||||||
@override
|
@override
|
||||||
Widget build(BuildContext context) {
|
Widget build(BuildContext context) {
|
||||||
bool bigScreen = MediaQuery.of(context).size.width > 768;
|
bool bigScreen = MediaQuery.of(context).size.width > 768;
|
||||||
List<FlSpot> trData = [for (var state in states) FlSpot(state.state.millisecondsSinceEpoch.toDouble(), state.tlSeason1.rating)];
|
List<FlSpot> trData = [for (var state in states) if (state.tlSeason1.gamesPlayed > 9) FlSpot(state.state.millisecondsSinceEpoch.toDouble(), state.tlSeason1.rating)];
|
||||||
List<FlSpot> apmData = [for (var state in states) FlSpot(state.state.millisecondsSinceEpoch.toDouble(), state.tlSeason1.apm!)];
|
List<FlSpot> apmData = [for (var state in states) if (state.tlSeason1.apm != null) FlSpot(state.state.millisecondsSinceEpoch.toDouble(), state.tlSeason1.apm!)];
|
||||||
List<FlSpot> ppsData = [for (var state in states) FlSpot(state.state.millisecondsSinceEpoch.toDouble(), state.tlSeason1.pps!)];
|
List<FlSpot> ppsData = [for (var state in states) if (state.tlSeason1.pps != null) FlSpot(state.state.millisecondsSinceEpoch.toDouble(), state.tlSeason1.pps!)];
|
||||||
List<FlSpot> vsData = [for (var state in states) FlSpot(state.state.millisecondsSinceEpoch.toDouble(), state.tlSeason1.vs!)];
|
List<FlSpot> vsData = [for (var state in states) if (state.tlSeason1.vs != null) FlSpot(state.state.millisecondsSinceEpoch.toDouble(), state.tlSeason1.vs!)];
|
||||||
|
List<FlSpot> appData = [for (var state in states) if (state.tlSeason1.nerdStats != null) FlSpot(state.state.millisecondsSinceEpoch.toDouble(), state.tlSeason1.nerdStats!.app)];
|
||||||
|
List<FlSpot> dssData = [for (var state in states) if (state.tlSeason1.nerdStats != null) FlSpot(state.state.millisecondsSinceEpoch.toDouble(), state.tlSeason1.nerdStats!.dss)];
|
||||||
|
List<FlSpot> dspData = [for (var state in states) if (state.tlSeason1.nerdStats != null) FlSpot(state.state.millisecondsSinceEpoch.toDouble(), state.tlSeason1.nerdStats!.dsp)];
|
||||||
|
List<FlSpot> appdspData = [for (var state in states) if (state.tlSeason1.nerdStats != null) FlSpot(state.state.millisecondsSinceEpoch.toDouble(), state.tlSeason1.nerdStats!.appdsp)];
|
||||||
|
List<FlSpot> vsapmData = [for (var state in states) if (state.tlSeason1.nerdStats != null) FlSpot(state.state.millisecondsSinceEpoch.toDouble(), state.tlSeason1.nerdStats!.vsapm)];
|
||||||
|
List<FlSpot> cheeseData = [for (var state in states) if (state.tlSeason1.nerdStats != null) FlSpot(state.state.millisecondsSinceEpoch.toDouble(), state.tlSeason1.nerdStats!.cheese)];
|
||||||
|
List<FlSpot> gbeData = [for (var state in states) if (state.tlSeason1.nerdStats != null) FlSpot(state.state.millisecondsSinceEpoch.toDouble(), state.tlSeason1.nerdStats!.gbe)];
|
||||||
|
List<FlSpot> nyaappData = [for (var state in states) if (state.tlSeason1.nerdStats != null) FlSpot(state.state.millisecondsSinceEpoch.toDouble(), state.tlSeason1.nerdStats!.nyaapp)];
|
||||||
|
List<FlSpot> areaData = [for (var state in states) if (state.tlSeason1.nerdStats != null) FlSpot(state.state.millisecondsSinceEpoch.toDouble(), state.tlSeason1.nerdStats!.area)];
|
||||||
|
List<FlSpot> estTrData = [for (var state in states) if (state.tlSeason1.estTr != null) FlSpot(state.state.millisecondsSinceEpoch.toDouble(), state.tlSeason1.estTr!.esttr)];
|
||||||
|
List<FlSpot> estaccData = [for (var state in states) if (state.tlSeason1.esttracc != null) FlSpot(state.state.millisecondsSinceEpoch.toDouble(), state.tlSeason1.esttracc!)];
|
||||||
return ListView(physics: const ClampingScrollPhysics(),
|
return ListView(physics: const ClampingScrollPhysics(),
|
||||||
children: states.isNotEmpty ? [
|
children: states.isNotEmpty ? [
|
||||||
Column(
|
Column(
|
||||||
children: [
|
children: [
|
||||||
_HistoryChartThigy(data: trData, title: "Tetra Rating", yAxisTitle: "TR", bigScreen: bigScreen),
|
if(trData.length > 1) _HistoryChartThigy(data: trData, title: "Tetra Rating", yAxisTitle: "TR", bigScreen: bigScreen, leftSpace: bigScreen? 80 : 45, yFormat: bigScreen? f2 : NumberFormat.compact(),),
|
||||||
_HistoryChartThigy(data: apmData, title: "Attack Per Minute", yAxisTitle: "APM", bigScreen: bigScreen),
|
if(apmData.length > 1) _HistoryChartThigy(data: apmData, title: "Attack Per Minute", yAxisTitle: "APM", bigScreen: bigScreen, leftSpace: 40, yFormat: NumberFormat.compact(),),
|
||||||
_HistoryChartThigy(data: ppsData, title: "Pieces Per Second", yAxisTitle: "PPS", bigScreen: bigScreen),
|
if(ppsData.length > 1) _HistoryChartThigy(data: ppsData, title: "Pieces Per Second", yAxisTitle: "PPS", bigScreen: bigScreen, leftSpace: 40, yFormat: NumberFormat.compact(),),
|
||||||
_HistoryChartThigy(data: vsData, title: "Versus Score", yAxisTitle: "VS", bigScreen: bigScreen),
|
if(vsData.length > 1) _HistoryChartThigy(data: vsData, title: "Versus Score", yAxisTitle: "VS", bigScreen: bigScreen, leftSpace: 40, yFormat: NumberFormat.compact(),),
|
||||||
|
if(appData.length > 1) _HistoryChartThigy(data: appData, title: "Attack Per Piece", yAxisTitle: "APP", bigScreen: bigScreen, leftSpace: 48, yFormat: NumberFormat.compact(),),
|
||||||
|
if(dssData.length > 1) _HistoryChartThigy(data: dssData, title: bigScreen ? "Downstack Per Second" : "Downstack\nPer Second", yAxisTitle: "DS/S", bigScreen: bigScreen, leftSpace: 48, yFormat: NumberFormat.compact(),),
|
||||||
|
if(dspData.length > 1) _HistoryChartThigy(data: dspData, title: bigScreen ? "Downstack Per Piece" : "Downstack\nPer Piece", yAxisTitle: "DS/P", bigScreen: bigScreen, leftSpace: 48, yFormat: NumberFormat.compact(),),
|
||||||
|
if(appdspData.length > 1) _HistoryChartThigy(data: appdspData, title: "APP + DS/P", yAxisTitle: "APP + DS/P", bigScreen: bigScreen, leftSpace: 48, yFormat: NumberFormat.compact(),),
|
||||||
|
if(vsapmData.length > 1) _HistoryChartThigy(data: vsapmData, title: "VS/APM", yAxisTitle: "VS/APM", bigScreen: bigScreen, leftSpace: 48, yFormat: NumberFormat.compact(),),
|
||||||
|
if(cheeseData.length > 1) _HistoryChartThigy(data: cheeseData, title: "Cheese Index", yAxisTitle: "Cheese", bigScreen: bigScreen, leftSpace: 40, yFormat: NumberFormat.compact(),),
|
||||||
|
if(gbeData.length > 1) _HistoryChartThigy(data: gbeData, title: "Garbage Efficiency", yAxisTitle: "GbE", bigScreen: bigScreen, leftSpace: 48, yFormat: NumberFormat.compact(),),
|
||||||
|
if(nyaappData.length > 1) _HistoryChartThigy(data: nyaappData, title: "Weighted APP", yAxisTitle: "wAPP", bigScreen: bigScreen, leftSpace: 48, yFormat: NumberFormat.compact(),),
|
||||||
|
if(areaData.length > 1) _HistoryChartThigy(data: areaData, title: "Area", yAxisTitle: "Area", bigScreen: bigScreen, leftSpace: 40, yFormat: NumberFormat.compact(),),
|
||||||
|
if(estTrData.length > 1) _HistoryChartThigy(data: estTrData, title: "Est. of TR", yAxisTitle: "eTR", bigScreen: bigScreen, leftSpace: bigScreen? 80 : 45, yFormat: bigScreen? f2 : NumberFormat.compact(),),
|
||||||
|
if(estaccData.length > 1) _HistoryChartThigy(data: estaccData, title: "Accuracy of Est.", yAxisTitle: "±eTR", bigScreen: bigScreen, leftSpace: 60, yFormat: NumberFormat.compact(explicitSign: true),),
|
||||||
|
if(trData.length <= 1 || apmData.length <= 1 || ppsData.length <= 1 || vsData.length <= 1 || appData.length <= 1 || dssData.length <= 1 || dspData.length <= 1 || appdspData.length <= 1 || vsapmData.length <= 1 || cheeseData.length <= 1 || gbeData.length <= 1 || nyaappData.length <= 1 || areaData.length <= 1 || estTrData.length <= 1 || estaccData.length <= 1) const Center(child: Text("Some charts aren't shown due to lack of data...", style: TextStyle(fontFamily: "Eurostile Round Extended", fontSize: 28)))
|
||||||
|
// Why it's look like a garbage solution???
|
||||||
],
|
],
|
||||||
),
|
),
|
||||||
] : [const Center(child: Text("No history saved", style: TextStyle(fontFamily: "Eurostile Round Extended", fontSize: 28)))]);
|
] : [const Center(child: Text("No history saved", style: TextStyle(fontFamily: "Eurostile Round Extended", fontSize: 28)))]);
|
||||||
|
@ -459,37 +505,40 @@ class _HistoryChartThigy extends StatelessWidget{
|
||||||
final String title;
|
final String title;
|
||||||
final String yAxisTitle;
|
final String yAxisTitle;
|
||||||
final bool bigScreen;
|
final bool bigScreen;
|
||||||
const _HistoryChartThigy({super.key, required this.data, required this.title, required this.yAxisTitle, required this.bigScreen});
|
final double leftSpace;
|
||||||
|
final NumberFormat yFormat;
|
||||||
|
const _HistoryChartThigy({required this.data, required this.title, required this.yAxisTitle, required this.bigScreen, required this.leftSpace, required this.yFormat});
|
||||||
|
|
||||||
@override
|
@override
|
||||||
Widget build(BuildContext context) {
|
Widget build(BuildContext context) {
|
||||||
|
double xInterval = bigScreen ? max(1, (data.last.x - data.first.x) / 6) : max(1, (data.last.x - data.first.x) / 3);
|
||||||
return AspectRatio(
|
return AspectRatio(
|
||||||
aspectRatio: bigScreen ? 1.9 : 1.1,
|
aspectRatio: bigScreen ? 1.9 : 1.1,
|
||||||
child: Stack(
|
child: Stack(
|
||||||
children: [
|
children: [
|
||||||
Row(mainAxisAlignment: MainAxisAlignment.center, children: [Text(title, style: TextStyle(fontFamily: "Eurostile Round Extended", fontSize: 28))]),
|
Row(mainAxisAlignment: MainAxisAlignment.center, children: [Text(title, style: const TextStyle(fontFamily: "Eurostile Round Extended", fontSize: 28))]),
|
||||||
Padding( padding: bigScreen ? const EdgeInsets.fromLTRB(40, 80, 40, 48) : const EdgeInsets.fromLTRB(0, 80, 0, 48) ,
|
Padding( padding: bigScreen ? const EdgeInsets.fromLTRB(40, 75, 40, 48) : const EdgeInsets.fromLTRB(0, 80, 0, 48) ,
|
||||||
child: LineChart(
|
child: LineChart(
|
||||||
LineChartData(
|
LineChartData(
|
||||||
lineBarsData: [LineChartBarData(spots: data)],
|
lineBarsData: [LineChartBarData(spots: data)],
|
||||||
borderData: FlBorderData(show: false),
|
borderData: FlBorderData(show: false),
|
||||||
|
gridData: FlGridData(verticalInterval: xInterval),
|
||||||
titlesData: FlTitlesData(topTitles: AxisTitles(sideTitles: SideTitles(showTitles: false)),
|
titlesData: FlTitlesData(topTitles: AxisTitles(sideTitles: SideTitles(showTitles: false)),
|
||||||
rightTitles: AxisTitles(sideTitles: SideTitles(showTitles: false)),
|
rightTitles: AxisTitles(sideTitles: SideTitles(showTitles: false)),
|
||||||
bottomTitles: AxisTitles(sideTitles: SideTitles(showTitles: true, reservedSize: 30, getTitlesWidget: (double value, TitleMeta meta){
|
bottomTitles: AxisTitles(sideTitles: SideTitles(interval: xInterval, showTitles: true, reservedSize: 30, getTitlesWidget: (double value, TitleMeta meta){
|
||||||
return SideTitleWidget(
|
return value != meta.min && value != meta.max ? SideTitleWidget(
|
||||||
axisSide: meta.axisSide,
|
axisSide: meta.axisSide,
|
||||||
angle: 0.3,
|
|
||||||
child: Text(DateFormat(DateFormat.YEAR_ABBR_MONTH_DAY).format(DateTime.fromMillisecondsSinceEpoch(value.floor()))),
|
child: Text(DateFormat(DateFormat.YEAR_ABBR_MONTH_DAY).format(DateTime.fromMillisecondsSinceEpoch(value.floor()))),
|
||||||
);
|
) : Container();
|
||||||
})),
|
})),
|
||||||
leftTitles: AxisTitles(sideTitles: SideTitles(showTitles: true, reservedSize: 80, getTitlesWidget: (double value, TitleMeta meta){
|
leftTitles: AxisTitles(sideTitles: SideTitles(showTitles: true, reservedSize: leftSpace, getTitlesWidget: (double value, TitleMeta meta){
|
||||||
return SideTitleWidget(
|
return value != meta.min && value != meta.max ? SideTitleWidget(
|
||||||
axisSide: meta.axisSide,
|
axisSide: meta.axisSide,
|
||||||
child: Text(f2.format(value)),
|
child: Text(yFormat.format(value)),
|
||||||
);
|
) : Container();
|
||||||
}))),
|
}))),
|
||||||
lineTouchData: LineTouchData(touchTooltipData: LineTouchTooltipData(getTooltipItems: (touchedSpots) {
|
lineTouchData: LineTouchData(touchTooltipData: LineTouchTooltipData( fitInsideHorizontally: true, fitInsideVertically: true, getTooltipItems: (touchedSpots) {
|
||||||
return [for (var v in touchedSpots) LineTooltipItem("${f2.format(v.y)} $yAxisTitle \n", TextStyle(), children: [TextSpan(text: "${dateFormat.format(DateTime.fromMillisecondsSinceEpoch(v.x.floor()))}")])];
|
return [for (var v in touchedSpots) LineTooltipItem("${f4.format(v.y)} $yAxisTitle \n", const TextStyle(), children: [TextSpan(text: dateFormat.format(DateTime.fromMillisecondsSinceEpoch(v.x.floor())))])];
|
||||||
},))
|
},))
|
||||||
)
|
)
|
||||||
),
|
),
|
||||||
|
|
|
@ -28,7 +28,7 @@ class StatesState extends State<StatesView> {
|
||||||
itemBuilder: (context, index) {
|
itemBuilder: (context, index) {
|
||||||
return ListTile(
|
return ListTile(
|
||||||
title: Text("On ${dateFormat.format(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"),
|
subtitle: Text("Level ${widget.states[index].level.toStringAsFixed(2)}, ${widget.states[index].gameTime} of gametime, ${widget.states[index].friendCount} friends, ${NumberFormat.compact().format(widget.states[index].tlSeason1.rd)} RD"),
|
||||||
trailing: IconButton(
|
trailing: IconButton(
|
||||||
icon: const Icon(Icons.delete_forever),
|
icon: const Icon(Icons.delete_forever),
|
||||||
onPressed: () {
|
onPressed: () {
|
||||||
|
|
|
@ -31,7 +31,7 @@ class TlMatchResultState extends State<TlMatchResultView> {
|
||||||
return Scaffold(
|
return Scaffold(
|
||||||
appBar: AppBar(
|
appBar: AppBar(
|
||||||
title: Text(
|
title: Text(
|
||||||
"${widget.record.endContext.firstWhere((element) => element.userId == widget.initPlayerId).username.toUpperCase()} vs. ${widget.record.endContext.firstWhere((element) => element.userId != widget.initPlayerId).username.toUpperCase()} in TL match ${dateFormat.format(widget.record.timestamp!)}"),
|
"${widget.record.endContext.firstWhere((element) => element.userId == widget.initPlayerId).username.toUpperCase()} vs. ${widget.record.endContext.firstWhere((element) => element.userId != widget.initPlayerId).username.toUpperCase()} in TL match ${dateFormat.format(widget.record.timestamp)}"),
|
||||||
),
|
),
|
||||||
backgroundColor: Colors.black,
|
backgroundColor: Colors.black,
|
||||||
body: SafeArea(
|
body: SafeArea(
|
||||||
|
@ -48,19 +48,19 @@ class TlMatchResultState extends State<TlMatchResultView> {
|
||||||
children: [
|
children: [
|
||||||
Expanded(
|
Expanded(
|
||||||
child: Container(
|
child: Container(
|
||||||
decoration: const BoxDecoration(
|
decoration: BoxDecoration(
|
||||||
gradient: LinearGradient(
|
gradient: LinearGradient(
|
||||||
colors: [Colors.green, Colors.transparent],
|
colors: const [Colors.green, Colors.transparent],
|
||||||
begin: Alignment.bottomCenter,
|
begin: Alignment.bottomCenter,
|
||||||
end: Alignment.topCenter,
|
end: Alignment.topCenter,
|
||||||
stops: [0.0, 0.4],
|
stops: [0.0, widget.record.endContext.firstWhere((element) => element.userId == widget.initPlayerId).success ? 0.4 : 0.0],
|
||||||
)),
|
)),
|
||||||
child: Padding(
|
child: Padding(
|
||||||
padding: const EdgeInsets.fromLTRB(8, 0, 8, 0),
|
padding: const EdgeInsets.fromLTRB(8, 0, 8, 0),
|
||||||
child: Column(children: [
|
child: Column(children: [
|
||||||
Text(widget.record.endContext.firstWhere((element) => element.userId == widget.initPlayerId).username, style: const TextStyle(
|
Text(widget.record.endContext.firstWhere((element) => element.userId == widget.initPlayerId).username, style: bigScreen ? const TextStyle(
|
||||||
fontFamily: "Eurostile Round Extended",
|
fontFamily: "Eurostile Round Extended",
|
||||||
fontSize: 28)),
|
fontSize: 28) : const TextStyle()),
|
||||||
Text(widget.record.endContext.firstWhere((element) => element.userId == widget.initPlayerId).points.toString(), style: const TextStyle(
|
Text(widget.record.endContext.firstWhere((element) => element.userId == widget.initPlayerId).points.toString(), style: const TextStyle(
|
||||||
fontFamily: "Eurostile Round Extended",
|
fontFamily: "Eurostile Round Extended",
|
||||||
fontSize: 42))
|
fontSize: 42))
|
||||||
|
@ -74,19 +74,19 @@ class TlMatchResultState extends State<TlMatchResultView> {
|
||||||
),
|
),
|
||||||
Expanded(
|
Expanded(
|
||||||
child: Container(
|
child: Container(
|
||||||
decoration: const BoxDecoration(
|
decoration: BoxDecoration(
|
||||||
gradient: LinearGradient(
|
gradient: LinearGradient(
|
||||||
colors: [Colors.red, Colors.transparent],
|
colors: const [Colors.red, Colors.transparent],
|
||||||
begin: Alignment.bottomCenter,
|
begin: Alignment.bottomCenter,
|
||||||
end: Alignment.topCenter,
|
end: Alignment.topCenter,
|
||||||
stops: [0.0, 0.4],
|
stops: [0.0, widget.record.endContext.firstWhere((element) => element.userId != widget.initPlayerId).success ? 0.4 : 0.0],
|
||||||
)),
|
)),
|
||||||
child: Padding(
|
child: Padding(
|
||||||
padding: const EdgeInsets.fromLTRB(8, 0, 8, 0),
|
padding: const EdgeInsets.fromLTRB(8, 0, 8, 0),
|
||||||
child: Column(children: [
|
child: Column(children: [
|
||||||
Text(widget.record.endContext.firstWhere((element) => element.userId != widget.initPlayerId).username, style: const TextStyle(
|
Text(widget.record.endContext.firstWhere((element) => element.userId != widget.initPlayerId).username, style: bigScreen ? const TextStyle(
|
||||||
fontFamily: "Eurostile Round Extended",
|
fontFamily: "Eurostile Round Extended",
|
||||||
fontSize: 28)),
|
fontSize: 28) : const TextStyle()),
|
||||||
Text(widget.record.endContext.firstWhere((element) => element.userId != widget.initPlayerId).points.toString(), style: const TextStyle(
|
Text(widget.record.endContext.firstWhere((element) => element.userId != widget.initPlayerId).points.toString(), style: const TextStyle(
|
||||||
fontFamily: "Eurostile Round Extended",
|
fontFamily: "Eurostile Round Extended",
|
||||||
fontSize: 42))
|
fontSize: 42))
|
||||||
|
@ -779,8 +779,9 @@ class CompareRegTimeThingy extends StatelessWidget {
|
||||||
String verdict(DateTime? greenSide, DateTime? redSide) {
|
String verdict(DateTime? greenSide, DateTime? redSide) {
|
||||||
var f = NumberFormat("#,### days later;#,### days before");
|
var f = NumberFormat("#,### days later;#,### days before");
|
||||||
String result = "---";
|
String result = "---";
|
||||||
if (greenSide != null && redSide != null)
|
if (greenSide != null && redSide != null) {
|
||||||
result = f.format(greenSide.difference(redSide).inDays);
|
result = f.format(greenSide.difference(redSide).inDays);
|
||||||
|
}
|
||||||
return result;
|
return result;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -206,7 +206,7 @@ class TLThingy extends StatelessWidget {
|
||||||
RadarEntry(value: tl.nerdStats!.dss * dssWeight),
|
RadarEntry(value: tl.nerdStats!.dss * dssWeight),
|
||||||
RadarEntry(value: tl.nerdStats!.dsp * dspWeight),
|
RadarEntry(value: tl.nerdStats!.dsp * dspWeight),
|
||||||
RadarEntry(value: tl.nerdStats!.appdsp * appdspWeight),
|
RadarEntry(value: tl.nerdStats!.appdsp * appdspWeight),
|
||||||
RadarEntry(value: tl.nerdStats!.vsapm * vsWeight),
|
RadarEntry(value: tl.nerdStats!.vsapm * vsapmWeight),
|
||||||
RadarEntry(value: tl.nerdStats!.cheese * cheeseWeight),
|
RadarEntry(value: tl.nerdStats!.cheese * cheeseWeight),
|
||||||
RadarEntry(value: tl.nerdStats!.gbe * gbeWeight),
|
RadarEntry(value: tl.nerdStats!.gbe * gbeWeight),
|
||||||
],
|
],
|
||||||
|
|
|
@ -48,9 +48,7 @@ class UserThingy extends StatelessWidget {
|
||||||
height: bannerHeight,
|
height: bannerHeight,
|
||||||
errorBuilder: (context, error, stackTrace) {
|
errorBuilder: (context, error, stackTrace) {
|
||||||
developer.log("Error with building banner image", name: "main_view", error: error, stackTrace: stackTrace);
|
developer.log("Error with building banner image", name: "main_view", error: error, stackTrace: stackTrace);
|
||||||
return const Placeholder(
|
return Container();
|
||||||
color: Colors.black,
|
|
||||||
);
|
|
||||||
},
|
},
|
||||||
),
|
),
|
||||||
Container(
|
Container(
|
||||||
|
|
|
@ -85,7 +85,12 @@ flutter:
|
||||||
- res/tetrio_badges/early-supporter.png
|
- res/tetrio_badges/early-supporter.png
|
||||||
- res/tetrio_badges/founder.png
|
- res/tetrio_badges/founder.png
|
||||||
- res/tetrio_badges/galactic2x2_1.png
|
- res/tetrio_badges/galactic2x2_1.png
|
||||||
|
- res/tetrio_badges/ggc_1.png
|
||||||
- res/tetrio_badges/ggc_2.png
|
- res/tetrio_badges/ggc_2.png
|
||||||
|
- res/tetrio_badges/ggc_3.png
|
||||||
|
- res/tetrio_badges/hdoxii_1.png
|
||||||
|
- res/tetrio_badges/hdoxii_2.png
|
||||||
|
- res/tetrio_badges/hdoxii_3.png
|
||||||
- res/tetrio_badges/heart.png
|
- res/tetrio_badges/heart.png
|
||||||
- res/tetrio_badges/hnprism_1.png
|
- res/tetrio_badges/hnprism_1.png
|
||||||
- res/tetrio_badges/hnprism_2.png
|
- res/tetrio_badges/hnprism_2.png
|
||||||
|
|
Binary file not shown.
After Width: | Height: | Size: 8.0 KiB |
Binary file not shown.
After Width: | Height: | Size: 6.2 KiB |
Binary file not shown.
After Width: | Height: | Size: 6.2 KiB |
Binary file not shown.
After Width: | Height: | Size: 4.9 KiB |
Binary file not shown.
After Width: | Height: | Size: 4.9 KiB |
Loading…
Reference in New Issue