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{
late String id;
late RecordSingle sprint;
late RecordSingle blitz;
RecordSingle? sprint;
RecordSingle? blitz;
RecordSingle? zenith;
RecordSingle? zenithEx;
late TetraLeagueAlpha league;
late TetrioZen zen;
@ -466,8 +468,10 @@ class Summaries{
Summaries.fromJson(Map<String, dynamic> json, String i){
id = i;
sprint = RecordSingle.fromJson(json['40l']['record'], json['40l']['rank']);
blitz = RecordSingle.fromJson(json['blitz']['record'], json['blitz']['rank']);
if (json['40l']['record'] != null) sprint = RecordSingle.fromJson(json['40l']['record'], json['40l']['rank'], json['40l']['rank_local']);
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());
zen = TetrioZen.fromJson(json['zen']);
}
@ -676,11 +680,13 @@ class ResultsStats {
late int piecesPlaced;
late int lines;
late int score;
late int seed;
int? seed;
late Duration finalTime;
late int tSpins;
late Clears clears;
late Finesse? finesse;
late int kills;
Finesse? finesse;
ZenithResults? zenith;
double get pps => piecesPlaced / (finalTime.inMicroseconds / 1000000);
double get kpp => inputs / piecesPlaced;
@ -717,7 +723,9 @@ class ResultsStats {
tSpins = json['tspins'];
piecesPlaced = json['piecesplaced'];
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() {
@ -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 {
late num arr;
late num das;
@ -997,7 +1038,7 @@ class SingleplayerStream{
userId = userID;
type = tp;
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){
apm = json['apm'].toDouble();
pps = json['pps'].toDouble();
vs = json['vsscore'].toDouble();
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;
garbageSent = json['garbagesent'];
garbageReceived = json['garbagereceived'];
kills = json['kills'];
@ -1364,11 +1405,13 @@ class RecordSingle {
late String gamemode;
late DateTime timestamp;
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");
ownId = json['_id'];
gamemode = json['gamemode'];
@ -1377,6 +1420,8 @@ class RecordSingle {
timestamp = DateTime.parse(json['ts']);
userId = json['user']['id'];
rank = ran;
countryRank = cran;
aggregateStats = AggregateStats.fromJson(json['results']['aggregatestats']);
}
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 {
late int level;
late int 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) {
level = json['level'];
score = json['score'];

View File

@ -904,10 +904,10 @@ class TetrioService extends DB {
if (jsonDecode(response.body)['success']) {
Map jsonRecords = jsonDecode(response.body);
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;
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;
var zen = TetrioZen.fromJson(jsonRecords['data']['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';
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 nonsecs3 = NumberFormat("000", 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);
}
String getMoreNormalTime(Duration time){
return "${nonsecs.format(time.inMinutes)}:${(fixedSecs.format(time.inMilliseconds/1000%60))}";
}
/// Readable [a] - [b], without sign
String readableTimeDifference(Duration a, Duration 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:flutter/services.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/tetrio.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/tl_match_view.dart' show TlMatchResultView;
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/list_tile_trailing_stats.dart';
import 'package:tetra_stats/widgets/recent_sp_games.dart';
@ -430,12 +433,14 @@ class _MainState extends State<MainView> with TickerProviderStateMixin {
tabs: bigScreen ? [
Tab(text: t.tetraLeague,),
Tab(text: t.history),
Tab(text: "Quick Play"),
Tab(text: "${t.sprint} & ${t.blitz}"),
Tab(text: t.other),
] : [
Tab(text: t.tetraLeague),
Tab(text: t.tlRecords),
Tab(text: t.history),
Tab(text: "Quick Play"),
Tab(text: t.sprint),
Tab(text: t.blitz),
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),
_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")),
_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),
_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].blitz, rank: snapshot.data![1].league.percentileRank, stream: SingleplayerStream(userId: "userId", records: [], type: "Blitz")),
_RecentSingleplayersThingy(SingleplayerStream(userId: "userId", records: [], type: "recent")),
@ -1218,7 +1225,230 @@ class _RecentSingleplayersThingy extends StatelessWidget {
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 {
@ -1314,6 +1544,7 @@ class _OtherThingy extends StatelessWidget {
"40l" => get40lTime((news.data["result"]*1000).floor()),
"5mblast" => get40lTime((news.data["result"]*1000).floor()),
"zenith" => "${f2.format(news.data["result"])} m.",
"zenithex" => "${f2.format(news.data["result"])} m.",
_ => "unknown"
},
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.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)),
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": "5mblast", "result": 23.232}, timestamp: DateTime(2002, 2, 25, 10, 30, 03)),
]);
late ScrollController controller;
class _MainState extends State<MainView> with TickerProviderStateMixin {
@override
void initState() {
controller = ScrollController();
super.initState();
}
@override
void dispose() {
controller.dispose();
super.dispose();
}
@override
Widget build(BuildContext context) {
return Scaffold(body: Row(
@ -94,6 +107,16 @@ class _MainState extends State<MainView> with TickerProviderStateMixin {
],
selectedIndex: 0
),
Expanded(
child: Scrollbar(
controller: controller,
thumbVisibility: true,
child: SingleChildScrollView(
controller: controller,
scrollDirection: Axis.horizontal,
child: Row(
mainAxisSize: MainAxisSize.min,
children: [
SizedBox(
width: 450.0,
child: Column(
@ -225,8 +248,45 @@ class _MainState extends State<MainView> with TickerProviderStateMixin {
)
],
),
),
SizedBox(
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()
],
),
)
],
),
),
],
),
),
),
),
],
));
}
}

View File

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