details for singleplayer records
also very small refactoring (I will redo Tetra Stats from the ground one day...)
This commit is contained in:
parent
7bd0d6ecd4
commit
0f90358160
|
@ -11,3 +11,10 @@ final NumberFormat f2l = NumberFormat.decimalPatternDigits(locale: LocaleSetting
|
||||||
final NumberFormat f1 = NumberFormat.decimalPatternDigits(locale: LocaleSettings.currentLocale.languageCode, decimalDigits: 1);
|
final NumberFormat f1 = NumberFormat.decimalPatternDigits(locale: LocaleSettings.currentLocale.languageCode, decimalDigits: 1);
|
||||||
final NumberFormat f0 = NumberFormat.decimalPattern(LocaleSettings.currentLocale.languageCode);
|
final NumberFormat f0 = NumberFormat.decimalPattern(LocaleSettings.currentLocale.languageCode);
|
||||||
final NumberFormat percentage = NumberFormat.percentPattern(LocaleSettings.currentLocale.languageCode)..maximumFractionDigits = 2;
|
final NumberFormat percentage = NumberFormat.percentPattern(LocaleSettings.currentLocale.languageCode)..maximumFractionDigits = 2;
|
||||||
|
|
||||||
|
/// Readable [a] - [b], without sign
|
||||||
|
String readableIntDifference(int a, int b){
|
||||||
|
int result = a - b;
|
||||||
|
|
||||||
|
return NumberFormat("#,###;#,###", LocaleSettings.currentLocale.languageCode).format(result);
|
||||||
|
}
|
|
@ -1,5 +1,10 @@
|
||||||
|
import 'package:intl/intl.dart';
|
||||||
|
import 'package:tetra_stats/gen/strings.g.dart';
|
||||||
import 'package:tetra_stats/utils/numers_formats.dart';
|
import 'package:tetra_stats/utils/numers_formats.dart';
|
||||||
|
|
||||||
|
final NumberFormat secs = NumberFormat("00.###", LocaleSettings.currentLocale.languageCode);
|
||||||
|
final NumberFormat _timeInSec = NumberFormat("#,###.###s.", LocaleSettings.currentLocale.languageCode);
|
||||||
|
|
||||||
/// Returns string, that represents time difference between [dateTime] and now
|
/// Returns string, that represents time difference between [dateTime] and now
|
||||||
String relativeDateTime(DateTime dateTime){
|
String relativeDateTime(DateTime dateTime){
|
||||||
Duration difference = dateTime.difference(DateTime.now());
|
Duration difference = dateTime.difference(DateTime.now());
|
||||||
|
@ -57,3 +62,15 @@ String relativeDateTime(DateTime dateTime){
|
||||||
return inPast ? "${f1.format(timeInterval)} seconds ago" : "in ${f1.format(timeInterval)} seconds";
|
return inPast ? "${f1.format(timeInterval)} seconds ago" : "in ${f1.format(timeInterval)} seconds";
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// Takes number of [microseconds] and returns readable 40 lines time
|
||||||
|
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);
|
||||||
|
}
|
|
@ -17,12 +17,16 @@ import 'package:tetra_stats/gen/strings.g.dart';
|
||||||
import 'package:tetra_stats/main.dart' show prefs, teto;
|
import 'package:tetra_stats/main.dart' show prefs, teto;
|
||||||
import 'package:tetra_stats/services/crud_exceptions.dart';
|
import 'package:tetra_stats/services/crud_exceptions.dart';
|
||||||
import 'package:tetra_stats/utils/numers_formats.dart';
|
import 'package:tetra_stats/utils/numers_formats.dart';
|
||||||
|
import 'package:tetra_stats/utils/relative_timestamps.dart';
|
||||||
import 'package:tetra_stats/utils/text_shadow.dart';
|
import 'package:tetra_stats/utils/text_shadow.dart';
|
||||||
|
import 'package:tetra_stats/views/singleplayer_record_view.dart';
|
||||||
import 'package:tetra_stats/views/tl_match_view.dart' show TlMatchResultView;
|
import 'package:tetra_stats/views/tl_match_view.dart' show TlMatchResultView;
|
||||||
import 'package:tetra_stats/widgets/finesse_thingy.dart';
|
import 'package:tetra_stats/widgets/finesse_thingy.dart';
|
||||||
import 'package:tetra_stats/widgets/lineclears_thingy.dart';
|
import 'package:tetra_stats/widgets/lineclears_thingy.dart';
|
||||||
import 'package:tetra_stats/widgets/list_tile_trailing_stats.dart';
|
import 'package:tetra_stats/widgets/list_tile_trailing_stats.dart';
|
||||||
|
import 'package:tetra_stats/widgets/recent_sp_games.dart';
|
||||||
import 'package:tetra_stats/widgets/search_box.dart';
|
import 'package:tetra_stats/widgets/search_box.dart';
|
||||||
|
import 'package:tetra_stats/widgets/singleplayer_record.dart';
|
||||||
import 'package:tetra_stats/widgets/sp_trailing_stats.dart';
|
import 'package:tetra_stats/widgets/sp_trailing_stats.dart';
|
||||||
import 'package:tetra_stats/widgets/stat_sell_num.dart';
|
import 'package:tetra_stats/widgets/stat_sell_num.dart';
|
||||||
import 'package:tetra_stats/widgets/text_timestamp.dart';
|
import 'package:tetra_stats/widgets/text_timestamp.dart';
|
||||||
|
@ -38,9 +42,6 @@ late ZoomPanBehavior _zoomPanBehavior;
|
||||||
bool _smooth = false;
|
bool _smooth = false;
|
||||||
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"];
|
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;
|
late ScrollController _scrollController;
|
||||||
final NumberFormat _timeInSec = NumberFormat("#,###.###s.", LocaleSettings.currentLocale.languageCode);
|
|
||||||
final NumberFormat secs = NumberFormat("00.###", LocaleSettings.currentLocale.languageCode);
|
|
||||||
|
|
||||||
|
|
||||||
class MainView extends StatefulWidget {
|
class MainView extends StatefulWidget {
|
||||||
final String? player;
|
final String? player;
|
||||||
|
@ -57,25 +58,6 @@ Future<void> copyToClipboard(String text) async {
|
||||||
await Clipboard.setData(ClipboardData(text: text));
|
await Clipboard.setData(ClipboardData(text: text));
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Takes number of [microseconds] and returns readable 40 lines time
|
|
||||||
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 {
|
class _MainState extends State<MainView> with TickerProviderStateMixin {
|
||||||
Future<List> me = Future.delayed(const Duration(seconds: 60), () => [null, null, null, null, null, null]); // I love lists shut up
|
Future<List> me = Future.delayed(const Duration(seconds: 60), () => [null, null, null, null, null, null]); // I love lists shut up
|
||||||
TetrioPlayersLeaderboard? everyone;
|
TetrioPlayersLeaderboard? everyone;
|
||||||
|
@ -103,7 +85,7 @@ class _MainState extends State<MainView> with TickerProviderStateMixin {
|
||||||
void initState() {
|
void initState() {
|
||||||
initDB();
|
initDB();
|
||||||
_scrollController = ScrollController();
|
_scrollController = ScrollController();
|
||||||
_tabController = TabController(length: 6, vsync: this);
|
_tabController = TabController(length: 7, vsync: this);
|
||||||
_wideScreenTabController = TabController(length: 4, vsync: this);
|
_wideScreenTabController = TabController(length: 4, vsync: this);
|
||||||
_zoomPanBehavior = ZoomPanBehavior(
|
_zoomPanBehavior = ZoomPanBehavior(
|
||||||
enablePinching: true,
|
enablePinching: true,
|
||||||
|
@ -455,6 +437,7 @@ class _MainState extends State<MainView> with TickerProviderStateMixin {
|
||||||
Tab(text: t.history),
|
Tab(text: t.history),
|
||||||
Tab(text: t.sprint),
|
Tab(text: t.sprint),
|
||||||
Tab(text: t.blitz),
|
Tab(text: t.blitz),
|
||||||
|
Tab(text: "Recent runs"),
|
||||||
Tab(text: t.other),
|
Tab(text: t.other),
|
||||||
],
|
],
|
||||||
),
|
),
|
||||||
|
@ -514,8 +497,9 @@ class _MainState extends State<MainView> with TickerProviderStateMixin {
|
||||||
),
|
),
|
||||||
_TLRecords(userID: snapshot.data![0].userId, changePlayer: changePlayer, data: snapshot.data![3], wasActiveInTL: snapshot.data![0].tlSeason1.gamesPlayed > 0, oldMathcesHere: _TLHistoryWasFetched),
|
_TLRecords(userID: snapshot.data![0].userId, changePlayer: changePlayer, data: snapshot.data![3], wasActiveInTL: snapshot.data![0].tlSeason1.gamesPlayed > 0, oldMathcesHere: _TLHistoryWasFetched),
|
||||||
_History(chartsData: chartsData, changePlayer: changePlayer, userID: _searchFor, update: _justUpdate, wasActiveInTL: snapshot.data![0].tlSeason1.gamesPlayed > 0),
|
_History(chartsData: chartsData, changePlayer: changePlayer, userID: _searchFor, update: _justUpdate, wasActiveInTL: snapshot.data![0].tlSeason1.gamesPlayed > 0),
|
||||||
_RecordThingy(record: snapshot.data![1].sprint, rank: snapshot.data![0].tlSeason1.percentileRank, stream: snapshot.data![9]),
|
SingleplayerRecord(record: snapshot.data![1].sprint, rank: snapshot.data![0].tlSeason1.percentileRank, stream: snapshot.data![9]),
|
||||||
_RecordThingy(record: snapshot.data![1].blitz, rank: snapshot.data![0].tlSeason1.percentileRank, stream: snapshot.data![10]),
|
SingleplayerRecord(record: snapshot.data![1].blitz, rank: snapshot.data![0].tlSeason1.percentileRank, stream: snapshot.data![10]),
|
||||||
|
_RecentSingleplayersThingy(snapshot.data![8]),
|
||||||
_OtherThingy(zen: snapshot.data![1].zen, bio: snapshot.data![0].bio, distinguishment: snapshot.data![0].distinguishment, newsletter: snapshot.data![6])
|
_OtherThingy(zen: snapshot.data![1].zen, bio: snapshot.data![0].bio, distinguishment: snapshot.data![0].distinguishment, newsletter: snapshot.data![6])
|
||||||
],
|
],
|
||||||
),
|
),
|
||||||
|
@ -1106,9 +1090,7 @@ class _TwoRecordsThingy extends StatelessWidget {
|
||||||
mainAxisSize: MainAxisSize.min,
|
mainAxisSize: MainAxisSize.min,
|
||||||
children: [
|
children: [
|
||||||
for (int i = 1; i < sprintStream.records.length; i++) ListTile(
|
for (int i = 1; i < sprintStream.records.length; i++) ListTile(
|
||||||
onTap: () {
|
onTap: () => Navigator.push(context, MaterialPageRoute(builder: (context) => SingleplayerRecordView(record: sprintStream.records[i]))),
|
||||||
print("lox");
|
|
||||||
},
|
|
||||||
leading: Text("#${i+1}", style: const TextStyle(fontFamily: "Eurostile Round", fontSize: 28, shadows: textShadow, height: 0.9) ),
|
leading: Text("#${i+1}", style: const TextStyle(fontFamily: "Eurostile Round", fontSize: 28, shadows: textShadow, height: 0.9) ),
|
||||||
title: Text(get40lTime(sprintStream.records[i].endContext.finalTime.inMicroseconds),
|
title: Text(get40lTime(sprintStream.records[i].endContext.finalTime.inMicroseconds),
|
||||||
style: TextStyle(fontSize: 18)),
|
style: TextStyle(fontSize: 18)),
|
||||||
|
@ -1185,9 +1167,7 @@ class _TwoRecordsThingy extends StatelessWidget {
|
||||||
mainAxisSize: MainAxisSize.min,
|
mainAxisSize: MainAxisSize.min,
|
||||||
children: [
|
children: [
|
||||||
for (int i = 1; i < sprintStream.records.length; i++) ListTile(
|
for (int i = 1; i < sprintStream.records.length; i++) ListTile(
|
||||||
onTap: () {
|
onTap: () => Navigator.push(context, MaterialPageRoute(builder: (context) => SingleplayerRecordView(record: blitzStream.records[i]))),
|
||||||
print("lox");
|
|
||||||
},
|
|
||||||
leading: Text("#${i+1}", style: const TextStyle(fontFamily: "Eurostile Round", fontSize: 28, shadows: textShadow, height: 0.9) ),
|
leading: Text("#${i+1}", style: const TextStyle(fontFamily: "Eurostile Round", fontSize: 28, shadows: textShadow, height: 0.9) ),
|
||||||
title: Text("${NumberFormat.decimalPattern().format(blitzStream.records[i].endContext.score)} points",
|
title: Text("${NumberFormat.decimalPattern().format(blitzStream.records[i].endContext.score)} points",
|
||||||
style: TextStyle(fontSize: 18)),
|
style: TextStyle(fontSize: 18)),
|
||||||
|
@ -1201,180 +1181,25 @@ class _TwoRecordsThingy extends StatelessWidget {
|
||||||
),
|
),
|
||||||
SizedBox(
|
SizedBox(
|
||||||
width: 400,
|
width: 400,
|
||||||
child: Column(
|
child: RecentSingleplayerGames(recent: recent),
|
||||||
children: [
|
|
||||||
Padding(
|
|
||||||
padding: const EdgeInsets.only(bottom: 8.0),
|
|
||||||
child: Text("Recent", style: const TextStyle(height: 0.1, fontFamily: "Eurostile Round Extended", fontSize: 18)),
|
|
||||||
),
|
|
||||||
for(RecordSingle record in recent.records) ListTile(
|
|
||||||
onTap: () {
|
|
||||||
print("lox");
|
|
||||||
},
|
|
||||||
leading: Text(
|
|
||||||
switch (record.endContext.gameType){
|
|
||||||
"40l" => "40L",
|
|
||||||
"blitz" => "BLZ",
|
|
||||||
"5mblast" => "5MB",
|
|
||||||
String() => "huh",
|
|
||||||
},
|
|
||||||
style: const TextStyle(fontFamily: "Eurostile Round", fontSize: 28, shadows: textShadow, height: 0.9)
|
|
||||||
),
|
|
||||||
title: Text(
|
|
||||||
switch (record.endContext.gameType){
|
|
||||||
"40l" => get40lTime(record.endContext.finalTime.inMicroseconds),
|
|
||||||
"blitz" => "${NumberFormat.decimalPattern().format(record.endContext.score)} points",
|
|
||||||
"5mblast" => get40lTime(record.endContext.finalTime.inMicroseconds),
|
|
||||||
String() => "huh",
|
|
||||||
},
|
|
||||||
style: TextStyle(fontSize: 18)),
|
|
||||||
subtitle: Text(timestamp(record.timestamp), style: TextStyle(color: Colors.grey, height: 0.85)),
|
|
||||||
trailing: SpTrailingStats(record.endContext)
|
|
||||||
)
|
|
||||||
],
|
|
||||||
),
|
|
||||||
)
|
)
|
||||||
]),
|
]),
|
||||||
));
|
));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
class _RecordThingy extends StatelessWidget {
|
class _RecentSingleplayersThingy extends StatelessWidget {
|
||||||
final RecordSingle? record;
|
final SingleplayerStream recent;
|
||||||
final SingleplayerStream stream;
|
|
||||||
final String? rank;
|
|
||||||
|
|
||||||
/// Widget that displays data from [record]
|
const _RecentSingleplayersThingy(this.recent);
|
||||||
const _RecordThingy({required this.record, required this.stream, this.rank});
|
|
||||||
|
|
||||||
Color getColorOfRank(int rank){
|
|
||||||
if (rank == 1) return Colors.yellowAccent;
|
|
||||||
if (rank == 2) return Colors.blueGrey;
|
|
||||||
if (rank == 3) return Colors.brown[400]!;
|
|
||||||
if (rank <= 9) return Colors.blueAccent;
|
|
||||||
if (rank <= 99) return Colors.greenAccent;
|
|
||||||
return Colors.grey;
|
|
||||||
}
|
|
||||||
|
|
||||||
@override
|
@override
|
||||||
Widget build(BuildContext context) {
|
Widget build(BuildContext context) {
|
||||||
if (record == null) return Center(child: Text(t.noRecord, textAlign: TextAlign.center, style: const TextStyle(fontFamily: "Eurostile Round", fontSize: 28)));
|
return SingleChildScrollView(
|
||||||
late MapEntry closestAverageBlitz;
|
child: RecentSingleplayerGames(recent: recent, hideTitle: true)
|
||||||
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!.endContext.gameType == "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!.endContext.gameType == "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 SingleChildScrollView(
|
|
||||||
controller: _scrollController,
|
|
||||||
child: Padding(
|
|
||||||
padding: const EdgeInsets.only(top: 8.0),
|
|
||||||
child: Column(
|
|
||||||
mainAxisAlignment: MainAxisAlignment.start,
|
|
||||||
children: [
|
|
||||||
Row(
|
|
||||||
mainAxisSize: MainAxisSize.min,
|
|
||||||
children: [
|
|
||||||
if (record!.endContext.gameType == "40l") Padding(padding: const EdgeInsets.only(right: 8.0),
|
|
||||||
child: Image.asset("res/tetrio_tl_alpha_ranks/${closestAverageSprint.key}.png", height: 96)
|
|
||||||
),
|
|
||||||
if (record!.endContext.gameType == "blitz") Padding(padding: const EdgeInsets.only(right: 8.0),
|
|
||||||
child: Image.asset("res/tetrio_tl_alpha_ranks/${closestAverageBlitz.key}.png", height: 96)
|
|
||||||
),
|
|
||||||
Column(
|
|
||||||
crossAxisAlignment: CrossAxisAlignment.start,
|
|
||||||
children: [
|
|
||||||
if (record!.endContext.gameType == "40l") Text(t.sprint, style: const TextStyle(height: 0.1, fontFamily: "Eurostile Round Extended", fontSize: 18)),
|
|
||||||
if (record!.endContext.gameType == "blitz") Text(t.blitz, style: const TextStyle(height: 0.1, fontFamily: "Eurostile Round Extended", fontSize: 18)),
|
|
||||||
RichText(text: TextSpan(
|
|
||||||
text: record!.endContext.gameType == "40l" ? get40lTime(record!.endContext.finalTime.inMicroseconds) : NumberFormat.decimalPattern().format(record!.endContext.score),
|
|
||||||
style: TextStyle(fontFamily: "Eurostile Round Extended", fontSize: bigScreen ? 36 : 32, fontWeight: FontWeight.w500, color: Colors.white),
|
|
||||||
),
|
|
||||||
),
|
|
||||||
RichText(text: TextSpan(
|
|
||||||
text: "",
|
|
||||||
style: const TextStyle(fontFamily: "Eurostile Round", fontSize: 14, color: Colors.grey),
|
|
||||||
children: [
|
|
||||||
if (record!.endContext.gameType == "40l" && (rank != null && rank != "z")) TextSpan(text: "${t.verdictGeneral(n: readableTimeDifference(record!.endContext.finalTime, sprintAverages[rank]!), verdict: sprintBetterThanRankAverage??false ? t.verdictBetter : t.verdictWorse, rank: rank!.toUpperCase())}\n", style: TextStyle(
|
|
||||||
color: sprintBetterThanRankAverage??false ? Colors.greenAccent : Colors.redAccent
|
|
||||||
))
|
|
||||||
else if (record!.endContext.gameType == "40l" && (rank == null || rank == "z")) TextSpan(text: "${t.verdictGeneral(n: readableTimeDifference(record!.endContext.finalTime, closestAverageSprint.value), verdict: sprintBetterThanClosestAverage ? t.verdictBetter : t.verdictWorse, rank: closestAverageSprint.key.toUpperCase())}\n", style: TextStyle(
|
|
||||||
color: sprintBetterThanClosestAverage ? Colors.greenAccent : Colors.redAccent
|
|
||||||
))
|
|
||||||
else if (record!.endContext.gameType == "blitz" && (rank != null && rank != "z")) TextSpan(text: "${t.verdictGeneral(n: readableIntDifference(record!.endContext.score, blitzAverages[rank]!), verdict: blitzBetterThanRankAverage??false ? t.verdictBetter : t.verdictWorse, rank: rank!.toUpperCase())}\n", style: TextStyle(
|
|
||||||
color: blitzBetterThanRankAverage??false ? Colors.greenAccent : Colors.redAccent
|
|
||||||
))
|
|
||||||
else if (record!.endContext.gameType == "blitz" && (rank == null || rank == "z")) TextSpan(text: "${t.verdictGeneral(n: readableIntDifference(record!.endContext.score, closestAverageBlitz.value), verdict: blitzBetterThanClosestAverage ? t.verdictBetter : t.verdictWorse, rank: closestAverageBlitz.key.toUpperCase())}\n", style: TextStyle(
|
|
||||||
color: blitzBetterThanClosestAverage ? Colors.greenAccent : Colors.redAccent
|
|
||||||
)),
|
|
||||||
if (record!.rank != null) TextSpan(text: "№${record!.rank}", style: TextStyle(color: getColorOfRank(record!.rank!))),
|
|
||||||
if (record!.rank != null) const TextSpan(text: " • "),
|
|
||||||
TextSpan(text: timestamp(record!.timestamp)),
|
|
||||||
]
|
|
||||||
),
|
|
||||||
)
|
|
||||||
],),
|
|
||||||
],
|
|
||||||
),
|
|
||||||
if (record!.endContext.gameType == "40l") Wrap(
|
|
||||||
alignment: WrapAlignment.spaceBetween,
|
|
||||||
spacing: 20,
|
|
||||||
children: [
|
|
||||||
StatCellNum(playerStat: record!.endContext.piecesPlaced, playerStatLabel: t.statCellNum.pieces, isScreenBig: bigScreen, higherIsBetter: true, smallDecimal: false),
|
|
||||||
StatCellNum(playerStat: record!.endContext.pps, playerStatLabel: t.statCellNum.pps, fractionDigits: 2, isScreenBig: bigScreen, higherIsBetter: true, smallDecimal: false),
|
|
||||||
StatCellNum(playerStat: record!.endContext.kpp, playerStatLabel: t.statCellNum.kpp, fractionDigits: 2, isScreenBig: bigScreen, higherIsBetter: true, smallDecimal: false),
|
|
||||||
],
|
|
||||||
),
|
|
||||||
if (record!.endContext.gameType == "blitz") Wrap(
|
|
||||||
alignment: WrapAlignment.spaceBetween,
|
|
||||||
crossAxisAlignment: WrapCrossAlignment.start,
|
|
||||||
spacing: 20,
|
|
||||||
children: [
|
|
||||||
StatCellNum(playerStat: record!.endContext.level, playerStatLabel: t.statCellNum.level, isScreenBig: bigScreen, higherIsBetter: true, smallDecimal: false),
|
|
||||||
StatCellNum(playerStat: record!.endContext.pps, playerStatLabel: t.statCellNum.pps, fractionDigits: 2, isScreenBig: bigScreen, higherIsBetter: true, smallDecimal: false),
|
|
||||||
StatCellNum(playerStat: record!.endContext.spp, playerStatLabel: t.statCellNum.spp, fractionDigits: 2, isScreenBig: bigScreen, higherIsBetter: true)
|
|
||||||
],
|
|
||||||
),
|
|
||||||
FinesseThingy(record?.endContext.finesse, record?.endContext.finessePercentage),
|
|
||||||
LineclearsThingy(record!.endContext.clears, record!.endContext.lines, record!.endContext.holds, record!.endContext.tSpins),
|
|
||||||
if (record!.endContext.gameType == "40l") Text("${record!.endContext.inputs} KP • ${f2.format(record!.endContext.kps)} KPS"),
|
|
||||||
if (record!.endContext.gameType == "blitz") Text("${record!.endContext.piecesPlaced} P • ${record!.endContext.inputs} KP • ${f2.format(record!.endContext.kpp)} KPP • ${f2.format(record!.endContext.kps)} KPS"),
|
|
||||||
if (stream.records.length > 1) for(int i = 1; i < stream.records.length; i++) ListTile(
|
|
||||||
onTap: () {
|
|
||||||
print("lox");
|
|
||||||
},
|
|
||||||
leading: Text("#${i+1}",
|
|
||||||
style: const TextStyle(fontFamily: "Eurostile Round", fontSize: 28, shadows: textShadow, height: 0.9)
|
|
||||||
),
|
|
||||||
title: Text(
|
|
||||||
switch (stream.records[i].endContext.gameType){
|
|
||||||
"40l" => get40lTime(stream.records[i].endContext.finalTime.inMicroseconds),
|
|
||||||
"blitz" => "${NumberFormat.decimalPattern().format(stream.records[i].endContext.score)} points",
|
|
||||||
"5mblast" => get40lTime(stream.records[i].endContext.finalTime.inMicroseconds),
|
|
||||||
String() => "huh",
|
|
||||||
},
|
|
||||||
style: TextStyle(fontSize: 18)),
|
|
||||||
subtitle: Text(timestamp(stream.records[i].timestamp), style: TextStyle(color: Colors.grey, height: 0.85)),
|
|
||||||
trailing: SpTrailingStats(stream.records[i].endContext)
|
|
||||||
)
|
|
||||||
]
|
|
||||||
),
|
|
||||||
),
|
|
||||||
);
|
|
||||||
}
|
|
||||||
);
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
class _OtherThingy extends StatelessWidget {
|
class _OtherThingy extends StatelessWidget {
|
||||||
|
|
|
@ -0,0 +1,45 @@
|
||||||
|
import 'package:flutter/material.dart';
|
||||||
|
import 'package:tetra_stats/data_objects/tetrio.dart';
|
||||||
|
import 'package:tetra_stats/gen/strings.g.dart';
|
||||||
|
import 'package:tetra_stats/widgets/singleplayer_record.dart';
|
||||||
|
import 'package:tetra_stats/widgets/text_timestamp.dart';
|
||||||
|
|
||||||
|
class SingleplayerRecordView extends StatelessWidget {
|
||||||
|
final RecordSingle record;
|
||||||
|
|
||||||
|
const SingleplayerRecordView({super.key, required this.record});
|
||||||
|
|
||||||
|
@override
|
||||||
|
Widget build(BuildContext context) {
|
||||||
|
final t = Translations.of(context);
|
||||||
|
//bool bigScreen = MediaQuery.of(context).size.width >= 368;
|
||||||
|
return Scaffold(
|
||||||
|
backgroundColor: Colors.black,
|
||||||
|
appBar: AppBar(
|
||||||
|
title: Text("${
|
||||||
|
switch (record.endContext.gameType){
|
||||||
|
"40l" => t.sprint,
|
||||||
|
"blitz" => t.blitz,
|
||||||
|
String() => "5000000 Blast",
|
||||||
|
}
|
||||||
|
} ${timestamp(record.timestamp)}"),
|
||||||
|
),
|
||||||
|
body: SafeArea(
|
||||||
|
child: SingleChildScrollView(
|
||||||
|
child: Row(
|
||||||
|
crossAxisAlignment: CrossAxisAlignment.center,
|
||||||
|
mainAxisAlignment: MainAxisAlignment.center,
|
||||||
|
children: [
|
||||||
|
Column(
|
||||||
|
children: [
|
||||||
|
SingleplayerRecord(record: record, hideTitle: true),
|
||||||
|
]
|
||||||
|
)
|
||||||
|
],
|
||||||
|
)
|
||||||
|
)
|
||||||
|
),
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
|
@ -1,12 +1,11 @@
|
||||||
import 'dart:io';
|
import 'dart:io';
|
||||||
import 'dart:ui';
|
|
||||||
import 'package:flutter/foundation.dart';
|
import 'package:flutter/foundation.dart';
|
||||||
import 'package:flutter/material.dart';
|
import 'package:flutter/material.dart';
|
||||||
import 'package:intl/intl.dart';
|
import 'package:intl/intl.dart';
|
||||||
import 'package:tetra_stats/data_objects/tetrio.dart';
|
import 'package:tetra_stats/data_objects/tetrio.dart';
|
||||||
import 'package:tetra_stats/gen/strings.g.dart';
|
import 'package:tetra_stats/gen/strings.g.dart';
|
||||||
|
import 'package:tetra_stats/utils/relative_timestamps.dart';
|
||||||
import 'package:tetra_stats/utils/text_shadow.dart';
|
import 'package:tetra_stats/utils/text_shadow.dart';
|
||||||
import 'package:tetra_stats/views/main_view.dart';
|
|
||||||
import 'package:window_manager/window_manager.dart';
|
import 'package:window_manager/window_manager.dart';
|
||||||
|
|
||||||
late String oldWindowTitle;
|
late String oldWindowTitle;
|
||||||
|
|
|
@ -3,11 +3,11 @@
|
||||||
import 'dart:io';
|
import 'dart:io';
|
||||||
import 'package:tetra_stats/data_objects/tetrio_multiplayer_replay.dart';
|
import 'package:tetra_stats/data_objects/tetrio_multiplayer_replay.dart';
|
||||||
import 'package:tetra_stats/services/crud_exceptions.dart';
|
import 'package:tetra_stats/services/crud_exceptions.dart';
|
||||||
|
import 'package:tetra_stats/utils/relative_timestamps.dart';
|
||||||
import 'package:tetra_stats/views/compare_view.dart' show CompareThingy, CompareBoolThingy;
|
import 'package:tetra_stats/views/compare_view.dart' show CompareThingy, CompareBoolThingy;
|
||||||
import 'package:tetra_stats/widgets/list_tile_trailing_stats.dart';
|
import 'package:tetra_stats/widgets/list_tile_trailing_stats.dart';
|
||||||
import 'package:tetra_stats/widgets/text_timestamp.dart';
|
import 'package:tetra_stats/widgets/text_timestamp.dart';
|
||||||
import 'package:tetra_stats/widgets/vs_graphs.dart';
|
import 'package:tetra_stats/widgets/vs_graphs.dart';
|
||||||
import 'main_view.dart' show secs;
|
|
||||||
import 'package:tetra_stats/main.dart' show teto;
|
import 'package:tetra_stats/main.dart' show teto;
|
||||||
import 'package:flutter/foundation.dart';
|
import 'package:flutter/foundation.dart';
|
||||||
import 'package:flutter/material.dart';
|
import 'package:flutter/material.dart';
|
||||||
|
|
|
@ -0,0 +1,51 @@
|
||||||
|
import 'package:flutter/material.dart';
|
||||||
|
import 'package:intl/intl.dart';
|
||||||
|
import 'package:tetra_stats/data_objects/tetrio.dart';
|
||||||
|
import 'package:tetra_stats/gen/strings.g.dart';
|
||||||
|
import 'package:tetra_stats/utils/relative_timestamps.dart';
|
||||||
|
import 'package:tetra_stats/utils/text_shadow.dart';
|
||||||
|
import 'package:tetra_stats/views/singleplayer_record_view.dart';
|
||||||
|
import 'package:tetra_stats/widgets/singleplayer_record.dart';
|
||||||
|
import 'package:tetra_stats/widgets/sp_trailing_stats.dart';
|
||||||
|
import 'package:tetra_stats/widgets/text_timestamp.dart';
|
||||||
|
|
||||||
|
class RecentSingleplayerGames extends StatelessWidget{
|
||||||
|
final SingleplayerStream recent;
|
||||||
|
final bool hideTitle;
|
||||||
|
|
||||||
|
const RecentSingleplayerGames({required this.recent, this.hideTitle = false, super.key});
|
||||||
|
|
||||||
|
@override
|
||||||
|
Widget build(BuildContext context) {
|
||||||
|
return Column(
|
||||||
|
children: [
|
||||||
|
if (!hideTitle) const Padding(
|
||||||
|
padding: EdgeInsets.only(bottom: 8.0),
|
||||||
|
child: Text("Recent", style: TextStyle(height: 0.1, fontFamily: "Eurostile Round Extended", fontSize: 18)),
|
||||||
|
),
|
||||||
|
for(RecordSingle record in recent.records) ListTile(
|
||||||
|
onTap: () => Navigator.push(context, MaterialPageRoute(builder: (context) => SingleplayerRecordView(record: record))),
|
||||||
|
leading: Text(
|
||||||
|
switch (record.endContext.gameType){
|
||||||
|
"40l" => "40L",
|
||||||
|
"blitz" => "BLZ",
|
||||||
|
"5mblast" => "5MB",
|
||||||
|
String() => "huh",
|
||||||
|
},
|
||||||
|
style: const TextStyle(fontFamily: "Eurostile Round", fontSize: 28, shadows: textShadow, height: 0.9)
|
||||||
|
),
|
||||||
|
title: Text(
|
||||||
|
switch (record.endContext.gameType){
|
||||||
|
"40l" => get40lTime(record.endContext.finalTime.inMicroseconds),
|
||||||
|
"blitz" => "${NumberFormat.decimalPattern().format(record.endContext.score)} points",
|
||||||
|
"5mblast" => get40lTime(record.endContext.finalTime.inMicroseconds),
|
||||||
|
String() => "huh",
|
||||||
|
},
|
||||||
|
style: const TextStyle(fontSize: 18)),
|
||||||
|
subtitle: Text(timestamp(record.timestamp), style: TextStyle(color: Colors.grey, height: 0.85)),
|
||||||
|
trailing: SpTrailingStats(record.endContext)
|
||||||
|
)
|
||||||
|
],
|
||||||
|
);
|
||||||
|
}
|
||||||
|
}
|
|
@ -0,0 +1,151 @@
|
||||||
|
import 'package:flutter/material.dart';
|
||||||
|
import 'package:intl/intl.dart';
|
||||||
|
import 'package:tetra_stats/data_objects/tetrio.dart';
|
||||||
|
import 'package:tetra_stats/gen/strings.g.dart';
|
||||||
|
import 'package:tetra_stats/utils/numers_formats.dart';
|
||||||
|
import 'package:tetra_stats/utils/relative_timestamps.dart';
|
||||||
|
import 'package:tetra_stats/utils/text_shadow.dart';
|
||||||
|
import 'package:tetra_stats/views/singleplayer_record_view.dart';
|
||||||
|
import 'package:tetra_stats/widgets/finesse_thingy.dart';
|
||||||
|
import 'package:tetra_stats/widgets/lineclears_thingy.dart';
|
||||||
|
import 'package:tetra_stats/widgets/sp_trailing_stats.dart';
|
||||||
|
import 'package:tetra_stats/widgets/stat_sell_num.dart';
|
||||||
|
import 'package:tetra_stats/widgets/text_timestamp.dart';
|
||||||
|
|
||||||
|
class SingleplayerRecord extends StatelessWidget {
|
||||||
|
final RecordSingle? record;
|
||||||
|
final SingleplayerStream? stream;
|
||||||
|
final String? rank;
|
||||||
|
final bool hideTitle;
|
||||||
|
|
||||||
|
/// Widget that displays data from [record]
|
||||||
|
const SingleplayerRecord({super.key, required this.record, this.stream, this.rank, this.hideTitle = false});
|
||||||
|
|
||||||
|
Color getColorOfRank(int rank){
|
||||||
|
if (rank == 1) return Colors.yellowAccent;
|
||||||
|
if (rank == 2) return Colors.blueGrey;
|
||||||
|
if (rank == 3) return Colors.brown[400]!;
|
||||||
|
if (rank <= 9) return Colors.blueAccent;
|
||||||
|
if (rank <= 99) return Colors.greenAccent;
|
||||||
|
return Colors.grey;
|
||||||
|
}
|
||||||
|
|
||||||
|
@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!.endContext.gameType == "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!.endContext.gameType == "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 SingleChildScrollView(
|
||||||
|
child: Padding(
|
||||||
|
padding: const EdgeInsets.only(top: 8.0),
|
||||||
|
child: Column(
|
||||||
|
mainAxisAlignment: MainAxisAlignment.start,
|
||||||
|
mainAxisSize: MainAxisSize.min,
|
||||||
|
children: [
|
||||||
|
Row(
|
||||||
|
mainAxisSize: MainAxisSize.min,
|
||||||
|
children: [
|
||||||
|
if (record!.endContext.gameType == "40l") Padding(padding: const EdgeInsets.only(right: 8.0),
|
||||||
|
child: Image.asset("res/tetrio_tl_alpha_ranks/${closestAverageSprint.key}.png", height: 96)
|
||||||
|
),
|
||||||
|
if (record!.endContext.gameType == "blitz") Padding(padding: const EdgeInsets.only(right: 8.0),
|
||||||
|
child: Image.asset("res/tetrio_tl_alpha_ranks/${closestAverageBlitz.key}.png", height: 96)
|
||||||
|
),
|
||||||
|
Column(
|
||||||
|
crossAxisAlignment: CrossAxisAlignment.start,
|
||||||
|
mainAxisSize: MainAxisSize.min,
|
||||||
|
children: [
|
||||||
|
if (record!.endContext.gameType == "40l" && !hideTitle) Text(t.sprint, style: const TextStyle(height: 0.1, fontFamily: "Eurostile Round Extended", fontSize: 18)),
|
||||||
|
if (record!.endContext.gameType == "blitz" && !hideTitle) Text(t.blitz, style: const TextStyle(height: 0.1, fontFamily: "Eurostile Round Extended", fontSize: 18)),
|
||||||
|
RichText(text: TextSpan(
|
||||||
|
text: record!.endContext.gameType == "40l" ? get40lTime(record!.endContext.finalTime.inMicroseconds) : NumberFormat.decimalPattern().format(record!.endContext.score),
|
||||||
|
style: TextStyle(fontFamily: "Eurostile Round Extended", fontSize: bigScreen ? 36 : 32, fontWeight: FontWeight.w500, color: Colors.white),
|
||||||
|
),
|
||||||
|
),
|
||||||
|
RichText(text: TextSpan(
|
||||||
|
text: "",
|
||||||
|
style: const TextStyle(fontFamily: "Eurostile Round", fontSize: 14, color: Colors.grey),
|
||||||
|
children: [
|
||||||
|
if (record!.endContext.gameType == "40l" && (rank != null && rank != "z")) TextSpan(text: "${t.verdictGeneral(n: readableTimeDifference(record!.endContext.finalTime, sprintAverages[rank]!), verdict: sprintBetterThanRankAverage??false ? t.verdictBetter : t.verdictWorse, rank: rank!.toUpperCase())}\n", style: TextStyle(
|
||||||
|
color: sprintBetterThanRankAverage??false ? Colors.greenAccent : Colors.redAccent
|
||||||
|
))
|
||||||
|
else if (record!.endContext.gameType == "40l" && (rank == null || rank == "z")) TextSpan(text: "${t.verdictGeneral(n: readableTimeDifference(record!.endContext.finalTime, closestAverageSprint.value), verdict: sprintBetterThanClosestAverage ? t.verdictBetter : t.verdictWorse, rank: closestAverageSprint.key.toUpperCase())}\n", style: TextStyle(
|
||||||
|
color: sprintBetterThanClosestAverage ? Colors.greenAccent : Colors.redAccent
|
||||||
|
))
|
||||||
|
else if (record!.endContext.gameType == "blitz" && (rank != null && rank != "z")) TextSpan(text: "${t.verdictGeneral(n: readableIntDifference(record!.endContext.score, blitzAverages[rank]!), verdict: blitzBetterThanRankAverage??false ? t.verdictBetter : t.verdictWorse, rank: rank!.toUpperCase())}\n", style: TextStyle(
|
||||||
|
color: blitzBetterThanRankAverage??false ? Colors.greenAccent : Colors.redAccent
|
||||||
|
))
|
||||||
|
else if (record!.endContext.gameType == "blitz" && (rank == null || rank == "z")) TextSpan(text: "${t.verdictGeneral(n: readableIntDifference(record!.endContext.score, closestAverageBlitz.value), verdict: blitzBetterThanClosestAverage ? t.verdictBetter : t.verdictWorse, rank: closestAverageBlitz.key.toUpperCase())}\n", style: TextStyle(
|
||||||
|
color: blitzBetterThanClosestAverage ? Colors.greenAccent : Colors.redAccent
|
||||||
|
)),
|
||||||
|
if (record!.rank != null) TextSpan(text: "№${record!.rank}", style: TextStyle(color: getColorOfRank(record!.rank!))),
|
||||||
|
if (record!.rank != null) const TextSpan(text: " • "),
|
||||||
|
TextSpan(text: timestamp(record!.timestamp)),
|
||||||
|
]
|
||||||
|
),
|
||||||
|
)
|
||||||
|
],),
|
||||||
|
],
|
||||||
|
),
|
||||||
|
if (record!.endContext.gameType == "40l") Wrap(
|
||||||
|
alignment: WrapAlignment.spaceBetween,
|
||||||
|
spacing: 20,
|
||||||
|
children: [
|
||||||
|
StatCellNum(playerStat: record!.endContext.piecesPlaced, playerStatLabel: t.statCellNum.pieces, isScreenBig: bigScreen, higherIsBetter: true, smallDecimal: false),
|
||||||
|
StatCellNum(playerStat: record!.endContext.pps, playerStatLabel: t.statCellNum.pps, fractionDigits: 2, isScreenBig: bigScreen, higherIsBetter: true, smallDecimal: false),
|
||||||
|
StatCellNum(playerStat: record!.endContext.kpp, playerStatLabel: t.statCellNum.kpp, fractionDigits: 2, isScreenBig: bigScreen, higherIsBetter: true, smallDecimal: false),
|
||||||
|
],
|
||||||
|
),
|
||||||
|
if (record!.endContext.gameType == "blitz") Wrap(
|
||||||
|
alignment: WrapAlignment.spaceBetween,
|
||||||
|
crossAxisAlignment: WrapCrossAlignment.start,
|
||||||
|
spacing: 20,
|
||||||
|
children: [
|
||||||
|
StatCellNum(playerStat: record!.endContext.level, playerStatLabel: t.statCellNum.level, isScreenBig: bigScreen, higherIsBetter: true, smallDecimal: false),
|
||||||
|
StatCellNum(playerStat: record!.endContext.pps, playerStatLabel: t.statCellNum.pps, fractionDigits: 2, isScreenBig: bigScreen, higherIsBetter: true, smallDecimal: false),
|
||||||
|
StatCellNum(playerStat: record!.endContext.spp, playerStatLabel: t.statCellNum.spp, fractionDigits: 2, isScreenBig: bigScreen, higherIsBetter: true)
|
||||||
|
],
|
||||||
|
),
|
||||||
|
FinesseThingy(record?.endContext.finesse, record?.endContext.finessePercentage),
|
||||||
|
LineclearsThingy(record!.endContext.clears, record!.endContext.lines, record!.endContext.holds, record!.endContext.tSpins),
|
||||||
|
if (record!.endContext.gameType == "40l") Text("${record!.endContext.inputs} KP • ${f2.format(record!.endContext.kps)} KPS"),
|
||||||
|
if (record!.endContext.gameType == "blitz") Text("${record!.endContext.piecesPlaced} P • ${record!.endContext.inputs} KP • ${f2.format(record!.endContext.kpp)} KPP • ${f2.format(record!.endContext.kps)} KPS"),
|
||||||
|
if (stream != null && stream!.records.length > 1) for(int i = 1; i < stream!.records.length; i++) ListTile(
|
||||||
|
onTap: () => Navigator.push(context, MaterialPageRoute(builder: (context) => SingleplayerRecordView(record: stream!.records[i]))),
|
||||||
|
leading: Text("#${i+1}",
|
||||||
|
style: const TextStyle(fontFamily: "Eurostile Round", fontSize: 28, shadows: textShadow, height: 0.9)
|
||||||
|
),
|
||||||
|
title: Text(
|
||||||
|
switch (stream!.records[i].endContext.gameType){
|
||||||
|
"40l" => get40lTime(stream!.records[i].endContext.finalTime.inMicroseconds),
|
||||||
|
"blitz" => "${NumberFormat.decimalPattern().format(stream!.records[i].endContext.score)} points",
|
||||||
|
"5mblast" => get40lTime(stream!.records[i].endContext.finalTime.inMicroseconds),
|
||||||
|
String() => "huh",
|
||||||
|
},
|
||||||
|
style: TextStyle(fontSize: 18)),
|
||||||
|
subtitle: Text(timestamp(stream!.records[i].timestamp), style: TextStyle(color: Colors.grey, height: 0.85)),
|
||||||
|
trailing: SpTrailingStats(stream!.records[i].endContext)
|
||||||
|
)
|
||||||
|
]
|
||||||
|
),
|
||||||
|
),
|
||||||
|
);
|
||||||
|
}
|
||||||
|
);
|
||||||
|
}
|
||||||
|
}
|
Loading…
Reference in New Issue