From b72d47e20238b31a2dac01f937c4933b3682933a Mon Sep 17 00:00:00 2001 From: dan63047 Date: Mon, 12 Jun 2023 00:56:15 +0300 Subject: [PATCH] Now it's possible to compare players Also upadted dependencies --- lib/data_objects/tetrio.dart | 4 +- lib/main.dart | 15 +- lib/services/tetrio_crud.dart | 8 - lib/views/compare_view.dart | 625 +++++++++++++++++++++++++++- lib/views/main_view.dart | 24 +- lib/views/state_view.dart | 9 +- lib/views/tracked_players_view.dart | 9 +- lib/widgets/stat_sell_num.dart | 2 +- lib/widgets/tl_thingy.dart | 2 - lib/widgets/user_thingy.dart | 23 +- pubspec.lock | 32 +- pubspec.yaml | 1 + 12 files changed, 676 insertions(+), 78 deletions(-) diff --git a/lib/data_objects/tetrio.dart b/lib/data_objects/tetrio.dart index 47ef9b6..505b8ff 100644 --- a/lib/data_objects/tetrio.dart +++ b/lib/data_objects/tetrio.dart @@ -73,7 +73,7 @@ class TetrioPlayer { double get level => pow((xp / 500), 0.6) + (xp / (5000 + (max(0, xp - 4 * pow(10, 6)) / 5000))) + 1; TetrioPlayer.fromJson(Map json, DateTime stateTime, bool fetchRecords) { - developer.log("TetrioPlayer.fromJson $stateTime: $json", name: "data_objects/tetrio"); + //developer.log("TetrioPlayer.fromJson $stateTime: $json", name: "data_objects/tetrio"); userId = json['_id']; username = json['username']; state = stateTime; @@ -144,7 +144,7 @@ class TetrioPlayer { data['friend_count'] = friendCount; if (badstanding != null) data['badstanding'] = badstanding; if (botmaster != null) data['botmaster'] = botmaster; - developer.log("TetrioPlayer.toJson: $data", name: "data_objects/tetrio"); + //developer.log("TetrioPlayer.toJson: $data", name: "data_objects/tetrio"); return data; } diff --git a/lib/main.dart b/lib/main.dart index f3039ab..88c92a0 100644 --- a/lib/main.dart +++ b/lib/main.dart @@ -1,22 +1,19 @@ +import 'dart:io'; import 'package:flutter/material.dart'; import 'package:sqflite_common_ffi/sqflite_ffi.dart'; import 'package:tetra_stats/views/main_view.dart'; -import 'package:tetra_stats/views/compare_view.dart'; import 'package:tetra_stats/views/settings_view.dart'; import 'package:tetra_stats/views/tracked_players_view.dart'; import 'package:tetra_stats/views/calc_view.dart'; void main() { - sqfliteFfiInit(); - databaseFactory = databaseFactoryFfi; + if (Platform.isWindows || Platform.isLinux || Platform.isMacOS) { + sqfliteFfiInit(); + databaseFactory = databaseFactoryFfi; + } runApp(MaterialApp( home: const MainView(), - routes: { - "/settings": (context) => const SettingsView(), - "/compare": (context) => const CompareView(), - "/states": (context) => const TrackedPlayersView(), - "/calc": (context) => const CalcView() - }, + routes: {"/settings": (context) => const SettingsView(), "/states": (context) => const TrackedPlayersView(), "/calc": (context) => const CalcView()}, theme: ThemeData( fontFamily: 'Eurostile Round', colorScheme: const ColorScheme.dark(primary: Colors.cyanAccent, secondary: Colors.purpleAccent), diff --git a/lib/services/tetrio_crud.dart b/lib/services/tetrio_crud.dart index d894046..21d8f4b 100644 --- a/lib/services/tetrio_crud.dart +++ b/lib/services/tetrio_crud.dart @@ -189,14 +189,6 @@ class TetrioService extends DB { } } - // Future _ensureDbIsOpen() async { - // try { - // await open(); - // } on DatabaseAlreadyOpen { - // // empty - // } - // } - Future>>> getAllPlayers() async { await ensureDbIsOpen(); final db = getDatabaseOrThrow(); diff --git a/lib/views/compare_view.dart b/lib/views/compare_view.dart index 3dfad8f..f2b5b5d 100644 --- a/lib/views/compare_view.dart +++ b/lib/views/compare_view.dart @@ -1,31 +1,632 @@ +import 'package:fl_chart/fl_chart.dart'; import 'package:flutter/material.dart'; +import 'package:intl/intl.dart'; +import 'package:tetra_stats/data_objects/tetrio.dart'; +import 'package:tetra_stats/services/tetrio_crud.dart'; + +TetrioPlayer? theGreenSide; +TetrioPlayer? theRedSide; +final TetrioService teto = TetrioService(); class CompareView extends StatefulWidget { - const CompareView({Key? key}) : super(key: key); + final TetrioPlayer greenSide; + final TetrioPlayer? redSide; + const CompareView({Key? key, required this.greenSide, required this.redSide}) : super(key: key); @override State createState() => CompareState(); } class CompareState extends State { + late ScrollController _scrollController; + + @override + void initState() { + theGreenSide = widget.greenSide; + theRedSide = widget.redSide; + _scrollController = ScrollController(); + super.initState(); + } + + void fetchRedSide(String user) async { + try { + theRedSide = await teto.fetchPlayer(user, false); + } on Exception { + ScaffoldMessenger.of(context).showSnackBar(SnackBar(content: Text("Falied to assign $user"))); + } + setState(() {}); + } + + void fetchGreenSide(String user) async { + try { + theGreenSide = await teto.fetchPlayer(user, false); + } on Exception { + ScaffoldMessenger.of(context).showSnackBar(SnackBar(content: Text("Falied to assign $user"))); + } + setState(() {}); + } + + void _justUpdate() { + setState(() {}); + } + @override Widget build(BuildContext context) { + bool bigScreen = MediaQuery.of(context).size.width > 768; return Scaffold( appBar: AppBar( - title: const Text("you vs someone"), + title: Text( + "${theGreenSide != null ? theGreenSide!.username.toUpperCase() : "???"} vs ${theRedSide != null ? theRedSide!.username.toUpperCase() : "???"}"), ), backgroundColor: Colors.black, body: SafeArea( - child: ListView( - children: const [ - ListTile( - title: Center(child: Text("So thats gonna be the main purpose of the app")), - subtitle: Center(child: Text("We gonna look who is the best")), - trailing: Text("Opponent value"), - leading: Text("Your value"), - ) - ], - )), + child: NestedScrollView( + controller: _scrollController, + headerSliverBuilder: (context, value) { + return [ + SliverToBoxAdapter( + child: Padding( + padding: const EdgeInsets.fromLTRB(16, 16, 16, 32), + child: Row( + mainAxisAlignment: MainAxisAlignment.spaceBetween, + crossAxisAlignment: CrossAxisAlignment.start, + children: [ + Expanded( + child: Padding( + padding: const EdgeInsets.fromLTRB(8, 0, 8, 0), + child: PlayerSelector(player: theGreenSide, change: fetchGreenSide, updateState: _justUpdate), + ), + ), + const Padding( + padding: EdgeInsets.only(top: 16), + child: Text("VS"), + ), + Expanded( + child: Padding( + padding: const EdgeInsets.fromLTRB(8, 0, 8, 0), + child: PlayerSelector(player: theRedSide, change: fetchRedSide, updateState: _justUpdate), + ), + ), + ], + ), + ), + ), + const SliverToBoxAdapter( + child: Divider(), + ) + ]; + }, + body: theGreenSide != null && theRedSide != null + ? ListView( + children: [ + CompareThingy( + label: "Level", + greenSide: theGreenSide!.level, + redSide: theRedSide!.level, + higherIsBetter: true, + fractionDigits: 2, + ), + 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) + CompareThingy( + label: "Games Won", + greenSide: theGreenSide!.gamesWon, + redSide: theRedSide!.gamesWon, + higherIsBetter: true, + ), + CompareThingy( + label: "Friends", + greenSide: theGreenSide!.friendCount, + redSide: theRedSide!.friendCount, + higherIsBetter: true, + ), + const Divider(), + 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)), + ), + if (theGreenSide!.tlSeason1.gamesPlayed > 9 && theRedSide!.tlSeason1.gamesPlayed > 9) + CompareThingy( + label: "TR", + greenSide: theGreenSide!.tlSeason1.rating, + redSide: theRedSide!.tlSeason1.rating, + fractionDigits: 2, + higherIsBetter: true, + ), + CompareThingy( + label: "Games Played", + greenSide: theGreenSide!.tlSeason1.gamesPlayed, + redSide: theRedSide!.tlSeason1.gamesPlayed, + higherIsBetter: true, + ), + CompareThingy( + label: "Games Won", + greenSide: theGreenSide!.tlSeason1.gamesWon, + redSide: theRedSide!.tlSeason1.gamesWon, + higherIsBetter: true, + ), + CompareThingy( + label: "WR %", + greenSide: theGreenSide!.tlSeason1.winrate * 100, + redSide: theRedSide!.tlSeason1.winrate * 100, + fractionDigits: 2, + higherIsBetter: true, + ), + if (theGreenSide!.tlSeason1.gamesPlayed > 9 && theRedSide!.tlSeason1.gamesPlayed > 9) + CompareThingy( + label: "Glicko", + greenSide: theGreenSide!.tlSeason1.glicko!, + redSide: theRedSide!.tlSeason1.glicko!, + fractionDigits: 2, + higherIsBetter: true, + ), + if (theGreenSide!.tlSeason1.gamesPlayed > 9 && theRedSide!.tlSeason1.gamesPlayed > 9) + CompareThingy( + label: "RD", + greenSide: theGreenSide!.tlSeason1.rd!, + redSide: theRedSide!.tlSeason1.rd!, + fractionDigits: 3, + higherIsBetter: false, + ), + 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) + CompareThingy( + label: "№ in local LB", + greenSide: theGreenSide!.tlSeason1.standingLocal, + redSide: theRedSide!.tlSeason1.standingLocal, + higherIsBetter: false, + ), + if (theGreenSide!.tlSeason1.apm != null && theRedSide!.tlSeason1.apm != null) + CompareThingy( + label: "APM", + greenSide: theGreenSide!.tlSeason1.apm!, + redSide: theRedSide!.tlSeason1.apm!, + fractionDigits: 2, + higherIsBetter: true, + ), + if (theGreenSide!.tlSeason1.pps != null && theRedSide!.tlSeason1.pps != null) + CompareThingy( + label: "PPS", + greenSide: theGreenSide!.tlSeason1.pps!, + redSide: theRedSide!.tlSeason1.pps!, + fractionDigits: 2, + higherIsBetter: true, + ), + if (theGreenSide!.tlSeason1.vs != null && theRedSide!.tlSeason1.vs != null) + CompareThingy( + label: "VS", + greenSide: theGreenSide!.tlSeason1.vs!, + redSide: theRedSide!.tlSeason1.vs!, + fractionDigits: 2, + higherIsBetter: true, + ), + ], + ) + : Padding( + padding: const EdgeInsets.fromLTRB(16, 2, 16, 2), + child: Row(children: [ + Expanded( + child: Text( + theGreenSide!.tlSeason1.gamesPlayed > 0 ? "Yes" : "No", + style: const TextStyle(fontSize: 22), + textAlign: TextAlign.start, + )), + Column( + children: const [ + Text( + "Played Tetra League", + style: TextStyle(fontSize: 22), + textAlign: TextAlign.center, + ), + Text( + "---", + style: TextStyle(fontSize: 16), + textAlign: TextAlign.center, + ) + ], + ), + Expanded( + child: Text( + theRedSide!.tlSeason1.gamesPlayed > 0 ? "Yes" : "No", + style: const TextStyle(fontSize: 22), + textAlign: TextAlign.end, + )), + ]), + ), + const Divider(), + if (theGreenSide!.tlSeason1.apm != null && + theRedSide!.tlSeason1.apm != null && + theGreenSide!.tlSeason1.pps != null && + theRedSide!.tlSeason1.pps != null && + theGreenSide!.tlSeason1.vs != null && + theRedSide!.tlSeason1.vs != null) + Column( + children: [ + Padding( + padding: const EdgeInsets.only(bottom: 16), + child: Text("Nerd Stats", style: TextStyle(fontFamily: "Eurostile Round Extended", fontSize: bigScreen ? 42 : 28)), + ), + CompareThingy( + label: "APP", + greenSide: theGreenSide!.tlSeason1.nerdStats!.app, + redSide: theRedSide!.tlSeason1.nerdStats!.app, + fractionDigits: 3, + higherIsBetter: true, + ), + CompareThingy( + label: "VS/APM", + greenSide: theGreenSide!.tlSeason1.nerdStats!.vsapm, + redSide: theRedSide!.tlSeason1.nerdStats!.vsapm, + fractionDigits: 3, + higherIsBetter: true, + ), + CompareThingy( + label: "DS/S", + greenSide: theGreenSide!.tlSeason1.nerdStats!.dss, + redSide: theRedSide!.tlSeason1.nerdStats!.dss, + fractionDigits: 3, + higherIsBetter: true, + ), + CompareThingy( + label: "DS/P", + greenSide: theGreenSide!.tlSeason1.nerdStats!.dsp, + redSide: theRedSide!.tlSeason1.nerdStats!.dsp, + fractionDigits: 3, + higherIsBetter: true, + ), + CompareThingy( + label: "APP + DS/P", + greenSide: theGreenSide!.tlSeason1.nerdStats!.appdsp, + redSide: theRedSide!.tlSeason1.nerdStats!.appdsp, + fractionDigits: 3, + higherIsBetter: true, + ), + CompareThingy( + label: "Cheese", + greenSide: theGreenSide!.tlSeason1.nerdStats!.cheese, + redSide: theRedSide!.tlSeason1.nerdStats!.cheese, + fractionDigits: 2, + higherIsBetter: true, + ), + CompareThingy( + label: "Garbage Eff.", + greenSide: theGreenSide!.tlSeason1.nerdStats!.gbe, + redSide: theRedSide!.tlSeason1.nerdStats!.gbe, + fractionDigits: 3, + higherIsBetter: true, + ), + CompareThingy( + label: "Weighted APP", + greenSide: theGreenSide!.tlSeason1.nerdStats!.nyaapp, + redSide: theRedSide!.tlSeason1.nerdStats!.nyaapp, + fractionDigits: 3, + higherIsBetter: true, + ), + CompareThingy( + label: "Area", + greenSide: theGreenSide!.tlSeason1.nerdStats!.area, + redSide: theRedSide!.tlSeason1.nerdStats!.area, + fractionDigits: 2, + higherIsBetter: true, + ), + CompareThingy( + label: "Est. of TR", + greenSide: theGreenSide!.tlSeason1.estTr!.esttr, + redSide: theRedSide!.tlSeason1.estTr!.esttr, + fractionDigits: 2, + higherIsBetter: true, + ), + if (theGreenSide!.tlSeason1.gamesPlayed > 9 && theGreenSide!.tlSeason1.gamesPlayed > 9) + CompareThingy( + label: "Acc. of Est.", + greenSide: theGreenSide!.tlSeason1.esttracc!, + redSide: theRedSide!.tlSeason1.esttracc!, + fractionDigits: 2, + higherIsBetter: true, + ), + Wrap( + direction: Axis.horizontal, + alignment: WrapAlignment.spaceAround, + spacing: 25, + crossAxisAlignment: WrapCrossAlignment.start, + clipBehavior: Clip.hardEdge, + children: [ + Padding( + padding: const EdgeInsets.fromLTRB(20, 20, 20, 20), + child: SizedBox( + height: 300, + width: 300, + child: RadarChart( + 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), + getTitle: (index, angle) { + switch (index) { + case 0: + return RadarChartTitle( + text: 'APM', + angle: angle, + ); + case 1: + return RadarChartTitle( + text: 'PPS', + angle: angle, + ); + case 2: + return RadarChartTitle(text: 'VS', angle: angle); + case 3: + return RadarChartTitle(text: 'APP', angle: angle + 180); + case 4: + return RadarChartTitle(text: 'DS/S', angle: angle + 180); + case 5: + return RadarChartTitle(text: 'DS/P', angle: angle + 180); + case 6: + return RadarChartTitle(text: 'APP+DS/P', angle: angle + 180); + case 7: + return RadarChartTitle(text: 'VS/APM', angle: angle + 180); + case 8: + return RadarChartTitle(text: 'Cheese', angle: angle); + case 9: + return RadarChartTitle(text: 'Gb Eff.', angle: angle); + default: + return const RadarChartTitle(text: ''); + } + }, + dataSets: [ + RadarDataSet( + fillColor: const Color.fromARGB(117, 105, 240, 175), + borderColor: Colors.greenAccent, + 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), + ], + ), + RadarDataSet( + fillColor: const Color.fromARGB(117, 255, 82, 82), + borderColor: Colors.redAccent, + 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), + ], + ), + RadarDataSet( + fillColor: Colors.transparent, + borderColor: Colors.transparent, + dataEntries: [ + const RadarEntry(value: 0), + const RadarEntry(value: 0), + const RadarEntry(value: 0), + const RadarEntry(value: 0), + const RadarEntry(value: 0), + const RadarEntry(value: 0), + const RadarEntry(value: 0), + const RadarEntry(value: 0), + const RadarEntry(value: 0), + const RadarEntry(value: 0), + ], + ) + ], + ), + swapAnimationDuration: const Duration(milliseconds: 150), // Optional + swapAnimationCurve: Curves.linear, // Optional + ), + ), + ), + Padding( + padding: const EdgeInsets.fromLTRB(20, 20, 20, 20), + child: SizedBox( + height: 300, + width: 300, + child: RadarChart( + 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), + getTitle: (index, angle) { + switch (index) { + case 0: + return RadarChartTitle( + text: 'Opener', + angle: angle, + ); + case 1: + return RadarChartTitle( + text: 'Stride', + angle: angle, + ); + case 2: + return RadarChartTitle(text: 'Inf Ds', angle: angle + 180); + case 3: + return RadarChartTitle(text: 'Plonk', angle: angle); + default: + return const RadarChartTitle(text: ''); + } + }, + dataSets: [ + RadarDataSet( + fillColor: const Color.fromARGB(117, 105, 240, 175), + borderColor: Colors.greenAccent, + 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), + ], + ), + RadarDataSet( + fillColor: const Color.fromARGB(117, 255, 82, 82), + borderColor: Colors.redAccent, + 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), + ], + ), + RadarDataSet( + fillColor: Colors.transparent, + borderColor: Colors.transparent, + dataEntries: [ + const RadarEntry(value: 0), + const RadarEntry(value: 0), + const RadarEntry(value: 0), + const RadarEntry(value: 0), + ], + ), + RadarDataSet( + fillColor: Colors.transparent, + borderColor: Colors.transparent, + dataEntries: [ + const RadarEntry(value: 1), + const RadarEntry(value: 1), + const RadarEntry(value: 1), + const RadarEntry(value: 1), + ], + ) + ], + ), + 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)), + ), + ], + ) + ], + ) + ], + ) + : const Text("Please enter valid nicknames"), + ), + ), + ); + } +} + +class PlayerSelector extends StatelessWidget { + final TetrioPlayer? player; + final Function change; + final Function updateState; + const PlayerSelector({super.key, required this.player, required this.change, required this.updateState}); + + @override + Widget build(BuildContext context) { + final TextEditingController playerController = TextEditingController(); + if (player != null) playerController.text = player!.username; + return Column( + children: [ + TextField( + autocorrect: false, + enableSuggestions: false, + maxLength: 25, + controller: playerController, + decoration: const InputDecoration(counter: Offstage()), + onSubmitted: (String value) { + change(value); + }, + ), + if (player != null) Text(player!.toString()) + ], + ); + } +} + +class CompareThingy extends StatelessWidget { + final num greenSide; + final num redSide; + 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}); + + String verdict(num greenSide, num redSide, int fraction) { + var f = NumberFormat("+#,###.##;-#,###.##"); + f.maximumFractionDigits = fraction; + return f.format((greenSide - redSide)); + } + + @override + Widget build(BuildContext context) { + var f = NumberFormat("#,###.##"); + f.maximumFractionDigits = fractionDigits ?? 0; + return Padding( + padding: const EdgeInsets.fromLTRB(16, 2, 16, 2), + child: Row( + mainAxisAlignment: MainAxisAlignment.center, + children: [ + Expanded( + child: Text( + f.format(greenSide), + style: const TextStyle( + fontSize: 22, + ), + textAlign: TextAlign.start, + )), + Column( + children: [ + Text( + label, + style: const TextStyle(fontSize: 22), + textAlign: TextAlign.center, + ), + Text( + verdict(greenSide, redSide, fractionDigits != null ? fractionDigits! + 2 : 0), + style: const TextStyle(fontSize: 16), + textAlign: TextAlign.center, + ) + ], + ), + Expanded( + child: Text( + f.format(redSide), + style: const TextStyle(fontSize: 22), + textAlign: TextAlign.end, + )), + ], + ), ); } } diff --git a/lib/views/main_view.dart b/lib/views/main_view.dart index 7864864..6926030 100644 --- a/lib/views/main_view.dart +++ b/lib/views/main_view.dart @@ -46,6 +46,8 @@ class _MainState extends State with SingleTickerProviderStateMixin { Widget _searchTextField() { return TextField( maxLength: 25, + autocorrect: false, + enableSuggestions: false, decoration: const InputDecoration(counter: Offstage()), style: const TextStyle( shadows: [ @@ -178,17 +180,17 @@ class _MainState extends State with SingleTickerProviderStateMixin { developer.log("builder ($context): $snapshot", name: "main_view"); switch (snapshot.connectionState) { case ConnectionState.none: - return Center( + return const Center( child: Text('none case of FutureBuilder', - style: const TextStyle(fontFamily: "Eurostile Round Extended", fontSize: 42), textAlign: TextAlign.center)); + style: TextStyle(fontFamily: "Eurostile Round Extended", fontSize: 42), textAlign: TextAlign.center)); case ConnectionState.waiting: return const Center(child: CircularProgressIndicator(color: Colors.white)); case ConnectionState.active: - return Center( + return const Center( child: Text('active case of FutureBuilder', - style: const TextStyle(fontFamily: "Eurostile Round Extended", fontSize: 42), textAlign: TextAlign.center)); + style: TextStyle(fontFamily: "Eurostile Round Extended", fontSize: 42), textAlign: TextAlign.center)); case ConnectionState.done: - bool bigScreen = MediaQuery.of(context).size.width > 1024; + //bool bigScreen = MediaQuery.of(context).size.width > 1024; if (snapshot.hasData) { if (_searchFor.length > 16) _searchFor = snapshot.data!.username; teto.isPlayerTracking(snapshot.data!.userId).then((value) { @@ -235,12 +237,12 @@ class _MainState extends State with SingleTickerProviderStateMixin { } break; default: - return Center( + return const Center( child: Text('default case of FutureBuilder', - style: const TextStyle(fontFamily: "Eurostile Round Extended", fontSize: 42), textAlign: TextAlign.center)); + style: TextStyle(fontFamily: "Eurostile Round Extended", fontSize: 42), textAlign: TextAlign.center)); } - return Center( - child: Text('end of FutureBuilder', style: const TextStyle(fontFamily: "Eurostile Round Extended", fontSize: 42), textAlign: TextAlign.center)); + return const Center( + child: Text('end of FutureBuilder', style: TextStyle(fontFamily: "Eurostile Round Extended", fontSize: 42), textAlign: TextAlign.center)); }, ), ), @@ -294,7 +296,7 @@ class _NavDrawerState extends State { builder: (context, snapshot) { switch (snapshot.connectionState) { case ConnectionState.none: - return Center(child: Text('none case of StreamBuilder')); + return const Center(child: Text('none case of StreamBuilder')); case ConnectionState.waiting: case ConnectionState.active: final allPlayers = (snapshot.data != null) ? snapshot.data as Map> : >{}; @@ -334,7 +336,7 @@ class _NavDrawerState extends State { ); })); case ConnectionState.done: - return Center(child: Text('done case of StreamBuilder')); + return const Center(child: Text('done case of StreamBuilder')); } }, ), diff --git a/lib/views/state_view.dart b/lib/views/state_view.dart index 7804372..5018d09 100644 --- a/lib/views/state_view.dart +++ b/lib/views/state_view.dart @@ -35,14 +35,7 @@ class StateState extends State { child: NestedScrollView( controller: _scrollController, headerSliverBuilder: (context, value) { - return [ - SliverToBoxAdapter( - child: UserThingy( - player: widget.state, - showStateTimestamp: true, - setState: _justUpdate, - )) - ]; + return [SliverToBoxAdapter(child: UserThingy(player: widget.state, showStateTimestamp: true, setState: _justUpdate))]; }, body: TLThingy(tl: widget.state.tlSeason1, userID: widget.state.userId)))); } diff --git a/lib/views/tracked_players_view.dart b/lib/views/tracked_players_view.dart index 130a760..bcddaf9 100644 --- a/lib/views/tracked_players_view.dart +++ b/lib/views/tracked_players_view.dart @@ -26,12 +26,11 @@ class TrackedPlayersState extends State { builder: (context, snapshot) { switch (snapshot.connectionState) { case ConnectionState.none: - return Center(child: Text('none case of StreamBuilder')); + return const Center(child: Text('none case of StreamBuilder')); case ConnectionState.waiting: case ConnectionState.active: final allPlayers = (snapshot.data != null) ? snapshot.data as Map> : >{}; List keys = allPlayers.keys.toList(); - print(allPlayers.toString()); return NestedScrollView( headerSliverBuilder: (context, value) { return [ @@ -40,7 +39,7 @@ class TrackedPlayersState extends State { padding: const EdgeInsets.only(left: 16), child: Text( 'There are ${allPlayers.length} players', - style: TextStyle(color: Colors.white, fontSize: 25), + style: const TextStyle(color: Colors.white, fontSize: 25), ), )), const SliverToBoxAdapter(child: Divider()) @@ -67,9 +66,9 @@ class TrackedPlayersState extends State { ); })); case ConnectionState.done: - return Center( + return const Center( child: Text('done case of StreamBuilder', - style: const TextStyle(fontFamily: "Eurostile Round Extended", fontSize: 42), textAlign: TextAlign.center)); + style: TextStyle(fontFamily: "Eurostile Round Extended", fontSize: 42), textAlign: TextAlign.center)); } })), ); diff --git a/lib/widgets/stat_sell_num.dart b/lib/widgets/stat_sell_num.dart index 6489211..ff55952 100644 --- a/lib/widgets/stat_sell_num.dart +++ b/lib/widgets/stat_sell_num.dart @@ -1,7 +1,7 @@ import 'package:flutter/material.dart'; class StatCellNum extends StatelessWidget { - const StatCellNum({required this.playerStat, required this.playerStatLabel, required this.isScreenBig, this.snackBar, this.fractionDigits}); + const StatCellNum({super.key, required this.playerStat, required this.playerStatLabel, required this.isScreenBig, this.snackBar, this.fractionDigits}); final num playerStat; final String playerStatLabel; diff --git a/lib/widgets/tl_thingy.dart b/lib/widgets/tl_thingy.dart index a030ca8..bb3f28c 100644 --- a/lib/widgets/tl_thingy.dart +++ b/lib/widgets/tl_thingy.dart @@ -1,7 +1,5 @@ import 'package:flutter/material.dart'; -import 'package:flutter/services.dart'; import 'package:tetra_stats/data_objects/tetrio.dart'; -import 'dart:developer' as developer; import 'package:fl_chart/fl_chart.dart'; import 'package:tetra_stats/widgets/stat_sell_num.dart'; diff --git a/lib/widgets/user_thingy.dart b/lib/widgets/user_thingy.dart index 20250d2..f45833a 100644 --- a/lib/widgets/user_thingy.dart +++ b/lib/widgets/user_thingy.dart @@ -1,7 +1,7 @@ import 'package:flutter/material.dart'; import 'package:flutter/services.dart'; import 'package:tetra_stats/data_objects/tetrio.dart'; -import 'package:tetra_stats/views/tracked_players_view.dart'; +import 'package:tetra_stats/views/compare_view.dart'; import 'dart:developer' as developer; import 'package:tetra_stats/widgets/stat_sell_num.dart'; @@ -116,27 +116,27 @@ class UserThingy extends StatelessWidget { return Column( children: [ IconButton( - icon: Icon(Icons.person_remove), + icon: const Icon(Icons.person_remove), onPressed: () { teto.deletePlayerToTrack(player.userId).then((value) => setState()); ScaffoldMessenger.of(context).showSnackBar(const SnackBar(content: Text("Removed from tracking list!"))); }, ), - Text("Stop tracking") + const Text("Stop tracking") ], ); } else { return Column( children: [ IconButton( - icon: Icon(Icons.person_add), + icon: const Icon(Icons.person_add), onPressed: () { teto.addPlayerToTrack(player).then((value) => setState()); teto.storeState(player); ScaffoldMessenger.of(context).showSnackBar(const SnackBar(content: Text("Added to tracking list!"))); }, ), - Text("Track") + const Text("Track") ], ); } @@ -145,10 +145,17 @@ class UserThingy extends StatelessWidget { Column( children: [ IconButton( - icon: Icon(Icons.balance), - onPressed: () {}, + icon: const Icon(Icons.balance), + onPressed: () { + Navigator.push( + context, + MaterialPageRoute( + builder: (context) => CompareView(greenSide: player, redSide: null), + ), + ); + }, ), - Text("Compare") + const Text("Compare") ], ) ]), diff --git a/pubspec.lock b/pubspec.lock index 8192e10..3c404eb 100644 --- a/pubspec.lock +++ b/pubspec.lock @@ -128,6 +128,14 @@ packages: url: "https://pub.dev" source: hosted version: "4.0.2" + intl: + dependency: "direct main" + description: + name: intl + sha256: "3bc132a9dbce73a7e4a21a17d06e1878839ffbf975568bc875c60537824b0c4d" + url: "https://pub.dev" + source: hosted + version: "0.18.1" js: dependency: transitive description: @@ -220,10 +228,10 @@ packages: dependency: transitive description: name: path_provider_linux - sha256: "2ae08f2216225427e64ad224a24354221c2c7907e448e6e0e8b57b1eb9f10ad1" + sha256: ffbb8cc9ed2c9ec0e4b7a541e56fd79b138e8f47d2fb86815f15358a349b3b57 url: "https://pub.dev" source: hosted - version: "2.1.10" + version: "2.1.11" path_provider_platform_interface: dependency: transitive description: @@ -236,10 +244,10 @@ packages: dependency: transitive description: name: path_provider_windows - sha256: d3f80b32e83ec208ac95253e0cd4d298e104fbc63cb29c5c69edaed43b0c69d6 + sha256: "1cb68ba4cd3a795033de62ba1b7b4564dace301f952de6bfb3cd91b202b6ee96" url: "https://pub.dev" source: hosted - version: "2.1.6" + version: "2.1.7" platform: dependency: transitive description: @@ -268,10 +276,10 @@ packages: dependency: "direct main" description: name: shared_preferences - sha256: "16d3fb6b3692ad244a695c0183fca18cf81fd4b821664394a781de42386bf022" + sha256: "396f85b8afc6865182610c0a2fc470853d56499f75f7499e2a73a9f0539d23d0" url: "https://pub.dev" source: hosted - version: "2.1.1" + version: "2.1.2" shared_preferences_android: dependency: transitive description: @@ -337,10 +345,10 @@ packages: dependency: "direct main" description: name: sqflite - sha256: "3a82c9a216b46b88617e3714dd74227eaca20c501c4abcc213e56db26b9caa00" + sha256: b4d6710e1200e96845747e37338ea8a819a12b51689a3bcf31eff0003b37a0b9 url: "https://pub.dev" source: hosted - version: "2.2.8+2" + version: "2.2.8+4" sqflite_common: dependency: transitive description: @@ -361,10 +369,10 @@ packages: dependency: transitive description: name: sqlite3 - sha256: "2cef47b59d310e56f8275b13734ee80a9cf4a48a43172020cb55a620121fbf66" + sha256: "281b672749af2edf259fc801f0fcba092257425bcd32a0ce1c8237130bc934c7" url: "https://pub.dev" source: hosted - version: "1.11.1" + version: "1.11.2" stack_trace: dependency: transitive description: @@ -417,10 +425,10 @@ packages: dependency: transitive description: name: typed_data - sha256: "26f87ade979c47a150c9eaab93ccd2bebe70a27dc0b4b29517f2904f04eb11a5" + sha256: facc8d6582f16042dd49f2463ff1bd6e2c9ef9f3d5da3d9b087e244a7b564b3c url: "https://pub.dev" source: hosted - version: "1.3.1" + version: "1.3.2" vector_math: dependency: "direct main" description: diff --git a/pubspec.yaml b/pubspec.yaml index 1fb3b73..37ed8aa 100644 --- a/pubspec.yaml +++ b/pubspec.yaml @@ -38,6 +38,7 @@ dependencies: fl_chart: ^0.62.0 package_info_plus: ^4.0.2 shared_preferences: ^2.1.1 + intl: ^0.18.1 dev_dependencies: flutter_test: