Zenith added

I probably should push Nerd Stats into new widget, but i planning to redo UI a little bit, so idk
This commit is contained in:
dan63047 2024-07-29 23:58:17 +03:00
parent 90ad788c6c
commit c1561fba80
6 changed files with 519 additions and 144 deletions

View File

@ -457,8 +457,10 @@ class TetrioPlayer {
class Summaries{ class Summaries{
late String id; late String id;
late RecordSingle sprint; RecordSingle? sprint;
late RecordSingle blitz; RecordSingle? blitz;
RecordSingle? zenith;
RecordSingle? zenithEx;
late TetraLeagueAlpha league; late TetraLeagueAlpha league;
late TetrioZen zen; late TetrioZen zen;
@ -466,8 +468,10 @@ class Summaries{
Summaries.fromJson(Map<String, dynamic> json, String i){ Summaries.fromJson(Map<String, dynamic> json, String i){
id = i; id = i;
sprint = RecordSingle.fromJson(json['40l']['record'], json['40l']['rank']); if (json['40l']['record'] != null) sprint = RecordSingle.fromJson(json['40l']['record'], json['40l']['rank'], json['40l']['rank_local']);
blitz = RecordSingle.fromJson(json['blitz']['record'], json['blitz']['rank']); if (json['blitz']['record'] != null) blitz = RecordSingle.fromJson(json['blitz']['record'], json['blitz']['rank'], json['40l']['rank_local']);
if (json['zenith']['record'] != null) zenith = RecordSingle.fromJson(json['zenith']['record'], json['zenith']['rank'], json['zenith']['rank_local']);
if (json['zenithex']['record'] != null) zenithEx = RecordSingle.fromJson(json['zenithex']['record'], json['zenithex']['rank'], json['zenithex']['rank_local']);
league = TetraLeagueAlpha.fromJson(json['league'], DateTime.now()); league = TetraLeagueAlpha.fromJson(json['league'], DateTime.now());
zen = TetrioZen.fromJson(json['zen']); zen = TetrioZen.fromJson(json['zen']);
} }
@ -676,11 +680,13 @@ class ResultsStats {
late int piecesPlaced; late int piecesPlaced;
late int lines; late int lines;
late int score; late int score;
late int seed; int? seed;
late Duration finalTime; late Duration finalTime;
late int tSpins; late int tSpins;
late Clears clears; late Clears clears;
late Finesse? finesse; late int kills;
Finesse? finesse;
ZenithResults? zenith;
double get pps => piecesPlaced / (finalTime.inMicroseconds / 1000000); double get pps => piecesPlaced / (finalTime.inMicroseconds / 1000000);
double get kpp => inputs / piecesPlaced; double get kpp => inputs / piecesPlaced;
@ -717,7 +723,9 @@ class ResultsStats {
tSpins = json['tspins']; tSpins = json['tspins'];
piecesPlaced = json['piecesplaced']; piecesPlaced = json['piecesplaced'];
clears = Clears.fromJson(json['clears']); clears = Clears.fromJson(json['clears']);
finesse = json.containsKey("finesse") ? Finesse.fromJson(json['finesse']) : null; kills = json['kills'];
if (json.containsKey("finesse")) finesse = Finesse.fromJson(json['finesse']);
if (json.containsKey("zenith")) zenith = ZenithResults.fromJson(json['zenith']);
} }
Map<String, dynamic> toJson() { Map<String, dynamic> toJson() {
@ -739,6 +747,39 @@ class ResultsStats {
} }
} }
class ZenithResults{
late double altitude;
late double rank;
late double peakrank;
late double avgrankpts;
late int floor;
late double targetingfactor;
late double targetinggrace;
late double totalbonus;
late int revives;
late int revivesTotal;
late bool speedrun;
late bool speedrunSeen;
late List<Duration> splits;
ZenithResults.fromJson(Map<String, dynamic> json){
altitude = json['altitude'].toDouble();
rank = json['rank'].toDouble();
peakrank = json['peakrank'].toDouble();
avgrankpts = json['avgrankpts'].toDouble();
floor = json['floor'];
targetingfactor = json['targetingfactor'].toDouble();
targetinggrace = json['targetinggrace'].toDouble();
totalbonus = json['totalbonus'].toDouble();
revives = json['revives'];
revivesTotal = json['revivesTotal'];
speedrun = json['speedrun'];
speedrunSeen = json['speedrun_seen'];
splits = [];
for (int ms in json['splits']) splits.add(Duration(milliseconds: ms));
}
}
class Handling { class Handling {
late num arr; late num arr;
late num das; late num das;
@ -997,7 +1038,7 @@ class SingleplayerStream{
userId = userID; userId = userID;
type = tp; type = tp;
records = []; records = [];
for (var value in json) {records.add(RecordSingle.fromJson(value, null));} for (var value in json) {records.add(RecordSingle.fromJson(value, -1, -1));}
} }
} }
@ -1079,9 +1120,9 @@ class BetaLeagueStats{
} }
BetaLeagueStats.fromJson(Map<String, dynamic> json){ BetaLeagueStats.fromJson(Map<String, dynamic> json){
apm = json['apm'].toDouble(); apm = json['apm'] != null ? json['apm'].toDouble() : 0.00;
pps = json['pps'].toDouble(); pps = json['apm'] != null ? json['pps'].toDouble() : 0.00;
vs = json['vsscore'].toDouble(); vs = json['apm'] != null ? json['vsscore'].toDouble() : 0.00;
garbageSent = json['garbagesent']; garbageSent = json['garbagesent'];
garbageReceived = json['garbagereceived']; garbageReceived = json['garbagereceived'];
kills = json['kills']; kills = json['kills'];
@ -1364,11 +1405,13 @@ class RecordSingle {
late String gamemode; late String gamemode;
late DateTime timestamp; late DateTime timestamp;
late ResultsStats stats; late ResultsStats stats;
int? rank; late int rank;
late int countryRank;
late AggregateStats aggregateStats;
RecordSingle({required this.userId, required this.replayId, required this.ownId, required this.timestamp, required this.stats, this.rank}); RecordSingle({required this.userId, required this.replayId, required this.ownId, required this.timestamp, required this.stats, required this.rank, required this.countryRank, required this.aggregateStats});
RecordSingle.fromJson(Map<String, dynamic> json, int? ran) { RecordSingle.fromJson(Map<String, dynamic> json, int ran, int cran) {
//developer.log("RecordSingle.fromJson: $json", name: "data_objects/tetrio"); //developer.log("RecordSingle.fromJson: $json", name: "data_objects/tetrio");
ownId = json['_id']; ownId = json['_id'];
gamemode = json['gamemode']; gamemode = json['gamemode'];
@ -1377,6 +1420,8 @@ class RecordSingle {
timestamp = DateTime.parse(json['ts']); timestamp = DateTime.parse(json['ts']);
userId = json['user']['id']; userId = json['user']['id'];
rank = ran; rank = ran;
countryRank = cran;
aggregateStats = AggregateStats.fromJson(json['results']['aggregatestats']);
} }
Map<String, dynamic> toJson() { Map<String, dynamic> toJson() {
@ -1391,12 +1436,38 @@ class RecordSingle {
} }
} }
class AggregateStats{
late double apm;
late double pps;
late double vs;
late NerdStats nerdStats;
late EstTr estTr;
late Playstyle playstyle;
AggregateStats(this.apm, this.pps, this.vs){
nerdStats = NerdStats(apm, pps, vs);
estTr = EstTr(apm, pps, vs, nerdStats.app, nerdStats.dss, nerdStats.dsp, nerdStats.gbe);
playstyle = Playstyle(apm, pps, nerdStats.app, nerdStats.vsapm, nerdStats.dsp, nerdStats.gbe, estTr.srarea, estTr.statrank);
}
AggregateStats.fromJson(Map<String, dynamic> json){
apm = json['apm'] != null ? json['apm'].toDouble() : 0.00;
pps = json['apm'] != null ? json['pps'].toDouble() : 0.00;
vs = json['apm'] != null ? json['vsscore'].toDouble() : 0.00;
nerdStats = NerdStats(apm, pps, vs);
estTr = EstTr(apm, pps, vs, nerdStats.app, nerdStats.dss, nerdStats.dsp, nerdStats.gbe);
playstyle = Playstyle(apm, pps, nerdStats.app, nerdStats.vsapm, nerdStats.dsp, nerdStats.gbe, estTr.srarea, estTr.statrank);
}
}
class TetrioZen { class TetrioZen {
late int level; late int level;
late int score; late int score;
TetrioZen({required this.level, required this.score}); TetrioZen({required this.level, required this.score});
double get scoreRequirement => (10000 + 10000 * ((log(level + 1) / log(2)) - 1));
TetrioZen.fromJson(Map<String, dynamic> json) { TetrioZen.fromJson(Map<String, dynamic> json) {
level = json['level']; level = json['level'];
score = json['score']; score = json['score'];

View File

@ -904,10 +904,10 @@ class TetrioService extends DB {
if (jsonDecode(response.body)['success']) { if (jsonDecode(response.body)['success']) {
Map jsonRecords = jsonDecode(response.body); Map jsonRecords = jsonDecode(response.body);
var sprint = jsonRecords['data']['records']['40l']['record'] != null var sprint = jsonRecords['data']['records']['40l']['record'] != null
? RecordSingle.fromJson(jsonRecords['data']['records']['40l']['record'], jsonRecords['data']['records']['40l']['rank']) ? RecordSingle.fromJson(jsonRecords['data']['records']['40l']['record'], jsonRecords['data']['records']['40l']['rank'], jsonRecords['data']['records']['40l']['rank_local'])
: null; : null;
var blitz = jsonRecords['data']['records']['blitz']['record'] != null var blitz = jsonRecords['data']['records']['blitz']['record'] != null
? RecordSingle.fromJson(jsonRecords['data']['records']['blitz']['record'], jsonRecords['data']['records']['blitz']['rank']) ? RecordSingle.fromJson(jsonRecords['data']['records']['blitz']['record'], jsonRecords['data']['records']['blitz']['rank'], jsonRecords['data']['records']['blitz']['rank_local'])
: null; : null;
var zen = TetrioZen.fromJson(jsonRecords['data']['zen']); var zen = TetrioZen.fromJson(jsonRecords['data']['zen']);
UserRecords result = UserRecords(userID, sprint, blitz, zen); UserRecords result = UserRecords(userID, sprint, blitz, zen);

View File

@ -3,6 +3,7 @@ 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 secs = NumberFormat("00.###", LocaleSettings.currentLocale.languageCode);
final NumberFormat fixedSecs = NumberFormat("00.000", LocaleSettings.currentLocale.languageCode);
final NumberFormat nonsecs = NumberFormat("00", LocaleSettings.currentLocale.languageCode); final NumberFormat nonsecs = NumberFormat("00", LocaleSettings.currentLocale.languageCode);
final NumberFormat nonsecs3 = NumberFormat("000", LocaleSettings.currentLocale.languageCode); final NumberFormat nonsecs3 = NumberFormat("000", LocaleSettings.currentLocale.languageCode);
final NumberFormat _timeInSec = NumberFormat("#,###.###s.", LocaleSettings.currentLocale.languageCode); final NumberFormat _timeInSec = NumberFormat("#,###.###s.", LocaleSettings.currentLocale.languageCode);
@ -70,6 +71,10 @@ String get40lTime(int microseconds){
return microseconds > 60000000 ? "${(microseconds/1000000/60).floor()}:${(secs.format(microseconds /1000000 % 60))}" : _timeInSec.format(microseconds / 1000000); return microseconds > 60000000 ? "${(microseconds/1000000/60).floor()}:${(secs.format(microseconds /1000000 % 60))}" : _timeInSec.format(microseconds / 1000000);
} }
String getMoreNormalTime(Duration time){
return "${nonsecs.format(time.inMinutes)}:${(fixedSecs.format(time.inMilliseconds/1000%60))}";
}
/// Readable [a] - [b], without sign /// Readable [a] - [b], without sign
String readableTimeDifference(Duration a, Duration b){ String readableTimeDifference(Duration a, Duration b){
Duration result = a - b; Duration result = a - b;

View File

@ -11,6 +11,7 @@ import 'package:intl/intl.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';
import 'package:syncfusion_flutter_charts/charts.dart'; import 'package:syncfusion_flutter_charts/charts.dart';
import 'package:syncfusion_flutter_gauges/gauges.dart';
import 'package:tetra_stats/data_objects/tetra_stats.dart'; import 'package:tetra_stats/data_objects/tetra_stats.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';
@ -23,6 +24,8 @@ import 'package:tetra_stats/utils/text_shadow.dart';
import 'package:tetra_stats/views/singleplayer_record_view.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/gauget_num.dart';
import 'package:tetra_stats/widgets/graphs.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/recent_sp_games.dart';
@ -430,12 +433,14 @@ class _MainState extends State<MainView> with TickerProviderStateMixin {
tabs: bigScreen ? [ tabs: bigScreen ? [
Tab(text: t.tetraLeague,), Tab(text: t.tetraLeague,),
Tab(text: t.history), Tab(text: t.history),
Tab(text: "Quick Play"),
Tab(text: "${t.sprint} & ${t.blitz}"), Tab(text: "${t.sprint} & ${t.blitz}"),
Tab(text: t.other), Tab(text: t.other),
] : [ ] : [
Tab(text: t.tetraLeague), Tab(text: t.tetraLeague),
Tab(text: t.tlRecords), Tab(text: t.tlRecords),
Tab(text: t.history), Tab(text: t.history),
Tab(text: "Quick Play"),
Tab(text: t.sprint), Tab(text: t.sprint),
Tab(text: t.blitz), Tab(text: t.blitz),
Tab(text: t.recentRuns), Tab(text: t.recentRuns),
@ -478,6 +483,7 @@ class _MainState extends State<MainView> with TickerProviderStateMixin {
), ),
],), ],),
_History(chartsData: chartsData, changePlayer: changePlayer, userID: _searchFor, update: _justUpdate, wasActiveInTL: snapshot.data![1].league.gamesPlayed > 0), _History(chartsData: chartsData, changePlayer: changePlayer, userID: _searchFor, update: _justUpdate, wasActiveInTL: snapshot.data![1].league.gamesPlayed > 0),
_ZenithThingy(record: snapshot.data![1].zenith, recordEX: snapshot.data![1].zenithEx),
_TwoRecordsThingy(sprint: snapshot.data![1].sprint, blitz: snapshot.data![1].blitz, rank: snapshot.data![1].league.percentileRank, recent: SingleplayerStream(userId: "userId", records: [], type: "recent"), sprintStream: SingleplayerStream(userId: "userId", records: [], type: "40l"), blitzStream: SingleplayerStream(userId: "userId", records: [], type: "blitz")), _TwoRecordsThingy(sprint: snapshot.data![1].sprint, blitz: snapshot.data![1].blitz, rank: snapshot.data![1].league.percentileRank, recent: SingleplayerStream(userId: "userId", records: [], type: "recent"), sprintStream: SingleplayerStream(userId: "userId", records: [], type: "40l"), blitzStream: SingleplayerStream(userId: "userId", records: [], type: "blitz")),
_OtherThingy(zen: snapshot.data![1].zen, bio: snapshot.data![0].bio, distinguishment: snapshot.data![0].distinguishment, newsletter: snapshot.data![2]) _OtherThingy(zen: snapshot.data![1].zen, bio: snapshot.data![0].bio, distinguishment: snapshot.data![0].distinguishment, newsletter: snapshot.data![2])
] : [ ] : [
@ -500,6 +506,7 @@ class _MainState extends State<MainView> with TickerProviderStateMixin {
), ),
_TLRecords(userID: snapshot.data![0].userId, changePlayer: changePlayer, data: snapshot.data![3].records, wasActiveInTL: true, oldMathcesHere: _TLHistoryWasFetched, separateScrollController: true), _TLRecords(userID: snapshot.data![0].userId, changePlayer: changePlayer, data: snapshot.data![3].records, wasActiveInTL: true, oldMathcesHere: _TLHistoryWasFetched, separateScrollController: true),
_History(chartsData: chartsData, changePlayer: changePlayer, userID: _searchFor, update: _justUpdate, wasActiveInTL: snapshot.data![1].league.gamesPlayed > 0), _History(chartsData: chartsData, changePlayer: changePlayer, userID: _searchFor, update: _justUpdate, wasActiveInTL: snapshot.data![1].league.gamesPlayed > 0),
_ZenithThingy(record: snapshot.data![1].zenith, recordEX: snapshot.data![1].zenithEx),
SingleplayerRecord(record: snapshot.data![1].sprint, rank: snapshot.data![1].league.percentileRank, stream: SingleplayerStream(userId: "userId", records: [], type: "40l")), SingleplayerRecord(record: snapshot.data![1].sprint, rank: snapshot.data![1].league.percentileRank, stream: SingleplayerStream(userId: "userId", records: [], type: "40l")),
SingleplayerRecord(record: snapshot.data![1].blitz, rank: snapshot.data![1].league.percentileRank, stream: SingleplayerStream(userId: "userId", records: [], type: "Blitz")), SingleplayerRecord(record: snapshot.data![1].blitz, rank: snapshot.data![1].league.percentileRank, stream: SingleplayerStream(userId: "userId", records: [], type: "Blitz")),
_RecentSingleplayersThingy(SingleplayerStream(userId: "userId", records: [], type: "recent")), _RecentSingleplayersThingy(SingleplayerStream(userId: "userId", records: [], type: "recent")),
@ -1218,7 +1225,230 @@ class _RecentSingleplayersThingy extends StatelessWidget {
child: RecentSingleplayerGames(recent: recent, hideTitle: true) child: RecentSingleplayerGames(recent: recent, hideTitle: true)
); );
} }
}
class _ZenithThingy extends StatefulWidget{
final RecordSingle? record;
final RecordSingle? recordEX;
_ZenithThingy({this.record, this.recordEX});
@override
State<_ZenithThingy> createState() => _ZenithThingyState();
}
class _ZenithThingyState extends State<_ZenithThingy> {
late RecordSingle? record;
bool ex = false;
@override
void initState(){
super.initState();
record = ex ? widget.recordEX : widget.record;
}
@override
Widget build(BuildContext context) {
return LayoutBuilder(builder: (context, constraints){
bool bigScreen = constraints.maxWidth > 768;
if (record == null) {
return Padding(
padding: const EdgeInsets.only(top: 8.0),
child: Column(
children: [
Text("Quick Play${ex ? " Expert" : ""}", style: const TextStyle(height: 0.1, fontFamily: "Eurostile Round Extended", fontSize: 18)),
RichText(text: TextSpan(
text: "--- m",
style: TextStyle(fontFamily: "Eurostile Round Extended", fontSize: bigScreen ? 36 : 32, fontWeight: FontWeight.w500, color: Colors.grey),
),
),
TextButton(onPressed: (){
if (ex){
ex = false;
}else{
ex = true;
}
setState(() {
record = ex ? widget.recordEX : widget.record;
});
}, child: Text(ex ? "Switch to normal" : "Switch to Expert")),
],
),
);
}
return SingleChildScrollView(
child: Padding(padding: const EdgeInsets.only(top: 8.0),
child: Column(
children: [
Text("Quick Play${ex ? " Expert" : ""}", style: const TextStyle(height: 0.1, fontFamily: "Eurostile Round Extended", fontSize: 18)),
RichText(text: TextSpan(
text: "${f2.format(record!.stats.zenith!.altitude)} m",
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!.rank != -1) TextSpan(text: "${record!.rank}"),
if (record!.rank != -1) const TextSpan(text: ""),
if (record!.countryRank != -1) TextSpan(text: "${record!.countryRank} local"),
if (record!.countryRank != -1) const TextSpan(text: ""),
TextSpan(text: timestamp(widget.record!.timestamp)),
]
),
),
TextButton(onPressed: (){
if (ex){
ex = false;
}else{
ex = true;
}
setState(() {
record = ex ? widget.recordEX : widget.record;
});
}, child: Text(ex ? "Switch to normal" : "Switch to Expert")),
Wrap(
alignment: WrapAlignment.spaceBetween,
crossAxisAlignment: WrapCrossAlignment.start,
spacing: 20,
children: [
StatCellNum(playerStat: record!.aggregateStats.apm, playerStatLabel: t.statCellNum.apm, fractionDigits: 2, isScreenBig: bigScreen, higherIsBetter: true, smallDecimal: true),
StatCellNum(playerStat: record!.aggregateStats.pps, playerStatLabel: t.statCellNum.pps, fractionDigits: 2, isScreenBig: bigScreen, higherIsBetter: true, smallDecimal: false),
StatCellNum(playerStat: record!.aggregateStats.vs, playerStatLabel: t.statCellNum.vs, fractionDigits: 2, isScreenBig: bigScreen, higherIsBetter: true, smallDecimal: true),
StatCellNum(playerStat: record!.stats.kills, playerStatLabel: "Kills", isScreenBig: bigScreen, higherIsBetter: true)
],
),
FinesseThingy(record?.stats.finesse, record?.stats.finessePercentage),
LineclearsThingy(record!.stats.clears, record!.stats.lines, record!.stats.holds, record!.stats.tSpins),
Padding(
padding: const EdgeInsets.only(top: 8.0),
child: SizedBox(
width: 300,
child: Column(
mainAxisSize: MainAxisSize.min,
children: [
Text("Total time: ${getMoreNormalTime(record!.stats.finalTime)}", style: const TextStyle(color: Colors.white, fontFamily: "Eurostile Round Extended"), textAlign: TextAlign.center),
Table(
children: [
TableRow(
children: [
Text("Floor"),
Text("Split"),
Text("Total"),
]
),
for (int i = 0; i < record!.stats.zenith!.splits.length; i++) TableRow(
children: [
Text((i+1).toString()),
Text(record!.stats.zenith!.splits[i] != Duration.zero ? getMoreNormalTime(record!.stats.zenith!.splits[i]-(i-1 != -1 ? record!.stats.zenith!.splits[i-1] : Duration.zero)) : "--:--.---"),
Text(record!.stats.zenith!.splits[i] != Duration.zero ? getMoreNormalTime(record!.stats.zenith!.splits[i]) : "--:--.---"),
]
)
],
),
],
),
),
),
Column(
children: [
Text(t.nerdStats, style: TextStyle(fontFamily: "Eurostile Round Extended", fontSize: bigScreen ? 42 : 28)),
Padding(
padding: const EdgeInsets.fromLTRB(0, 40, 0, 0),
child: Wrap(
direction: Axis.horizontal,
alignment: WrapAlignment.center,
spacing: 35,
crossAxisAlignment: WrapCrossAlignment.start,
clipBehavior: Clip.hardEdge,
children: [
GaugetNum(playerStat: record!.aggregateStats.nerdStats.app, playerStatLabel: t.statCellNum.app, higherIsBetter: true, minimum: 0, maximum: 1, ranges: [
GaugeRange(startValue: 0, endValue: 0.2, color: Colors.red),
GaugeRange(startValue: 0.2, endValue: 0.4, color: Colors.yellow),
GaugeRange(startValue: 0.4, endValue: 0.6, color: Colors.green),
GaugeRange(startValue: 0.6, endValue: 0.8, color: Colors.blue),
GaugeRange(startValue: 0.8, endValue: 1, color: Colors.purple),
], alertWidgets: [
Text(t.statCellNum.appDescription),
Text("${t.exactValue}: ${record!.aggregateStats.nerdStats.app}")
]),
GaugetNum(playerStat: record!.aggregateStats.nerdStats.vsapm, playerStatLabel: "VS / APM", higherIsBetter: true, minimum: 1.8, maximum: 2.4, ranges: [
GaugeRange(startValue: 1.8, endValue: 2.0, color: Colors.green),
GaugeRange(startValue: 2.0, endValue: 2.2, color: Colors.blue),
GaugeRange(startValue: 2.2, endValue: 2.4, color: Colors.purple),
], alertWidgets: [
Text(t.statCellNum.vsapmDescription),
Text("${t.exactValue}: ${record!.aggregateStats.nerdStats.vsapm}")
])
]),
),
Padding(
padding: const EdgeInsets.fromLTRB(8, 0, 8, 0),
child: Wrap(
direction: Axis.horizontal,
alignment: WrapAlignment.center,
spacing: 25,
crossAxisAlignment: WrapCrossAlignment.start,
clipBehavior: Clip.hardEdge,
children: [
StatCellNum(playerStat: record!.aggregateStats.nerdStats.dss, isScreenBig: bigScreen, fractionDigits: 3, playerStatLabel: t.statCellNum.dss,
alertWidgets: [Text(t.statCellNum.dssDescription),
Text("${t.formula}: (VS / 100) - (APM / 60)"),
Text("${t.exactValue}: ${record!.aggregateStats.nerdStats.dss}"),],
okText: t.popupActions.ok,
higherIsBetter: true,),
StatCellNum(playerStat: record!.aggregateStats.nerdStats.dsp, isScreenBig: bigScreen, fractionDigits: 3, playerStatLabel: t.statCellNum.dsp,
alertWidgets: [Text(t.statCellNum.dspDescription),
Text("${t.formula}: DS/S / PPS"),
Text("${t.exactValue}: ${record!.aggregateStats.nerdStats.dsp}"),],
okText: t.popupActions.ok,
higherIsBetter: true),
StatCellNum(playerStat: record!.aggregateStats.nerdStats.appdsp, isScreenBig: bigScreen, fractionDigits: 3, playerStatLabel: t.statCellNum.appdsp,
alertWidgets: [Text(t.statCellNum.appdspDescription),
Text("${t.formula}: APP + DS/P"),
Text("${t.exactValue}: ${record!.aggregateStats.nerdStats.appdsp}"),],
okText: t.popupActions.ok,
higherIsBetter: true),
StatCellNum(playerStat: record!.aggregateStats.nerdStats.cheese, isScreenBig: bigScreen, fractionDigits: 2, playerStatLabel: t.statCellNum.cheese,
alertWidgets: [Text(t.statCellNum.cheeseDescription),
Text("${t.formula}: (DS/P * 150) + ((VS/APM - 2) * 50) + (0.6 - APP) * 125"),
Text("${t.exactValue}: ${record!.aggregateStats.nerdStats.cheese}"),],
okText: t.popupActions.ok,
higherIsBetter: false),
StatCellNum(playerStat: record!.aggregateStats.nerdStats.gbe, isScreenBig: bigScreen, fractionDigits: 3, playerStatLabel: t.statCellNum.gbe,
alertWidgets: [Text(t.statCellNum.gbeDescription),
Text("${t.formula}: APP * DS/P * 2"),
Text("${t.exactValue}: ${record!.aggregateStats.nerdStats.gbe}"),],
okText: t.popupActions.ok,
higherIsBetter: true),
StatCellNum(playerStat: record!.aggregateStats.nerdStats.nyaapp, isScreenBig: bigScreen, fractionDigits: 3, playerStatLabel: t.statCellNum.nyaapp,
alertWidgets: [Text(t.statCellNum.nyaappDescription),
Text("${t.formula}: APP - 5 * tan(radians((Cheese Index / -30) + 1))"),
Text("${t.exactValue}: ${record!.aggregateStats.nerdStats.nyaapp}")],
okText: t.popupActions.ok,
higherIsBetter: true),
StatCellNum(playerStat: record!.aggregateStats.nerdStats.area, isScreenBig: bigScreen, fractionDigits: 1, playerStatLabel: t.statCellNum.area,
alertWidgets: [Text(t.statCellNum.areaDescription),
Text("${t.formula}: APM * 1 + PPS * 45 + VS * 0.444 + APP * 185 + DS/S * 175 + DS/P * 450 + Garbage Effi * 315"),
Text("${t.exactValue}: ${record!.aggregateStats.nerdStats.area}"),],
okText: t.popupActions.ok,
higherIsBetter: true)
]),
)
],
),
Padding(
padding: const EdgeInsets.only(top: 16.0),
child: Graphs(record!.aggregateStats.apm, record!.aggregateStats.pps, record!.aggregateStats.vs, record!.aggregateStats.nerdStats, record!.aggregateStats.playstyle),
)
],
)
),
);
});
}
} }
class _OtherThingy extends StatelessWidget { class _OtherThingy extends StatelessWidget {
@ -1314,6 +1544,7 @@ class _OtherThingy extends StatelessWidget {
"40l" => get40lTime((news.data["result"]*1000).floor()), "40l" => get40lTime((news.data["result"]*1000).floor()),
"5mblast" => get40lTime((news.data["result"]*1000).floor()), "5mblast" => get40lTime((news.data["result"]*1000).floor()),
"zenith" => "${f2.format(news.data["result"])} m.", "zenith" => "${f2.format(news.data["result"])} m.",
"zenithex" => "${f2.format(news.data["result"])} m.",
_ => "unknown" _ => "unknown"
}, },
style: const TextStyle(fontWeight: FontWeight.bold) style: const TextStyle(fontWeight: FontWeight.bold)
@ -1463,6 +1694,14 @@ class _OtherThingy extends StatelessWidget {
Text(t.zen, style: TextStyle(fontFamily: "Eurostile Round Extended", fontSize: bigScreen ? 42 : 28)), Text(t.zen, style: TextStyle(fontFamily: "Eurostile Round Extended", fontSize: bigScreen ? 42 : 28)),
Text("${t.statCellNum.level} ${NumberFormat.decimalPattern().format(zen!.level)}", style: const TextStyle(fontSize: 28, fontWeight: FontWeight.bold)), Text("${t.statCellNum.level} ${NumberFormat.decimalPattern().format(zen!.level)}", style: const TextStyle(fontSize: 28, fontWeight: FontWeight.bold)),
Text("${t.statCellNum.score} ${NumberFormat.decimalPattern().format(zen!.score)}", style: const TextStyle(fontSize: 18)), Text("${t.statCellNum.score} ${NumberFormat.decimalPattern().format(zen!.score)}", style: const TextStyle(fontSize: 18)),
Container(
constraints: BoxConstraints(maxWidth: 300.0),
child: Row(children: [
Text("Score requirement to level up:"),
Spacer(),
Text(intf.format(zen!.scoreRequirement))
],),
)
], ],
), ),
), ),

