diff --git a/README.md b/README.md index 5aa643d..9f943d9 100644 --- a/README.md +++ b/README.md @@ -10,8 +10,8 @@ - ~~Sqlite Database and service, that can work with it~~ *v0.0.2* - ~~Ability to track player~~ - ~~Ability to compare 2 players~~ *v0.1.0, we are here* -- ~~Stats Calculator~~ *dev build are here* -- Ability to compare player with himself in past +- ~~Stats Calculator~~ +- ~~Ability to compare player with himself in past~~ *dev build are here* - Tetra League matches history - Tetra League historic charts for tracked players (maybe even same sh*t for 40l and blitz well see) - Better UI with delta and hints for stats *that will be v0.2.0* diff --git a/lib/data_objects/tetrio.dart b/lib/data_objects/tetrio.dart index 535303d..3177627 100644 --- a/lib/data_objects/tetrio.dart +++ b/lib/data_objects/tetrio.dart @@ -179,7 +179,7 @@ class TetrioPlayer { int get hashCode => state.hashCode; @override - bool operator ==(covariant TetrioPlayer other) => (userId == other.userId); + bool operator ==(covariant TetrioPlayer other) => isSameState(other) && state.isAtSameMomentAs(other.state); } class Badge { diff --git a/lib/views/compare_view.dart b/lib/views/compare_view.dart index e1c2015..8939e0d 100644 --- a/lib/views/compare_view.dart +++ b/lib/views/compare_view.dart @@ -6,16 +6,17 @@ import 'package:tetra_stats/data_objects/tetrio.dart'; import 'package:tetra_stats/services/tetrio_crud.dart'; TetrioPlayer? theGreenSide; +List>? greenSideStates; TetrioPlayer? theRedSide; +List>? redSideStates; final TetrioService teto = TetrioService(); - -FocusNode greenFocusNode = FocusNode(); -FocusNode redFocusNode = FocusNode(); +final DateFormat dateFormat = DateFormat.yMMMd().add_Hms(); class CompareView extends StatefulWidget { final TetrioPlayer greenSide; final TetrioPlayer? redSide; - const CompareView({Key? key, required this.greenSide, required this.redSide}) : super(key: key); + const CompareView({Key? key, required this.greenSide, required this.redSide}) + : super(key: key); @override State createState() => CompareState(); @@ -27,32 +28,91 @@ class CompareState extends State { @override void initState() { theGreenSide = widget.greenSide; - theRedSide = widget.redSide; + fetchGreenSide(widget.greenSide.userId); + if (widget.redSide != null) fetchRedSide(widget.redSide!.userId); _scrollController = ScrollController(); super.initState(); } + @override + void dispose(){ + greenSideStates = null; + theGreenSide = null; + redSideStates = null; + theRedSide = null; + super.dispose(); + } + void fetchRedSide(String user) async { try { theRedSide = await teto.fetchPlayer(user, false); + late List states; + try{ + states = await teto.getPlayer(theRedSide!.userId); + redSideStates = >[]; + for (final TetrioPlayer state in states) { + redSideStates!.add(DropdownMenuItem( + value: state, child: Text(dateFormat.format(state.state)))); + } + redSideStates!.add(DropdownMenuItem( + value: theRedSide!, child: const Text("Most recent one"))); + }on Exception { + states = []; + redSideStates = null; + } } on Exception { - ScaffoldMessenger.of(context).showSnackBar(SnackBar(content: Text("Falied to assign $user"))); + ScaffoldMessenger.of(context) + .showSnackBar(SnackBar(content: Text("Falied to assign $user"))); } setState(() {}); } + void changeRedSide(TetrioPlayer user) { + setState(() {theRedSide = user;}); + } + void fetchGreenSide(String user) async { try { theGreenSide = await teto.fetchPlayer(user, false); + late List states; + greenSideStates = null; + try{ + states = await teto.getPlayer(theGreenSide!.userId); + greenSideStates = >[]; + for (final TetrioPlayer state in states) { + greenSideStates!.add(DropdownMenuItem( + value: state, child: Text(dateFormat.format(state.state)))); + } + greenSideStates!.add(DropdownMenuItem( + value: theGreenSide!, child: const Text("Most recent one"))); + }on Exception { + states = []; + greenSideStates = null; + } } on Exception { - ScaffoldMessenger.of(context).showSnackBar(SnackBar(content: Text("Falied to assign $user"))); + ScaffoldMessenger.of(context) + .showSnackBar(SnackBar(content: Text("Falied to assign $user"))); } setState(() {}); } - double getWinrateByTR(double yourGlicko, double yourRD, double notyourGlicko, double notyourRD) { + void changeGreenSide(TetrioPlayer user) { + setState(() {theGreenSide = user;}); + } + + double getWinrateByTR(double yourGlicko, double yourRD, double notyourGlicko, + double notyourRD) { return ((1 / - (1 + pow(10, (notyourGlicko - yourGlicko) / (400 * sqrt(1 + (3 * pow(0.0057564273, 2) * (pow(yourRD, 2) + pow(notyourRD, 2)) / pow(pi, 2)))))))); + (1 + + pow( + 10, + (notyourGlicko - yourGlicko) / + (400 * + sqrt(1 + + (3 * + pow(0.0057564273, 2) * + (pow(yourRD, 2) + pow(notyourRD, 2)) / + pow(pi, 2)))))))); } void _justUpdate() { @@ -93,7 +153,9 @@ class CompareState extends State { padding: const EdgeInsets.fromLTRB(8, 0, 8, 0), child: PlayerSelector( player: theGreenSide, - change: fetchGreenSide, + states: greenSideStates, + fetch: fetchGreenSide, + change: changeGreenSide, updateState: _justUpdate, ), ), @@ -116,7 +178,9 @@ class CompareState extends State { padding: const EdgeInsets.fromLTRB(8, 0, 8, 0), child: PlayerSelector( player: theRedSide, - change: fetchRedSide, + states: redSideStates, + fetch: fetchRedSide, + change: changeRedSide, updateState: _justUpdate, ), ), @@ -134,10 +198,14 @@ class CompareState extends State { body: theGreenSide != null && theRedSide != null ? ListView( children: [ - if (theGreenSide!.role != "banned" && theRedSide!.role != "banned") + if (theGreenSide!.role != "banned" && + theRedSide!.role != "banned") Column( children: [ - CompareRegTimeThingy(greenSide: theGreenSide!.registrationTime, redSide: theRedSide!.registrationTime, label: "Registred"), + CompareRegTimeThingy( + greenSide: theGreenSide!.registrationTime, + redSide: theRedSide!.registrationTime, + label: "Registred"), CompareThingy( label: "Level", greenSide: theGreenSide!.level, @@ -145,22 +213,31 @@ class CompareState extends State { higherIsBetter: true, fractionDigits: 2, ), - if (!theGreenSide!.gameTime.isNegative && !theRedSide!.gameTime.isNegative) + if (!theGreenSide!.gameTime.isNegative && + !theRedSide!.gameTime.isNegative) CompareThingy( - greenSide: theGreenSide!.gameTime.inMicroseconds / 1000000 / 60 / 60, - redSide: theRedSide!.gameTime.inMicroseconds / 1000000 / 60 / 60, + greenSide: theGreenSide!.gameTime.inMicroseconds / + 1000000 / + 60 / + 60, + redSide: theRedSide!.gameTime.inMicroseconds / + 1000000 / + 60 / + 60, label: "Hours Played", higherIsBetter: true, fractionDigits: 2, ), - if (theGreenSide!.gamesPlayed >= 0 && theRedSide!.gamesPlayed >= 0) + if (theGreenSide!.gamesPlayed >= 0 && + theRedSide!.gamesPlayed >= 0) CompareThingy( label: "Online Games", greenSide: theGreenSide!.gamesPlayed, redSide: theRedSide!.gamesPlayed, higherIsBetter: true, ), - if (theGreenSide!.gamesWon >= 0 && theRedSide!.gamesWon >= 0) + if (theGreenSide!.gamesWon >= 0 && + theRedSide!.gamesWon >= 0) CompareThingy( label: "Games Won", greenSide: theGreenSide!.gamesWon, @@ -176,16 +253,25 @@ class CompareState extends State { ], ) else - CompareBoolThingy(greenSide: theGreenSide!.role == "banned", redSide: theRedSide!.role == "banned", label: "Banned", trueIsBetter: false), + CompareBoolThingy( + greenSide: theGreenSide!.role == "banned", + redSide: theRedSide!.role == "banned", + label: "Banned", + trueIsBetter: false), const Divider(), - theGreenSide!.tlSeason1.gamesPlayed > 0 && theRedSide!.tlSeason1.gamesPlayed > 0 + theGreenSide!.tlSeason1.gamesPlayed > 0 && + theRedSide!.tlSeason1.gamesPlayed > 0 ? Column( children: [ Padding( padding: const EdgeInsets.only(bottom: 16), - child: Text("Tetra League", style: TextStyle(fontFamily: "Eurostile Round Extended", fontSize: bigScreen ? 42 : 28)), + child: Text("Tetra League", + style: TextStyle( + fontFamily: "Eurostile Round Extended", + fontSize: bigScreen ? 42 : 28)), ), - if (theGreenSide!.tlSeason1.gamesPlayed > 9 && theRedSide!.tlSeason1.gamesPlayed > 9) + if (theGreenSide!.tlSeason1.gamesPlayed > 9 && + theRedSide!.tlSeason1.gamesPlayed > 9) CompareThingy( label: "TR", greenSide: theGreenSide!.tlSeason1.rating, @@ -207,12 +293,14 @@ class CompareState extends State { ), CompareThingy( label: "WR %", - greenSide: theGreenSide!.tlSeason1.winrate * 100, + greenSide: + theGreenSide!.tlSeason1.winrate * 100, redSide: theRedSide!.tlSeason1.winrate * 100, fractionDigits: 2, higherIsBetter: true, ), - if (theGreenSide!.tlSeason1.gamesPlayed > 9 && theRedSide!.tlSeason1.gamesPlayed > 9) + if (theGreenSide!.tlSeason1.gamesPlayed > 9 && + theRedSide!.tlSeason1.gamesPlayed > 9) CompareThingy( label: "Glicko", greenSide: theGreenSide!.tlSeason1.glicko!, @@ -220,7 +308,8 @@ class CompareState extends State { fractionDigits: 2, higherIsBetter: true, ), - if (theGreenSide!.tlSeason1.gamesPlayed > 9 && theRedSide!.tlSeason1.gamesPlayed > 9) + if (theGreenSide!.tlSeason1.gamesPlayed > 9 && + theRedSide!.tlSeason1.gamesPlayed > 9) CompareThingy( label: "RD", greenSide: theGreenSide!.tlSeason1.rd!, @@ -228,21 +317,25 @@ class CompareState extends State { fractionDigits: 3, higherIsBetter: false, ), - if (theGreenSide!.tlSeason1.standing > 0 && theRedSide!.tlSeason1.standing > 0) + if (theGreenSide!.tlSeason1.standing > 0 && + theRedSide!.tlSeason1.standing > 0) CompareThingy( label: "№ in LB", greenSide: theGreenSide!.tlSeason1.standing, redSide: theRedSide!.tlSeason1.standing, higherIsBetter: false, ), - if (theGreenSide!.tlSeason1.standingLocal > 0 && theRedSide!.tlSeason1.standingLocal > 0) + if (theGreenSide!.tlSeason1.standingLocal > 0 && + theRedSide!.tlSeason1.standingLocal > 0) CompareThingy( label: "№ in local LB", - greenSide: theGreenSide!.tlSeason1.standingLocal, + greenSide: + theGreenSide!.tlSeason1.standingLocal, redSide: theRedSide!.tlSeason1.standingLocal, higherIsBetter: false, ), - if (theGreenSide!.tlSeason1.apm != null && theRedSide!.tlSeason1.apm != null) + if (theGreenSide!.tlSeason1.apm != null && + theRedSide!.tlSeason1.apm != null) CompareThingy( label: "APM", greenSide: theGreenSide!.tlSeason1.apm!, @@ -250,7 +343,8 @@ class CompareState extends State { fractionDigits: 2, higherIsBetter: true, ), - if (theGreenSide!.tlSeason1.pps != null && theRedSide!.tlSeason1.pps != null) + if (theGreenSide!.tlSeason1.pps != null && + theRedSide!.tlSeason1.pps != null) CompareThingy( label: "PPS", greenSide: theGreenSide!.tlSeason1.pps!, @@ -258,7 +352,8 @@ class CompareState extends State { fractionDigits: 2, higherIsBetter: true, ), - if (theGreenSide!.tlSeason1.vs != null && theRedSide!.tlSeason1.vs != null) + if (theGreenSide!.tlSeason1.vs != null && + theRedSide!.tlSeason1.vs != null) CompareThingy( label: "VS", greenSide: theGreenSide!.tlSeason1.vs!, @@ -284,7 +379,10 @@ class CompareState extends State { children: [ Padding( padding: const EdgeInsets.only(bottom: 16), - child: Text("Nerd Stats", style: TextStyle(fontFamily: "Eurostile Round Extended", fontSize: bigScreen ? 42 : 28)), + child: Text("Nerd Stats", + style: TextStyle( + fontFamily: "Eurostile Round Extended", + fontSize: bigScreen ? 42 : 28)), ), CompareThingy( label: "APP", @@ -316,14 +414,16 @@ class CompareState extends State { ), CompareThingy( label: "APP + DS/P", - greenSide: theGreenSide!.tlSeason1.nerdStats!.appdsp, + greenSide: + theGreenSide!.tlSeason1.nerdStats!.appdsp, redSide: theRedSide!.tlSeason1.nerdStats!.appdsp, fractionDigits: 3, higherIsBetter: true, ), CompareThingy( label: "Cheese", - greenSide: theGreenSide!.tlSeason1.nerdStats!.cheese, + greenSide: + theGreenSide!.tlSeason1.nerdStats!.cheese, redSide: theRedSide!.tlSeason1.nerdStats!.cheese, fractionDigits: 2, higherIsBetter: true, @@ -337,7 +437,8 @@ class CompareState extends State { ), CompareThingy( label: "Weighted APP", - greenSide: theGreenSide!.tlSeason1.nerdStats!.nyaapp, + greenSide: + theGreenSide!.tlSeason1.nerdStats!.nyaapp, redSide: theRedSide!.tlSeason1.nerdStats!.nyaapp, fractionDigits: 3, higherIsBetter: true, @@ -356,7 +457,8 @@ class CompareState extends State { fractionDigits: 2, higherIsBetter: true, ), - if (theGreenSide!.tlSeason1.gamesPlayed > 9 && theGreenSide!.tlSeason1.gamesPlayed > 9) + if (theGreenSide!.tlSeason1.gamesPlayed > 9 && + theGreenSide!.tlSeason1.gamesPlayed > 9) CompareThingy( label: "Acc. of Est.", greenSide: theGreenSide!.tlSeason1.esttracc!, @@ -372,7 +474,8 @@ class CompareState extends State { clipBehavior: Clip.hardEdge, children: [ Padding( - padding: const EdgeInsets.fromLTRB(20, 20, 20, 20), + padding: + const EdgeInsets.fromLTRB(20, 20, 20, 20), child: SizedBox( height: 300, width: 300, @@ -380,10 +483,15 @@ class CompareState extends State { RadarChartData( radarShape: RadarShape.polygon, tickCount: 4, - ticksTextStyle: const TextStyle(color: Colors.transparent, fontSize: 10), - radarBorderData: const BorderSide(color: Colors.transparent, width: 1), - gridBorderData: const BorderSide(color: Colors.white24, width: 1), - tickBorderData: const BorderSide(color: Colors.transparent, width: 1), + ticksTextStyle: const TextStyle( + color: Colors.transparent, + fontSize: 10), + radarBorderData: const BorderSide( + color: Colors.transparent, width: 1), + gridBorderData: const BorderSide( + color: Colors.white24, width: 1), + tickBorderData: const BorderSide( + color: Colors.transparent, width: 1), getTitle: (index, angle) { switch (index) { case 0: @@ -397,56 +505,132 @@ class CompareState extends State { angle: angle, ); case 2: - return RadarChartTitle(text: 'VS', angle: angle); + return RadarChartTitle( + text: 'VS', angle: angle); case 3: - return RadarChartTitle(text: 'APP', angle: angle + 180); + return RadarChartTitle( + text: 'APP', + angle: angle + 180); case 4: - return RadarChartTitle(text: 'DS/S', angle: angle + 180); + return RadarChartTitle( + text: 'DS/S', + angle: angle + 180); case 5: - return RadarChartTitle(text: 'DS/P', angle: angle + 180); + return RadarChartTitle( + text: 'DS/P', + angle: angle + 180); case 6: - return RadarChartTitle(text: 'APP+DS/P', angle: angle + 180); + return RadarChartTitle( + text: 'APP+DS/P', + angle: angle + 180); case 7: - return RadarChartTitle(text: 'VS/APM', angle: angle + 180); + return RadarChartTitle( + text: 'VS/APM', + angle: angle + 180); case 8: - return RadarChartTitle(text: 'Cheese', angle: angle); + return RadarChartTitle( + text: 'Cheese', angle: angle); case 9: - return RadarChartTitle(text: 'Gb Eff.', angle: angle); + return RadarChartTitle( + text: 'Gb Eff.', angle: angle); default: - return const RadarChartTitle(text: ''); + return const RadarChartTitle( + text: ''); } }, dataSets: [ RadarDataSet( - fillColor: const Color.fromARGB(115, 76, 175, 79), + fillColor: const Color.fromARGB( + 115, 76, 175, 79), borderColor: Colors.green, dataEntries: [ - RadarEntry(value: theGreenSide!.tlSeason1.apm! * 1), - RadarEntry(value: theGreenSide!.tlSeason1.pps! * 45), - RadarEntry(value: theGreenSide!.tlSeason1.vs! * 0.444), - RadarEntry(value: theGreenSide!.tlSeason1.nerdStats!.app * 185), - RadarEntry(value: theGreenSide!.tlSeason1.nerdStats!.dss * 175), - RadarEntry(value: theGreenSide!.tlSeason1.nerdStats!.dsp * 450), - RadarEntry(value: theGreenSide!.tlSeason1.nerdStats!.appdsp * 140), - RadarEntry(value: theGreenSide!.tlSeason1.nerdStats!.vsapm * 60), - RadarEntry(value: theGreenSide!.tlSeason1.nerdStats!.cheese * 1.25), - RadarEntry(value: theGreenSide!.tlSeason1.nerdStats!.gbe * 315), + RadarEntry( + value: theGreenSide! + .tlSeason1.apm! * + 1), + RadarEntry( + value: theGreenSide! + .tlSeason1.pps! * + 45), + RadarEntry( + value: theGreenSide! + .tlSeason1.vs! * + 0.444), + RadarEntry( + value: theGreenSide!.tlSeason1 + .nerdStats!.app * + 185), + RadarEntry( + value: theGreenSide!.tlSeason1 + .nerdStats!.dss * + 175), + RadarEntry( + value: theGreenSide!.tlSeason1 + .nerdStats!.dsp * + 450), + RadarEntry( + value: theGreenSide!.tlSeason1 + .nerdStats!.appdsp * + 140), + RadarEntry( + value: theGreenSide!.tlSeason1 + .nerdStats!.vsapm * + 60), + RadarEntry( + value: theGreenSide!.tlSeason1 + .nerdStats!.cheese * + 1.25), + RadarEntry( + value: theGreenSide!.tlSeason1 + .nerdStats!.gbe * + 315), ], ), RadarDataSet( - fillColor: const Color.fromARGB(115, 244, 67, 54), + fillColor: const Color.fromARGB( + 115, 244, 67, 54), borderColor: Colors.red, dataEntries: [ - RadarEntry(value: theRedSide!.tlSeason1.apm! * 1), - RadarEntry(value: theRedSide!.tlSeason1.pps! * 45), - RadarEntry(value: theRedSide!.tlSeason1.vs! * 0.444), - RadarEntry(value: theRedSide!.tlSeason1.nerdStats!.app * 185), - RadarEntry(value: theRedSide!.tlSeason1.nerdStats!.dss * 175), - RadarEntry(value: theRedSide!.tlSeason1.nerdStats!.dsp * 450), - RadarEntry(value: theRedSide!.tlSeason1.nerdStats!.appdsp * 140), - RadarEntry(value: theRedSide!.tlSeason1.nerdStats!.vsapm * 60), - RadarEntry(value: theRedSide!.tlSeason1.nerdStats!.cheese * 1.25), - RadarEntry(value: theRedSide!.tlSeason1.nerdStats!.gbe * 315), + RadarEntry( + value: + theRedSide!.tlSeason1.apm! * + 1), + RadarEntry( + value: + theRedSide!.tlSeason1.pps! * + 45), + RadarEntry( + value: + theRedSide!.tlSeason1.vs! * + 0.444), + RadarEntry( + value: theRedSide!.tlSeason1 + .nerdStats!.app * + 185), + RadarEntry( + value: theRedSide!.tlSeason1 + .nerdStats!.dss * + 175), + RadarEntry( + value: theRedSide!.tlSeason1 + .nerdStats!.dsp * + 450), + RadarEntry( + value: theRedSide!.tlSeason1 + .nerdStats!.appdsp * + 140), + RadarEntry( + value: theRedSide!.tlSeason1 + .nerdStats!.vsapm * + 60), + RadarEntry( + value: theRedSide!.tlSeason1 + .nerdStats!.cheese * + 1.25), + RadarEntry( + value: theRedSide!.tlSeason1 + .nerdStats!.gbe * + 315), ], ), RadarDataSet( @@ -467,13 +651,16 @@ class CompareState extends State { ) ], ), - swapAnimationDuration: const Duration(milliseconds: 150), // Optional - swapAnimationCurve: Curves.linear, // Optional + swapAnimationDuration: const Duration( + milliseconds: 150), // Optional + swapAnimationCurve: + Curves.linear, // Optional ), ), ), Padding( - padding: const EdgeInsets.fromLTRB(20, 20, 20, 20), + padding: + const EdgeInsets.fromLTRB(20, 20, 20, 20), child: SizedBox( height: 300, width: 300, @@ -481,10 +668,15 @@ class CompareState extends State { RadarChartData( radarShape: RadarShape.polygon, tickCount: 4, - ticksTextStyle: const TextStyle(color: Colors.transparent, fontSize: 10), - radarBorderData: const BorderSide(color: Colors.transparent, width: 1), - gridBorderData: const BorderSide(color: Colors.white24, width: 1), - tickBorderData: const BorderSide(color: Colors.transparent, width: 1), + ticksTextStyle: const TextStyle( + color: Colors.transparent, + fontSize: 10), + radarBorderData: const BorderSide( + color: Colors.transparent, width: 1), + gridBorderData: const BorderSide( + color: Colors.white24, width: 1), + tickBorderData: const BorderSide( + color: Colors.transparent, width: 1), getTitle: (index, angle) { switch (index) { case 0: @@ -498,32 +690,54 @@ class CompareState extends State { angle: angle, ); case 2: - return RadarChartTitle(text: 'Inf Ds', angle: angle + 180); + return RadarChartTitle( + text: 'Inf Ds', + angle: angle + 180); case 3: - return RadarChartTitle(text: 'Plonk', angle: angle); + return RadarChartTitle( + text: 'Plonk', angle: angle); default: - return const RadarChartTitle(text: ''); + return const RadarChartTitle( + text: ''); } }, dataSets: [ RadarDataSet( - fillColor: const Color.fromARGB(115, 76, 175, 79), + fillColor: const Color.fromARGB( + 115, 76, 175, 79), borderColor: Colors.green, dataEntries: [ - RadarEntry(value: theGreenSide!.tlSeason1.playstyle!.opener), - RadarEntry(value: theGreenSide!.tlSeason1.playstyle!.stride), - RadarEntry(value: theGreenSide!.tlSeason1.playstyle!.infds), - RadarEntry(value: theGreenSide!.tlSeason1.playstyle!.plonk), + RadarEntry( + value: theGreenSide!.tlSeason1 + .playstyle!.opener), + RadarEntry( + value: theGreenSide!.tlSeason1 + .playstyle!.stride), + RadarEntry( + value: theGreenSide!.tlSeason1 + .playstyle!.infds), + RadarEntry( + value: theGreenSide!.tlSeason1 + .playstyle!.plonk), ], ), RadarDataSet( - fillColor: const Color.fromARGB(115, 244, 67, 54), + fillColor: const Color.fromARGB( + 115, 244, 67, 54), borderColor: Colors.red, dataEntries: [ - RadarEntry(value: theRedSide!.tlSeason1.playstyle!.opener), - RadarEntry(value: theRedSide!.tlSeason1.playstyle!.stride), - RadarEntry(value: theRedSide!.tlSeason1.playstyle!.infds), - RadarEntry(value: theRedSide!.tlSeason1.playstyle!.plonk), + RadarEntry( + value: theRedSide!.tlSeason1 + .playstyle!.opener), + RadarEntry( + value: theRedSide!.tlSeason1 + .playstyle!.stride), + RadarEntry( + value: theRedSide!.tlSeason1 + .playstyle!.infds), + RadarEntry( + value: theRedSide!.tlSeason1 + .playstyle!.plonk), ], ), RadarDataSet( @@ -548,22 +762,33 @@ class CompareState extends State { ) ], ), - swapAnimationDuration: const Duration(milliseconds: 150), // Optional - swapAnimationCurve: Curves.linear, // Optional + swapAnimationDuration: const Duration( + milliseconds: 150), // Optional + swapAnimationCurve: + Curves.linear, // Optional ), ), ), const Divider(), Padding( padding: const EdgeInsets.only(bottom: 16), - child: Text("Win Chance", style: TextStyle(fontFamily: "Eurostile Round Extended", fontSize: bigScreen ? 42 : 28)), + child: Text("Win Chance", + style: TextStyle( + fontFamily: "Eurostile Round Extended", + fontSize: bigScreen ? 42 : 28)), ), CompareThingy( label: "By Glicko", - greenSide: getWinrateByTR(theGreenSide!.tlSeason1.glicko!, theGreenSide!.tlSeason1.rd!, theRedSide!.tlSeason1.glicko!, + greenSide: getWinrateByTR( + theGreenSide!.tlSeason1.glicko!, + theGreenSide!.tlSeason1.rd!, + theRedSide!.tlSeason1.glicko!, theRedSide!.tlSeason1.rd!) * 100, - redSide: getWinrateByTR(theRedSide!.tlSeason1.glicko!, theRedSide!.tlSeason1.rd!, theGreenSide!.tlSeason1.glicko!, + redSide: getWinrateByTR( + theRedSide!.tlSeason1.glicko!, + theRedSide!.tlSeason1.rd!, + theGreenSide!.tlSeason1.glicko!, theGreenSide!.tlSeason1.rd!) * 100, fractionDigits: 2, @@ -584,9 +809,15 @@ class CompareState extends State { class PlayerSelector extends StatelessWidget { final TetrioPlayer? player; + final List>? states; + final Function fetch; final Function change; final Function updateState; - const PlayerSelector({super.key, required this.player, required this.change, required this.updateState}); + const PlayerSelector( + {super.key, + required this.player, + required this.updateState, + required this.fetch, this.states, required this.change, }); @override Widget build(BuildContext context) { @@ -601,9 +832,9 @@ class PlayerSelector extends StatelessWidget { controller: playerController, decoration: const InputDecoration(counter: Offstage()), onSubmitted: (String value) { - change(value); + fetch(value); }), - if (player != null) + if (player != null && states == null) Text( player!.toString(), style: const TextStyle( @@ -620,7 +851,16 @@ class PlayerSelector extends StatelessWidget { ), ], ), - ) + ), + if (player != null && states != null) + Padding( + padding: const EdgeInsets.only(bottom: 8.0), + child: DropdownButton( + items: states, + value: player, + onChanged: (value) => change(value!), + ), + ) ], ); } @@ -632,7 +872,13 @@ class CompareThingy extends StatelessWidget { final String label; final bool higherIsBetter; final int? fractionDigits; - const CompareThingy({super.key, required this.greenSide, required this.redSide, required this.label, required this.higherIsBetter, this.fractionDigits}); + const CompareThingy( + {super.key, + required this.greenSide, + required this.redSide, + required this.label, + required this.higherIsBetter, + this.fractionDigits}); String verdict(num greenSide, num redSide, int fraction) { var f = NumberFormat("+#,###.##;-#,###.##"); @@ -696,7 +942,8 @@ class CompareThingy extends StatelessWidget { textAlign: TextAlign.center, ), Text( - verdict(greenSide, redSide, fractionDigits != null ? fractionDigits! + 2 : 0), + verdict(greenSide, redSide, + fractionDigits != null ? fractionDigits! + 2 : 0), style: const TextStyle(fontSize: 16), textAlign: TextAlign.center, ) @@ -752,7 +999,12 @@ class CompareBoolThingy extends StatelessWidget { final bool redSide; final String label; final bool trueIsBetter; - const CompareBoolThingy({super.key, required this.greenSide, required this.redSide, required this.label, required this.trueIsBetter}); + const CompareBoolThingy( + {super.key, + required this.greenSide, + required this.redSide, + required this.label, + required this.trueIsBetter}); @override Widget build(BuildContext context) { @@ -861,7 +1113,12 @@ class CompareDurationThingy extends StatelessWidget { final Duration redSide; final String label; final bool higherIsBetter; - const CompareDurationThingy({super.key, required this.greenSide, required this.redSide, required this.label, required this.higherIsBetter}); + const CompareDurationThingy( + {super.key, + required this.greenSide, + required this.redSide, + required this.label, + required this.higherIsBetter}); Duration verdict(Duration greenSide, Duration redSide) { return greenSide - redSide; @@ -927,12 +1184,18 @@ class CompareRegTimeThingy extends StatelessWidget { final DateTime? redSide; final String label; final int? fractionDigits; - const CompareRegTimeThingy({super.key, required this.greenSide, required this.redSide, required this.label, this.fractionDigits}); + const CompareRegTimeThingy( + {super.key, + required this.greenSide, + required this.redSide, + required this.label, + this.fractionDigits}); String verdict(DateTime? greenSide, DateTime? redSide) { var f = NumberFormat("#,### days later;#,### days before"); String result = "---"; - if (greenSide != null && redSide != null) result = f.format(greenSide.difference(redSide).inDays); + if (greenSide != null && redSide != null) + result = f.format(greenSide.difference(redSide).inDays); return result; } diff --git a/lib/views/main_view.dart b/lib/views/main_view.dart index 72bebc5..a353a60 100644 --- a/lib/views/main_view.dart +++ b/lib/views/main_view.dart @@ -18,7 +18,6 @@ const allowedHeightForPlayerIdInPixels = 40.0; const allowedHeightForPlayerBioInPixels = 30.0; const givenTextHeightByScreenPercentage = 0.3; final NumberFormat timeInSec = NumberFormat("#,###.###s."); -final DateFormat dateFormat = DateFormat.yMMMd().add_Hms(); class MainView extends StatefulWidget { const MainView({Key? key}) : super(key: key); diff --git a/lib/widgets/user_thingy.dart b/lib/widgets/user_thingy.dart index cfe9ee6..0c7de58 100644 --- a/lib/widgets/user_thingy.dart +++ b/lib/widgets/user_thingy.dart @@ -30,6 +30,7 @@ class UserThingy extends StatelessWidget { bool bigScreen = constraints.maxWidth > 768; double bannerHeight = bigScreen ? 240 : 120; double pfpHeight = 128; + return Column( children: [ Flex(