View File

@ -68,8 +68,21 @@ News testNews = News("6098518e3d5155e6ec429cdc", [
NewsEntry(type: "personalbest", data: {"gametype": "blitz", "result": 23.232}, timestamp: DateTime(2002, 2, 25, 10, 30, 02)), NewsEntry(type: "personalbest", data: {"gametype": "blitz", "result": 23.232}, timestamp: DateTime(2002, 2, 25, 10, 30, 02)),
NewsEntry(type: "personalbest", data: {"gametype": "5mblast", "result": 23.232}, timestamp: DateTime(2002, 2, 25, 10, 30, 03)), NewsEntry(type: "personalbest", data: {"gametype": "5mblast", "result": 23.232}, timestamp: DateTime(2002, 2, 25, 10, 30, 03)),
]); ]);
late ScrollController controller;
class _MainState extends State<MainView> with TickerProviderStateMixin { class _MainState extends State<MainView> with TickerProviderStateMixin {
@override
void initState() {
controller = ScrollController();
super.initState();
}
@override
void dispose() {
controller.dispose();
super.dispose();
}
@override @override
Widget build(BuildContext context) { Widget build(BuildContext context) {
return Scaffold(body: Row( return Scaffold(body: Row(
@ -94,138 +107,185 @@ class _MainState extends State<MainView> with TickerProviderStateMixin {
], ],
selectedIndex: 0 selectedIndex: 0
), ),
SizedBox( Expanded(
width: 450.0, child: Scrollbar(
child: Column( controller: controller,
children: [ thumbVisibility: true,
NewUserThingy(player: testPlayer, showStateTimestamp: false, setState: setState), child: SingleChildScrollView(
Padding( controller: controller,
padding: const EdgeInsets.fromLTRB(4.0, 0.0, 4.0, 0.0), scrollDirection: Axis.horizontal,
child: Row( child: Row(
mainAxisAlignment: MainAxisAlignment.center, mainAxisSize: MainAxisSize.min,
children: [ children: [
Expanded(child: ElevatedButton.icon(onPressed: (){print("ok, and?");}, icon: Icon(Icons.person_add), label: Text(t.track), style: ButtonStyle(shape: MaterialStatePropertyAll(RoundedRectangleBorder(borderRadius: BorderRadius.horizontal(left: Radius.circular(12.0), right: Radius.zero)))))), SizedBox(
Expanded(child: ElevatedButton.icon(onPressed: (){print("ok, and?");}, icon: Icon(Icons.balance), label: Text(t.compare), style: ButtonStyle(shape: MaterialStatePropertyAll(RoundedRectangleBorder(borderRadius: BorderRadius.horizontal(left: Radius.zero, right: Radius.circular(12.0))))))) width: 450.0,
], child: Column(
),
),
Card(
surfaceTintColor: theme.colorScheme.surface,
child: Column(
children: [
Padding(
padding: const EdgeInsets.fromLTRB(20.0, 0.0, 20.0, 0.0),
child: Row(
children: [
Text("Badges", style: TextStyle(fontFamily: "Eurostile Round Extended")),
Spacer(),
Text(intf.format(testPlayer.badges.length))
],
),
),
SingleChildScrollView(
scrollDirection: Axis.horizontal,
child: Row(
children: [
for (var badge in testPlayer.badges)
IconButton(
onPressed: () => showDialog<void>(
context: context,
builder: (BuildContext context) {
return AlertDialog(
title: Text(badge.label, style: const TextStyle(fontFamily: "Eurostile Round Extended")),
content: SingleChildScrollView(
child: ListBody(
children: [
Wrap(
direction: Axis.horizontal,
alignment: WrapAlignment.center,
crossAxisAlignment: WrapCrossAlignment.center,
spacing: 25,
children: [
Image.asset("res/tetrio_badges/${badge.badgeId}.png"),
Text(badge.ts != null
? t.obtainDate(date: timestamp(badge.ts!))
: t.assignedManualy),
],
)
],
),
),
actions: <Widget>[
TextButton(
child: Text(t.popupActions.ok),
onPressed: () {
Navigator.of(context).pop();
},
),
],
);
},
),
tooltip: badge.label,
icon: Image.asset(
"res/tetrio_badges/${badge.badgeId}.png",
height: 32,
width: 32,
errorBuilder: (context, error, stackTrace) {
return Image.network(
kIsWeb ? "https://ts.dan63.by/oskware_bridge.php?endpoint=TetrioBadge&badge=${badge.badgeId}" : "https://tetr.io/res/badges/${badge.badgeId}.png",
height: 32,
width: 32,
errorBuilder:(context, error, stackTrace) {
return Image.asset("res/icons/kagari.png", height: 32, width: 32);
}
);
},
)
)
],
),
)
],
),
),
if (testPlayer.distinguishment != null) DistinguishmentThingy(testPlayer.distinguishment!),
if (testPlayer.bio != null) Card(
surfaceTintColor: theme.colorScheme.surface,
child: Column(
children: [
Row(
children: [ children: [
Spacer(), NewUserThingy(player: testPlayer, showStateTimestamp: false, setState: setState),
Text(t.bio, style: TextStyle(fontFamily: "Eurostile Round Extended")), Padding(
Spacer() padding: const EdgeInsets.fromLTRB(4.0, 0.0, 4.0, 0.0),
child: Row(
mainAxisAlignment: MainAxisAlignment.center,
children: [
Expanded(child: ElevatedButton.icon(onPressed: (){print("ok, and?");}, icon: Icon(Icons.person_add), label: Text(t.track), style: ButtonStyle(shape: MaterialStatePropertyAll(RoundedRectangleBorder(borderRadius: BorderRadius.horizontal(left: Radius.circular(12.0), right: Radius.zero)))))),
Expanded(child: ElevatedButton.icon(onPressed: (){print("ok, and?");}, icon: Icon(Icons.balance), label: Text(t.compare), style: ButtonStyle(shape: MaterialStatePropertyAll(RoundedRectangleBorder(borderRadius: BorderRadius.horizontal(left: Radius.zero, right: Radius.circular(12.0)))))))
],
),
),
Card(
surfaceTintColor: theme.colorScheme.surface,
child: Column(
children: [
Padding(
padding: const EdgeInsets.fromLTRB(20.0, 0.0, 20.0, 0.0),
child: Row(
children: [
Text("Badges", style: TextStyle(fontFamily: "Eurostile Round Extended")),
Spacer(),
Text(intf.format(testPlayer.badges.length))
],
),
),
SingleChildScrollView(
scrollDirection: Axis.horizontal,
child: Row(
children: [
for (var badge in testPlayer.badges)
IconButton(
onPressed: () => showDialog<void>(
context: context,
builder: (BuildContext context) {
return AlertDialog(
title: Text(badge.label, style: const TextStyle(fontFamily: "Eurostile Round Extended")),
content: SingleChildScrollView(
child: ListBody(
children: [
Wrap(
direction: Axis.horizontal,
alignment: WrapAlignment.center,
crossAxisAlignment: WrapCrossAlignment.center,
spacing: 25,
children: [
Image.asset("res/tetrio_badges/${badge.badgeId}.png"),
Text(badge.ts != null
? t.obtainDate(date: timestamp(badge.ts!))
: t.assignedManualy),
],
)
],
),
),
actions: <Widget>[
TextButton(
child: Text(t.popupActions.ok),
onPressed: () {
Navigator.of(context).pop();
},
),
],
);
},
),
tooltip: badge.label,
icon: Image.asset(
"res/tetrio_badges/${badge.badgeId}.png",
height: 32,
width: 32,
errorBuilder: (context, error, stackTrace) {
return Image.network(
kIsWeb ? "https://ts.dan63.by/oskware_bridge.php?endpoint=TetrioBadge&badge=${badge.badgeId}" : "https://tetr.io/res/badges/${badge.badgeId}.png",
height: 32,
width: 32,
errorBuilder:(context, error, stackTrace) {
return Image.asset("res/icons/kagari.png", height: 32, width: 32);
}
);
},
)
)
],
),
)
],
),
),
if (testPlayer.distinguishment != null) DistinguishmentThingy(testPlayer.distinguishment!),
if (testPlayer.bio != null) Card(
surfaceTintColor: theme.colorScheme.surface,
child: Column(
children: [
Row(
children: [
Spacer(),
Text(t.bio, style: TextStyle(fontFamily: "Eurostile Round Extended")),
Spacer()
],
),
Padding(
padding: const EdgeInsets.only(bottom: 8.0),
child: MarkdownBody(data: testPlayer.bio!, styleSheet: MarkdownStyleSheet(textAlign: WrapAlignment.center)),
)
],
),
),
//if (testNews != null && testNews!.news.isNotEmpty)
Expanded(child: NewsThingy(testNews))
],
)
),
SizedBox(
width: 450.0,
child: Column(
children: [
Card(
child: Row(
children: [
Spacer(),
Text("test card"),
Spacer()
],
),
)
], ],
), ),
Padding( ),
padding: const EdgeInsets.only(bottom: 8.0), SizedBox(
child: MarkdownBody(data: testPlayer.bio!, styleSheet: MarkdownStyleSheet(textAlign: WrapAlignment.center)), width: 450.0,
) child: Column(
], children: [
), Card(
child: Row(
children: [
Spacer(),
Text("test card"),
Spacer()
],
),
)
],
),
),
SizedBox(
width: 450.0,
child: Column(
children: [
Card(
child: Row(
children: [
Spacer(),
Text("test card"),
Spacer()
],
),
)
],
),
),
],
), ),
//if (testNews != null && testNews!.news.isNotEmpty) ),
Expanded(child: NewsThingy(testNews))
],
)
),
SizedBox(
width: 450.0,
child: Column(
children: [
Card(
child: Row(
children: [
Spacer(),
Text("test card"),
Spacer()
],
),
)
],
), ),
) ),
], ],
)); ));
} }

View File

@ -11,7 +11,7 @@ class StatCellNum extends StatelessWidget {
required this.playerStat, required this.playerStat,
required this.playerStatLabel, required this.playerStatLabel,
required this.isScreenBig, required this.isScreenBig,
this.smallDecimal = true, this.smallDecimal = false,
this.alertWidgets, this.alertWidgets,
this.fractionDigits, this.fractionDigits,
this.oldPlayerStat, this.oldPlayerStat,