I'm not sure about my decisions

This commit is contained in:
dan63047 2024-11-23 01:35:16 +03:00
parent 874d5a2e5c
commit bf72c4cee3
13 changed files with 1213 additions and 1010 deletions

View File

@ -6,7 +6,7 @@
/// Locales: 3
/// Strings: 1818 (606 per locale)
///
/// Built on 2024-11-16 at 13:39 UTC
/// Built on 2024-11-21 at 21:18 UTC
// coverage:ignore-file
// ignore_for_file: type=lint
@ -220,7 +220,7 @@ class Translations implements BaseTranslations<AppLocale, Translations> {
String comparingWith({required Object newDate, required Object oldDate}) => 'Data from ${newDate} comparing with ${oldDate}';
String get top => 'Top';
String get topRank => 'Top rank';
String verdictGeneral({required Object n, required Object verdict, required Object rank}) => '${n} ${verdict} than ${rank} rank average';
String verdictGeneral({required Object n, required Object verdict, required Object rank}) => '${n} ${verdict} ${rank} rank avg';
String get verdictBetter => 'better';
String get verdictWorse => 'worse';
String get smooth => 'Smooth';
@ -2348,7 +2348,7 @@ extension on Translations {
case 'comparingWith': return ({required Object newDate, required Object oldDate}) => 'Data from ${newDate} comparing with ${oldDate}';
case 'top': return 'Top';
case 'topRank': return 'Top rank';
case 'verdictGeneral': return ({required Object n, required Object verdict, required Object rank}) => '${n} ${verdict} than ${rank} rank average';
case 'verdictGeneral': return ({required Object n, required Object verdict, required Object rank}) => '${n} ${verdict} ${rank} rank avg';
case 'verdictBetter': return 'better';
case 'verdictWorse': return 'worse';
case 'smooth': return 'Smooth';

View File

@ -46,6 +46,7 @@ ThemeData theme = ThemeData(
),
segmentedButtonTheme: SegmentedButtonThemeData(
style: ButtonStyle(
visualDensity: VisualDensity(horizontal: -4.0, vertical: -4.0),
side: const WidgetStatePropertyAll(BorderSide(color: Colors.transparent)),
surfaceTintColor: const WidgetStatePropertyAll(Colors.cyanAccent),
iconColor: const WidgetStatePropertyAll(Colors.cyanAccent),

View File

@ -13,6 +13,7 @@ final NumberFormat f2l = NumberFormat.decimalPatternDigits(locale: LocaleSetting
final NumberFormat f1 = NumberFormat.decimalPatternDigits(locale: LocaleSettings.currentLocale.languageCode, decimalDigits: 1);
final NumberFormat f0 = NumberFormat.decimalPattern(LocaleSettings.currentLocale.languageCode);
final NumberFormat percentage = NumberFormat.percentPattern(LocaleSettings.currentLocale.languageCode)..maximumFractionDigits = 2;
final NumberFormat percentagef4 = NumberFormat.percentPattern(LocaleSettings.currentLocale.languageCode)..maximumFractionDigits = 4;
/// Readable [a] - [b], without sign
String readableIntDifference(int a, int b){

View File

@ -27,6 +27,8 @@ enum CalcCards{
damage
}
CalcCards calcCard = CalcCards.calc;
class ClearData{
final String title;
final Lineclears lineclear;
@ -131,6 +133,7 @@ class Rules{
const TextStyle mainToggleInRules = TextStyle(fontSize: 18, fontWeight: ui.FontWeight.w800);
class _DestinationCalculatorState extends State<DestinationCalculator> {
// Stats calculator variables
double? apm;
double? pps;
double? vs;
@ -141,6 +144,25 @@ class _DestinationCalculatorState extends State<DestinationCalculator> {
TextEditingController apmController = TextEditingController();
TextEditingController vsController = TextEditingController();
// Damage Calculator variables
List<Widget> rSideWidgets = [];
List<Widget> lSideWidgets = [];
int combo = -1;
int b2b = -1;
int previousB2B = -1;
int totalDamage = 0;
int normalDamage = 0;
int comboDamage = 0;
int b2bDamage = 0;
int surgeDamage = 0;
int pcDamage = 0;
// values for "the bar"
late double sec2end;
late double sec3end;
late double sec4end;
late double sec5end;
List<ClearData> clears = [];
Map<String, int> customClearsChoice = {
"No Spin Clears": 5,
@ -149,8 +171,6 @@ class _DestinationCalculatorState extends State<DestinationCalculator> {
int idCounter = 0;
Rules rules = Rules();
CalcCards card = CalcCards.calc;
@override
void initState() {
super.initState();
@ -175,17 +195,11 @@ class _DestinationCalculatorState extends State<DestinationCalculator> {
}
}
// void calcDamage(){
// for (ClearData lineclear in clears){
// }
// }
Widget getCalculator(){
return SingleChildScrollView(
child: Column(
children: [
Card(
if (widget.constraints.maxWidth > 768.0) Card(
child: Center(child: Padding(
padding: const EdgeInsets.only(bottom: 8.0),
child: Column(
@ -200,14 +214,16 @@ class _DestinationCalculatorState extends State<DestinationCalculator> {
padding: const EdgeInsets.fromLTRB(16.0, 8.0, 16.0, 8.0),
child: Row(
children: [
//TODO: animate those TextFields
Expanded(
child: Padding(
padding: const EdgeInsets.fromLTRB(12.0, 0.0, 12.0, 0.0),
child: TextField(
onSubmitted: (value) => calc(),
onChanged: (value) {setState(() {});},
controller: apmController,
keyboardType: TextInputType.number,
decoration: const InputDecoration(suffix: Text("APM"), alignLabelWithHint: true, hintText: "Enter your APM"),
decoration: InputDecoration(suffix: apmController.value.text.isNotEmpty ? Text("APM") : null, alignLabelWithHint: true, hintText: widget.constraints.maxWidth > 768.0 ? "Enter your APM" : "APM"),
),
)
),
@ -216,9 +232,10 @@ class _DestinationCalculatorState extends State<DestinationCalculator> {
padding: const EdgeInsets.fromLTRB(12.0, 0.0, 12.0, 0.0),
child: TextField(
onSubmitted: (value) => calc(),
onChanged: (value) {setState(() {});},
controller: ppsController,
keyboardType: TextInputType.number,
decoration: const InputDecoration(suffix: Text("PPS"), alignLabelWithHint: true, hintText: "Enter your PPS"),
decoration: InputDecoration(suffix: ppsController.value.text.isNotEmpty ? Text("PPS") : null, alignLabelWithHint: true, hintText: widget.constraints.maxWidth > 768.0 ? "Enter your PPS" : "PPS"),
),
)
),
@ -227,9 +244,10 @@ class _DestinationCalculatorState extends State<DestinationCalculator> {
padding: const EdgeInsets.fromLTRB(12.0, 0.0, 12.0, 0.0),
child: TextField(
onSubmitted: (value) => calc(),
onChanged: (value) {setState(() {});},
controller: vsController,
keyboardType: TextInputType.number,
decoration: const InputDecoration(suffix: Text("VS"), alignLabelWithHint: true, hintText: "Enter your VS"),
decoration: InputDecoration(suffix: vsController.value.text.isNotEmpty ? Text("VS") : null, alignLabelWithHint: true, hintText: widget.constraints.maxWidth > 768.0 ? "Enter your VS" : "VS"),
),
)
),
@ -242,7 +260,7 @@ class _DestinationCalculatorState extends State<DestinationCalculator> {
),
),
if (nerdStats != null) Card(
child: NerdStatsThingy(nerdStats: nerdStats!)
child: NerdStatsThingy(nerdStats: nerdStats!, width: widget.constraints.minWidth)
),
if (playstyle != null) Card(
child: Graphs(apm!, pps!, vs!, nerdStats!, playstyle!)
@ -253,10 +271,102 @@ class _DestinationCalculatorState extends State<DestinationCalculator> {
);
}
Widget getDamageCalculator(){
List<Widget> rSideWidgets = [];
List<Widget> lSideWidgets = [];
Widget rSideDamageCalculator(double width, bool hasSidebar){
return SizedBox(
width: width - (hasSidebar ? 80 : 0),
height: widget.constraints.maxHeight - (hasSidebar ? 108 : 178),
child: clears.isEmpty ? InfoThingy("Click on the actions on the left to add them here") :
Card(
child: Column(
children: [
Expanded(
child: ReorderableListView(
onReorder: (oldIndex, newIndex) {
setState((){
if (oldIndex < newIndex) {
newIndex -= 1;
}
final ClearData item = clears.removeAt(oldIndex);
clears.insert(newIndex, item);
});
},
children: lSideWidgets,
),
),
Divider(),
Column(
mainAxisSize: MainAxisSize.min,
children: [
Padding(
padding: const EdgeInsets.fromLTRB(16.0, 0.0, 34.0, 0.0),
child: Row(
children: [
Text("Total damage:", style: TextStyle(fontSize: 36, fontWeight: ui.FontWeight.w100)),
Spacer(),
Text(intf.format(totalDamage), style: TextStyle(fontFamily: "Eurostile Round Extended", fontSize: 36, fontWeight: ui.FontWeight.w100))
],
),
),
Row(
mainAxisAlignment: MainAxisAlignment.spaceAround,
children: [
Text("Lineclears: ${intf.format(normalDamage)}"),
Text("Combo: ${intf.format(comboDamage)}"),
Text("B2B: ${intf.format(b2bDamage)}"),
Text("Surge: ${intf.format(surgeDamage)}"),
Text("PCs: ${intf.format(pcDamage)}")
],
),
if (totalDamage > 0) SfLinearGauge(
minimum: 0,
maximum: totalDamage.toDouble(),
showLabels: false,
showTicks: false,
ranges: [
LinearGaugeRange(
color: Colors.green,
startValue: 0,
endValue: normalDamage.toDouble(),
position: LinearElementPosition.cross,
),
LinearGaugeRange(
color: Colors.yellow,
startValue: normalDamage.toDouble(),
endValue: sec2end,
position: LinearElementPosition.cross,
),
LinearGaugeRange(
color: Colors.blue,
startValue: sec2end,
endValue: sec3end,
position: LinearElementPosition.cross,
),
LinearGaugeRange(
color: Colors.red,
startValue: sec3end,
endValue: sec4end,
position: LinearElementPosition.cross,
),
LinearGaugeRange(
color: Colors.orange,
startValue: sec4end,
endValue: sec5end,
position: LinearElementPosition.cross,
),
],
),
ElevatedButton.icon(onPressed: (){setState((){clears.clear();});}, icon: const Icon(Icons.clear), label: Text("Clear all"), style: const ButtonStyle(shape: WidgetStatePropertyAll(RoundedRectangleBorder(borderRadius: BorderRadius.all(Radius.circular(12.0))))))
],
)
],
),
),
);
}
Widget getDamageCalculator(){
rSideWidgets = [];
lSideWidgets = [];
for (var key in clearsExisting.keys){
rSideWidgets.add(Text(key));
for (ClearData data in clearsExisting[key]!) rSideWidgets.add(Card(
@ -299,15 +409,15 @@ class _DestinationCalculatorState extends State<DestinationCalculator> {
rSideWidgets.add(const Divider());
}
int combo = -1;
int b2b = -1;
int previousB2B = -1;
int totalDamage = 0;
int normalDamage = 0;
int comboDamage = 0;
int b2bDamage = 0;
int surgeDamage = 0;
int pcDamage = 0;
combo = -1;
b2b = -1;
previousB2B = -1;
totalDamage = 0;
normalDamage = 0;
comboDamage = 0;
b2bDamage = 0;
surgeDamage = 0;
pcDamage = 0;
for (ClearData lineclear in clears){
previousB2B = b2b;
@ -345,13 +455,13 @@ class _DestinationCalculatorState extends State<DestinationCalculator> {
pcDamage += pcDmg;
}
// values for "the bar"
double sec2end = normalDamage.toDouble()+comboDamage.toDouble();
double sec3end = normalDamage.toDouble()+comboDamage.toDouble()+b2bDamage.toDouble();
double sec4end = normalDamage.toDouble()+comboDamage.toDouble()+b2bDamage.toDouble()+surgeDamage.toDouble();
double sec5end = normalDamage.toDouble()+comboDamage.toDouble()+b2bDamage.toDouble()+surgeDamage.toDouble()+pcDamage.toDouble();
sec2end = normalDamage.toDouble()+comboDamage.toDouble();
sec3end = normalDamage.toDouble()+comboDamage.toDouble()+b2bDamage.toDouble();
sec4end = normalDamage.toDouble()+comboDamage.toDouble()+b2bDamage.toDouble()+surgeDamage.toDouble();
sec5end = normalDamage.toDouble()+comboDamage.toDouble()+b2bDamage.toDouble()+surgeDamage.toDouble()+pcDamage.toDouble();
return Column(
children: [
Card(
if (widget.constraints.maxWidth > 768.0) Card(
child: Center(child: Padding(
padding: const EdgeInsets.only(bottom: 8.0),
child: Column(
@ -361,18 +471,20 @@ class _DestinationCalculatorState extends State<DestinationCalculator> {
),
)),
),
Row(
Expanded(
child: Row(
crossAxisAlignment: CrossAxisAlignment.start,
children: [
SizedBox(
width: 350.0,
child: DefaultTabController(length: 2,
width: widget.constraints.maxWidth > 768.0 ? 350.0 : widget.constraints.maxWidth,
child: DefaultTabController(length: widget.constraints.maxWidth > 768.0 ? 2 : 3,
child: Column(
mainAxisSize: MainAxisSize.min,
children: [
Card(
child: TabBar(tabs: [
Tab(text: "Actions"),
if (widget.constraints.maxWidth <= 768.0) Tab(text: "Results"),
Tab(text: "Rules"),
]),
),
@ -384,6 +496,9 @@ class _DestinationCalculatorState extends State<DestinationCalculator> {
children: rSideWidgets,
),
),
if (widget.constraints.maxWidth <= 768.0) SingleChildScrollView(
child: rSideDamageCalculator(widget.constraints.minWidth, false),
),
SingleChildScrollView(
child: Column(
children: [
@ -473,104 +588,16 @@ class _DestinationCalculatorState extends State<DestinationCalculator> {
)
],
),
)
),
]),
)
],
)
),
),
SizedBox(
width: widget.constraints.maxWidth - 350 - 80,
height: widget.constraints.maxHeight - 108,
child: clears.isEmpty ? InfoThingy("Click on the actions on the left to add them here") :
Card(
child: Column(
children: [
Expanded(
child: ReorderableListView(
onReorder: (oldIndex, newIndex) {
setState((){
if (oldIndex < newIndex) {
newIndex -= 1;
}
final ClearData item = clears.removeAt(oldIndex);
clears.insert(newIndex, item);
});
},
children: lSideWidgets,
),
),
Divider(),
Column(
mainAxisSize: MainAxisSize.min,
children: [
Padding(
padding: const EdgeInsets.fromLTRB(16.0, 0.0, 34.0, 0.0),
child: Row(
children: [
Text("Total damage:", style: TextStyle(fontSize: 36, fontWeight: ui.FontWeight.w100)),
Spacer(),
Text(intf.format(totalDamage), style: TextStyle(fontFamily: "Eurostile Round Extended", fontSize: 36, fontWeight: ui.FontWeight.w100))
if (widget.constraints.maxWidth > 768.0) rSideDamageCalculator(widget.constraints.maxWidth - 350, true)
],
),
),
Row(
mainAxisAlignment: MainAxisAlignment.spaceAround,
children: [
Text("Lineclears: ${intf.format(normalDamage)}"),
Text("Combo: ${intf.format(comboDamage)}"),
Text("B2B: ${intf.format(b2bDamage)}"),
Text("Surge: ${intf.format(surgeDamage)}"),
Text("PCs: ${intf.format(pcDamage)}")
],
),
if (totalDamage > 0) SfLinearGauge(
minimum: 0,
maximum: totalDamage.toDouble(),
showLabels: false,
showTicks: false,
ranges: [
LinearGaugeRange(
color: Colors.green,
startValue: 0,
endValue: normalDamage.toDouble(),
position: LinearElementPosition.cross,
),
LinearGaugeRange(
color: Colors.yellow,
startValue: normalDamage.toDouble(),
endValue: sec2end,
position: LinearElementPosition.cross,
),
LinearGaugeRange(
color: Colors.blue,
startValue: sec2end,
endValue: sec3end,
position: LinearElementPosition.cross,
),
LinearGaugeRange(
color: Colors.red,
startValue: sec3end,
endValue: sec4end,
position: LinearElementPosition.cross,
),
LinearGaugeRange(
color: Colors.orange,
startValue: sec4end,
endValue: sec5end,
position: LinearElementPosition.cross,
),
],
),
ElevatedButton.icon(onPressed: (){setState((){clears.clear();});}, icon: const Icon(Icons.clear), label: Text("Clear all"), style: const ButtonStyle(shape: WidgetStatePropertyAll(RoundedRectangleBorder(borderRadius: BorderRadius.all(Radius.circular(12.0))))))
],
)
],
),
),
)
],
)
],
);
@ -581,13 +608,13 @@ class _DestinationCalculatorState extends State<DestinationCalculator> {
return Column(
children: [
SizedBox(
height: widget.constraints.maxHeight -32,
child: switch (card){
height: widget.constraints.maxHeight - (widget.constraints.maxWidth > 768.0 ? 32 : 133),
child: switch (calcCard){
CalcCards.calc => getCalculator(),
CalcCards.damage => getDamageCalculator()
}
),
SegmentedButton<CalcCards>(
if (widget.constraints.maxWidth > 768.0) SegmentedButton<CalcCards>(
showSelectedIcon: false,
segments: <ButtonSegment<CalcCards>>[
const ButtonSegment<CalcCards>(
@ -599,10 +626,10 @@ class _DestinationCalculatorState extends State<DestinationCalculator> {
label: Text('Damage Calculator'),
),
],
selected: <CalcCards>{card},
selected: <CalcCards>{calcCard},
onSelectionChanged: (Set<CalcCards> newSelection) {
setState(() {
card = newSelection.first;
calcCard = newSelection.first;
});})
],
);

View File

@ -157,7 +157,9 @@ class _DestinationCutoffsState extends State<DestinationCutoffs> {
),
),
),
Table(
SingleChildScrollView(
scrollDirection: Axis.horizontal,
child: Table(
defaultVerticalAlignment: TableCellVerticalAlignment.middle,
border: TableBorder.all(color: Colors.grey.shade900),
columnWidths: const {
@ -287,6 +289,7 @@ class _DestinationCutoffsState extends State<DestinationCutoffs> {
]
)
],
),
)
]
),

View File

@ -19,13 +19,17 @@ class DestinationGraphs extends StatefulWidget{
final String searchFor;
//final Function setState;
final BoxConstraints constraints;
final bool noSidebar;
const DestinationGraphs({super.key, required this.searchFor, required this.constraints});
const DestinationGraphs({super.key, required this.searchFor, required this.constraints, required this.noSidebar});
@override
State<DestinationGraphs> createState() => _DestinationGraphsState();
}
Graph graph = Graph.history;
Stats Ychart = Stats.tr;
enum Graph{
history,
leagueState,
@ -42,14 +46,12 @@ class _DestinationGraphsState extends State<DestinationGraphs> {
String yAxisTitle = "";
bool _smooth = false;
final List<DropdownMenuItem<Stats>> _yAxis = [for (MapEntry e in chartsShortTitles.entries) DropdownMenuItem(value: e.key, child: Text(e.value))];
Graph _graph = Graph.history;
Stats _Ychart = Stats.tr;
Stats _Xchart = Stats.tr;
int _season = currentSeason-1;
ValueNotifier<String> historyPlayerUsername = ValueNotifier("");
ValueNotifier<String> historyPlayerAvatarRevizion = ValueNotifier("");
List<String> excludeRanks = [];
late Future<List<_MyScatterSpot>> futureLeague = getTetraLeagueData(_Xchart, _Ychart);
late Future<List<_MyScatterSpot>> futureLeague = getTetraLeagueData(_Xchart, Ychart);
String searchLeague = "";
//Duration postSeasonLeft = seasonStart.difference(DateTime.now());
@ -99,7 +101,7 @@ class _DestinationGraphsState extends State<DestinationGraphs> {
style: const TextStyle(fontFamily: "Eurostile Round Extended", fontSize: 20),
),
),
Text('${f4.format(data.x)} ${chartsShortTitles[_Xchart]}\n${f4.format(data.y)} ${chartsShortTitles[_Ychart]}')
Text('${f4.format(data.x)} ${chartsShortTitles[_Xchart]}\n${f4.format(data.y)} ${chartsShortTitles[Ychart]}')
],
),
);
@ -207,8 +209,8 @@ class _DestinationGraphsState extends State<DestinationGraphs> {
case ConnectionState.done:
if (snapshot.hasData){
if (snapshot.data!.isEmpty || !snapshot.data!.containsKey(_season)) return ErrorThingy(eText: "Not enough data");
List<_HistoryChartSpot> selectedGraph = snapshot.data![_season]![_Ychart]!;
yAxisTitle = chartsShortTitles[_Ychart]!;
List<_HistoryChartSpot> selectedGraph = snapshot.data![_season]![Ychart]!;
yAxisTitle = chartsShortTitles[Ychart]!;
return SfCartesianChart(
tooltipBehavior: _historyTooltipBehavior,
zoomPanBehavior: _zoomPanBehavior,
@ -306,14 +308,14 @@ class _DestinationGraphsState extends State<DestinationGraphs> {
return const Center(child: CircularProgressIndicator());
case ConnectionState.done:
if (snapshot.hasData){
yAxisTitle = chartsShortTitles[_Ychart]!;
yAxisTitle = chartsShortTitles[Ychart]!;
return SfCartesianChart(
tooltipBehavior: _leagueTooltipBehavior,
zoomPanBehavior: _zoomPanBehavior,
primaryXAxis: const DateTimeAxis(),
primaryYAxis: NumericAxis(
// isInversed: true,
maximum: switch (_Ychart){
maximum: switch (Ychart){
Stats.tr => 25000.0,
Stats.gxe => 100.00,
_ => null
@ -327,7 +329,7 @@ class _DestinationGraphsState extends State<DestinationGraphs> {
animationDuration: 0,
//opacity: 0.5,
xValueMapper: (Cutoffs data, _) => data.ts,
yValueMapper: (Cutoffs data, _) => switch (_Ychart){
yValueMapper: (Cutoffs data, _) => switch (Ychart){
Stats.glicko => data.glicko[rank],
Stats.gxe => data.gxe[rank],
_ => data.tr[rank]
@ -344,20 +346,20 @@ class _DestinationGraphsState extends State<DestinationGraphs> {
@override
Widget build(BuildContext context) {
return Column(
return SingleChildScrollView(
child: Column(
mainAxisSize: MainAxisSize.min,
children: [
SingleChildScrollView(
scrollDirection: Axis.vertical,
child: Column(
Column(
mainAxisSize: MainAxisSize.min,
children: [
Card(
child: Wrap(
spacing: 20,
crossAxisAlignment: WrapCrossAlignment.center,
alignment: WrapAlignment.center,
children: [
if (_graph == Graph.history) Row(
if (graph == Graph.history) Row(
mainAxisSize: MainAxisSize.min,
children: [
Icon(Icons.person),
@ -372,7 +374,7 @@ class _DestinationGraphsState extends State<DestinationGraphs> {
),
],
),
if (_graph == Graph.leagueState) SizedBox(
if (graph == Graph.leagueState) SizedBox(
width: 300,
child: TextField(
style: TextStyle(fontSize: 18.0000),
@ -385,11 +387,11 @@ class _DestinationGraphsState extends State<DestinationGraphs> {
},
onSubmitted: (v){
searchLeague = v;
setState((){futureLeague = getTetraLeagueData(_Xchart, _Ychart);});
setState((){futureLeague = getTetraLeagueData(_Xchart, Ychart);});
},
)
),
if (_graph == Graph.history) Row(
if (graph == Graph.history) Row(
mainAxisSize: MainAxisSize.min,
children: [
const Padding(padding: EdgeInsets.all(8.0), child: Text("Season:", style: TextStyle(fontSize: 22))),
@ -404,20 +406,20 @@ class _DestinationGraphsState extends State<DestinationGraphs> {
),
],
),
if (_graph != Graph.leagueCutoffs) Row(
if (graph != Graph.leagueCutoffs) Row(
mainAxisSize: MainAxisSize.min,
children: [
const Padding(padding: EdgeInsets.all(8.0), child: Text("X:", style: TextStyle(fontSize: 22))),
DropdownButton(
items: switch (_graph){
items: switch (graph){
Graph.history => [DropdownMenuItem(value: false, child: Text("Date & Time")), DropdownMenuItem(value: true, child: Text("Games Played"))],
Graph.leagueState => _yAxis,
Graph.leagueCutoffs => [],
},
value: _graph == Graph.history ? _gamesPlayedInsteadOfDateAndTime : _Xchart,
value: graph == Graph.history ? _gamesPlayedInsteadOfDateAndTime : _Xchart,
onChanged: (value) {
setState(() {
if (_graph == Graph.history)
if (graph == Graph.history)
_gamesPlayedInsteadOfDateAndTime = value! as bool;
else _Xchart = value! as Stats;
});
@ -430,17 +432,17 @@ class _DestinationGraphsState extends State<DestinationGraphs> {
children: [
const Padding(padding: EdgeInsets.all(8.0), child: Text("Y:", style: TextStyle(fontSize: 22))),
DropdownButton<Stats>(
items: _graph == Graph.leagueCutoffs ? [DropdownMenuItem(value: Stats.tr, child: Text(chartsShortTitles[Stats.tr]!)), DropdownMenuItem(value: Stats.glicko, child: Text(chartsShortTitles[Stats.glicko]!)), DropdownMenuItem(value: Stats.gxe, child: Text(chartsShortTitles[Stats.gxe]!))] : _yAxis,
value: _Ychart,
items: graph == Graph.leagueCutoffs ? [DropdownMenuItem(value: Stats.tr, child: Text(chartsShortTitles[Stats.tr]!)), DropdownMenuItem(value: Stats.glicko, child: Text(chartsShortTitles[Stats.glicko]!)), DropdownMenuItem(value: Stats.gxe, child: Text(chartsShortTitles[Stats.gxe]!))] : _yAxis,
value: Ychart,
onChanged: (value) {
setState(() {
_Ychart = value!;
Ychart = value!;
});
}
),
],
),
if (_graph == Graph.history) Row(
if (graph == Graph.history) Row(
mainAxisSize: MainAxisSize.min,
children: [
Checkbox(value: _smooth,
@ -453,7 +455,7 @@ class _DestinationGraphsState extends State<DestinationGraphs> {
Text(t.smooth, style: const TextStyle(color: Colors.white, fontSize: 22))
],
),
if (_graph == Graph.leagueState) IconButton(
if (graph == Graph.leagueState) IconButton(
color: excludeRanks.isNotEmpty ? Theme.of(context).colorScheme.primary : null,
onPressed: (){
showDialog(context: context, builder: (BuildContext context) {
@ -492,7 +494,7 @@ class _DestinationGraphsState extends State<DestinationGraphs> {
actions: <Widget>[
TextButton(
child: const Text("Apply"),
onPressed: () {Navigator.of(context).pop(); setState((){futureLeague = getTetraLeagueData(_Xchart, _Ychart);});}
onPressed: () {Navigator.of(context).pop(); setState((){futureLeague = getTetraLeagueData(_Xchart, Ychart);});}
)
]
);
@ -506,10 +508,10 @@ class _DestinationGraphsState extends State<DestinationGraphs> {
),
Card(
child: SizedBox(
width: MediaQuery.of(context).size.width - 88,
width: MediaQuery.of(context).size.width - (widget.noSidebar ? 0 : 88),
height: MediaQuery.of(context).size.height - 96,
child: Padding( padding: const EdgeInsets.fromLTRB(40, 30, 40, 30),
child: switch (_graph){
child: switch (graph){
Graph.history => getHistoryGraph(),
Graph.leagueState => getLeagueState(),
Graph.leagueCutoffs => getCutoffsHistory()
@ -519,8 +521,7 @@ class _DestinationGraphsState extends State<DestinationGraphs> {
)
],
),
),
SegmentedButton<Graph>(
if (!widget.noSidebar) SegmentedButton<Graph>(
showSelectedIcon: false,
segments: <ButtonSegment<Graph>>[
const ButtonSegment<Graph>(
@ -534,19 +535,20 @@ class _DestinationGraphsState extends State<DestinationGraphs> {
label: Text('League Cutoffs'),
),
],
selected: <Graph>{_graph},
selected: <Graph>{graph},
onSelectionChanged: (Set<Graph> newSelection) {
setState(() {
_graph = newSelection.first;
graph = newSelection.first;
switch (newSelection.first){
case Graph.leagueCutoffs:
case Graph.history:
_Ychart = Stats.tr;
Ychart = Stats.tr;
case Graph.leagueState:
_Ychart = Stats.apm;
Ychart = Stats.apm;
}
});})
],
),
);
}
}

View File

@ -125,6 +125,7 @@ class ZenithCard extends StatelessWidget {
Widget splitsCard(){
return Card(
child: Center(
child: SizedBox(
width: 300,
height: 318,
@ -179,6 +180,7 @@ class ZenithCard extends StatelessWidget {
],
),
),
),
);
}
@ -257,38 +259,12 @@ class RecordCard extends StatelessWidget {
final MapEntry? closestAverage;
final bool? betterThanClosestAverage;
final String? rank;
final double width;
const RecordCard(this.record, this.achievements, this.betterThanRankAverage, this.closestAverage, this.betterThanClosestAverage, this.rank);
const RecordCard(this.record, this.achievements, this.betterThanRankAverage, this.closestAverage, this.betterThanClosestAverage, this.rank, {this.width = double.infinity});
@override
Widget build(BuildContext context) {
if (record == null) {
return const Card(
child: Center(child: Text("No record", style: TextStyle(fontSize: 42))),
);
}
return Column(
children: [
Card(
child: Padding(
padding: const EdgeInsets.only(bottom: 4.0),
child: Center(
child: Column(
mainAxisSize: MainAxisSize.min,
crossAxisAlignment: CrossAxisAlignment.center,
children: [
Text(switch(record!.gamemode){
"40l" => t.sprint,
"blitz" => t.blitz,
"5mblast" => "5,000,000 Blast",
_ => record!.gamemode
}, style: Theme.of(context).textTheme.titleLarge)
],
),
),
),
),
Card(
Widget result(){
return Card(
child: Column(
children: [
Row(
@ -342,6 +318,7 @@ class RecordCard extends StatelessWidget {
],
),
Row(
mainAxisSize: MainAxisSize.min,
children: [
Expanded(
child: Table(
@ -415,8 +392,11 @@ class RecordCard extends StatelessWidget {
)
],
),
),
Card(
);
}
Widget hjsdj(){
return Card(
child: Center(
child: Column(
children: [
@ -426,11 +406,46 @@ class RecordCard extends StatelessWidget {
],
),
),
);
}
@override
Widget build(BuildContext context) {
if (record == null) {
return const Card(
child: Center(child: Text("No record", style: TextStyle(fontSize: 42))),
);
}
return Column(
children: [
Card(
child: Padding(
padding: const EdgeInsets.only(bottom: 4.0),
child: Center(
child: Column(
mainAxisSize: MainAxisSize.min,
crossAxisAlignment: CrossAxisAlignment.center,
children: [
Text(switch(record!.gamemode){
"40l" => t.sprint,
"blitz" => t.blitz,
"5mblast" => "5,000,000 Blast",
_ => record!.gamemode
}, style: Theme.of(context).textTheme.titleLarge)
],
),
),
),
),
Column(
mainAxisSize: MainAxisSize.min,
crossAxisAlignment: CrossAxisAlignment.start,
children: [result(), hjsdj()],
),
Wrap(
direction: Axis.horizontal,
children: [
for (Achievement achievement in achievements) FractionallySizedBox(widthFactor: 0.5, child: AchievementSummary(achievement: achievement)),
for (Achievement achievement in achievements) FractionallySizedBox(widthFactor: 1/((width/600).ceil()), child: AchievementSummary(achievement: achievement)),
],
),
]
@ -461,8 +476,9 @@ class RecordSummary extends StatelessWidget{
final MapEntry? closestAverage;
final bool? betterThanClosestAverage;
final String? rank;
final double width;
const RecordSummary({super.key, required this.record, this.betterThanRankAverage, this.closestAverage, this.old = false, this.betterThanClosestAverage, this.rank, this.hideRank = false});
const RecordSummary({super.key, required this.record, this.betterThanRankAverage, this.closestAverage, this.old = false, this.betterThanClosestAverage, this.rank, this.hideRank = false, this.width = double.infinity});
@override
Widget build(BuildContext context) {
@ -597,7 +613,7 @@ class AchievementSummary extends StatelessWidget{
if (achievement!.vt == 4) TextSpan(text: ""),
if (achievement!.vt != 5) TextSpan(text: (achievement?.pos != null && !achievement!.pos!.isNegative) ? "${intf.format(achievement!.pos!+1)}" : "№ ---", style: TextStyle(color: achievement?.pos != null ? getColorOfRank(achievement!.pos!+1) : Colors.grey)),
if (achievement!.vt != 5) TextSpan(text: "", style: TextStyle(color: achievement?.pos != null ? getColorOfRank(achievement!.pos!+1) : Colors.grey)),
TextSpan(text: "Top ${achievement?.pos != null ? percentage.format(achievement!.pos! / achievement!.total!) : "---%"}", style: TextStyle(color: achievement?.pos != null ? getColorOfRank(achievement!.pos!+1) : Colors.grey)),
TextSpan(text: "Top ${achievement?.pos != null ? percentagef4.format(achievement!.pos! / achievement!.total!) : "---%"}", style: TextStyle(color: achievement?.pos != null ? getColorOfRank(achievement!.pos!+1) : Colors.grey)),
]
),
),
@ -1134,12 +1150,12 @@ class _DestinationHomeState extends State<DestinationHome> with SingleTickerProv
CardMod.exRecords => getListOfRecords("zenithex/recent", "zenithex/top", widget.constraints),
},
Cards.sprint => switch (cardMod){
CardMod.info => RecordCard(snapshot.data?.summaries!.sprint, sprintAchievements, sprintBetterThanRankAverage, closestAverageSprint, sprintBetterThanClosestAverage, snapshot.data!.summaries!.league.rank),
CardMod.info => RecordCard(snapshot.data?.summaries!.sprint, sprintAchievements, sprintBetterThanRankAverage, closestAverageSprint, sprintBetterThanClosestAverage, snapshot.data!.summaries!.league.rank, width: width),
CardMod.records => getListOfRecords("40l/recent", "40l/top", widget.constraints),
_ => const Center(child: Text("huh?"))
},
Cards.blitz => switch (cardMod){
CardMod.info => RecordCard(snapshot.data?.summaries!.blitz, blitzAchievements, blitzBetterThanRankAverage, closestAverageBlitz, blitzBetterThanClosestAverage, snapshot.data!.summaries!.league.rank),
CardMod.info => RecordCard(snapshot.data?.summaries!.blitz, blitzAchievements, blitzBetterThanRankAverage, closestAverageBlitz, blitzBetterThanClosestAverage, snapshot.data!.summaries!.league.rank, width: width),
CardMod.records => getListOfRecords("blitz/recent", "blitz/top", widget.constraints),
_ => const Center(child: Text("huh?"))
},

View File

@ -17,19 +17,20 @@ class DestinationInfo extends StatefulWidget{
class InfoCard extends StatelessWidget {
final double height;
final double viewportWidth;
final String assetLink;
final String? assetLinkOnFocus;
final String title;
final String description;
final void Function() onPressed;
const InfoCard({required this.height, required this.assetLink, required this.title, required this.description, this.assetLinkOnFocus, required this.onPressed});
const InfoCard({required this.height, this.viewportWidth = double.infinity, required this.assetLink, required this.title, required this.description, this.assetLinkOnFocus, required this.onPressed});
@override
Widget build(BuildContext context) {
return Card(
clipBehavior: Clip.hardEdge,
child: SizedBox(
child: viewportWidth > 768.0 ? SizedBox(
width: 450,
height: height,
child: Column(
@ -43,6 +44,26 @@ class InfoCard extends StatelessWidget {
Spacer()
],
),
) : SizedBox(
width: viewportWidth,
child: Row(
crossAxisAlignment: CrossAxisAlignment.start,
children: [
Image.asset(assetLink, fit: BoxFit.cover, width: 200.0),
Expanded(
child: Column(
crossAxisAlignment: CrossAxisAlignment.start,
children: [
TextButton(child: Text(title, style: Theme.of(context).textTheme.titleLarge!.copyWith(decoration: TextDecoration.underline, decorationColor: Colors.white70, decorationStyle: TextDecorationStyle.dotted, fontSize: 28), textAlign: TextAlign.center), onPressed: onPressed),
Padding(
padding: const EdgeInsets.all(12.0),
child: Text(description),
),
],
),
),
],
),
),
);
}
@ -52,18 +73,10 @@ class InfoCard extends StatelessWidget {
class _DestinationInfo extends State<DestinationInfo> {
@override
Widget build(BuildContext context) {
return Column(
mainAxisSize: MainAxisSize.min,
children: [
Card(
child: Center(child: Text("Information Center", style: Theme.of(context).textTheme.titleLarge)),
),
SingleChildScrollView(
scrollDirection: Axis.horizontal,
child: Row(
children: [
List<Widget> cards = [
InfoCard(
height: widget.constraints.maxHeight - 77,
viewportWidth: widget.constraints.maxWidth,
assetLink: "res/images/info card 1 focus.png",
title: "40 Lines & Blitz Averages",
description: "Since calculating 40 Lines & Blitz averages is tedious process, it gets updated only once in a while. Click on the title of this card to see the full 40 Lines & Blitz averages table\n\n${t.sprintAndBlitsRelevance(date: DateFormat.yMMMd(LocaleSettings.currentLocale.languageCode).format(sprintAndBlitzRelevance))}",
@ -75,6 +88,7 @@ class _DestinationInfo extends State<DestinationInfo> {
),
InfoCard(
height: widget.constraints.maxHeight - 77,
viewportWidth: widget.constraints.maxWidth,
assetLink: "res/images/Снимок экрана_2023-11-06_01-00-50.png",
title: "Tetra Stats Wiki",
description: "Find more information about Tetra Stats functions and statictic, that it provides",
@ -84,6 +98,7 @@ class _DestinationInfo extends State<DestinationInfo> {
),
InfoCard(
height: widget.constraints.maxHeight - 77,
viewportWidth: widget.constraints.maxWidth,
assetLink: "res/images/Снимок экрана_2023-11-06_01-00-50.png",
title: "About Tetra Stats",
description: "Developed by dan63\n",
@ -93,8 +108,17 @@ class _DestinationInfo extends State<DestinationInfo> {
));
},
),
],
];
return Column(
mainAxisSize: MainAxisSize.min,
children: [
Card(
child: Center(child: Text("Information Center", style: Theme.of(context).textTheme.titleLarge)),
),
SingleChildScrollView(
scrollDirection: Axis.horizontal,
child: widget.constraints.maxWidth > 768.0 ? Row(children: cards) : Column(children: cards),
)
],
);

View File

@ -1,4 +1,5 @@
import 'dart:async';
import 'dart:ffi';
import 'dart:math';
import 'package:flutter/material.dart';
import 'package:tetra_stats/data_objects/tetrio_constants.dart';
@ -12,13 +13,16 @@ import 'package:tetra_stats/widgets/future_error.dart';
class DestinationLeaderboards extends StatefulWidget{
final BoxConstraints constraints;
final bool noSidebar;
const DestinationLeaderboards({super.key, required this.constraints});
const DestinationLeaderboards({super.key, required this.constraints, required this.noSidebar});
@override
State<DestinationLeaderboards> createState() => _DestinationLeaderboardsState();
}
const double transformThreshold = 768.0;
enum Leaderboards{
tl,
fullTL,
@ -116,53 +120,12 @@ class _DestinationLeaderboardsState extends State<DestinationLeaderboards> {
});
}
static TextStyle trailingStyle = TextStyle(fontSize: 28);
@override
Widget build(BuildContext context) {
return Row(
children: [
SizedBox(
width: 350.0,
height: widget.constraints.maxHeight,
child: Column(
children: [
Card(
child: Row(
mainAxisSize: MainAxisSize.min,
children: [
Spacer(),
Text("Leaderboards", style: Theme.of(context).textTheme.headlineMedium),
Spacer()
],
),
),
Expanded(
child: ListView.builder(
itemCount: leaderboards.length,
itemBuilder: (BuildContext context, int index) {
return Card(
child: ListTile(
title: Text(leaderboards.values.elementAt(index)),
trailing: Icon(Icons.arrow_right, color: _currentLb.index == index ? Colors.white : Colors.grey),
subtitle: index == 1 ? Text("Heavy, but allows you to sort players by their stats and filter them by ranks", style: TextStyle(color: Colors.grey, fontSize: 12)) : null,
onTap: () {
_currentLb = leaderboards.keys.elementAt(index);
list.clear();
prisecter = null;
_reachedTheEnd = false;
_fetchData();
},
),
);
}
),
),
],
),
),
SizedBox(
width: widget.constraints.maxWidth - 350 - 88,
Widget rightSide(double width){
print(width);
const double eukjsakjas = 450;
TextStyle trailingStyle = TextStyle(fontSize: 28, fontFamily: width < eukjsakjas ? "Eurostile Round Condensed" : null);
return SizedBox(
width: width,
child: Card(
child: StreamBuilder<List<dynamic>>(
stream: dataStream,
@ -176,9 +139,9 @@ class _DestinationLeaderboardsState extends State<DestinationLeaderboards> {
if (snapshot.hasData){
return Column(
children: [
Text(leaderboards[_currentLb]!, style: Theme.of(context).textTheme.titleSmall),
Row(
mainAxisAlignment: MainAxisAlignment.center,
Text(leaderboards[_currentLb]!, style: Theme.of(context).textTheme.titleSmall, textAlign: TextAlign.center),
Wrap(
alignment: WrapAlignment.center,
children: [
DropdownMenu(
leadingIcon: Icon(Icons.public),
@ -327,7 +290,7 @@ class _DestinationLeaderboardsState extends State<DestinationLeaderboards> {
Leaderboards.zenith => Text("${f2.format(snapshot.data![index].stats.zenith!.altitude)} m", style: trailingStyle),
Leaderboards.zenithex => Text("${f2.format(snapshot.data![index].stats.zenith!.altitude)} m", style: trailingStyle)
},
subtitle: Text(switch (_currentLb){
subtitle: width >= eukjsakjas ? Text(switch (_currentLb){
Leaderboards.tl => "${f2.format(snapshot.data![index].apm)} APM, ${f2.format(snapshot.data![index].pps)} PPS, ${f2.format(snapshot.data![index].vs)} VS, ${f2.format(snapshot.data![index].nerdStats.app)} APP, ${f2.format(snapshot.data![index].nerdStats.vsapm)} VS/APM",
Leaderboards.fullTL => switch (stat) {
Stats.tr => "${f2.format(snapshot.data![index].apm)} APM, ${f2.format(snapshot.data![index].pps)} PPS, ${f2.format(snapshot.data![index].vs)} VS, ${f2.format(snapshot.data![index].nerdStats.app)} APP, ${f2.format(snapshot.data![index].nerdStats.vsapm)} VS/APM",
@ -339,7 +302,7 @@ class _DestinationLeaderboardsState extends State<DestinationLeaderboards> {
Leaderboards.blitz => "lvl ${snapshot.data![index].stats.level}, ${f2.format(snapshot.data![index].stats.pps)} PPS, ${f2.format(snapshot.data![index].stats.spp)} SPP",
Leaderboards.zenith => "${f2.format(snapshot.data![index].aggregateStats.apm)} APM, ${f2.format(snapshot.data![index].aggregateStats.pps)} PPS, ${intf.format(snapshot.data![index].stats.kills)} KO's, ${f2.format(snapshot.data![index].stats.cps)} climb speed (${f2.format(snapshot.data![index].stats.zenith!.peakrank)} peak), ${intf.format(snapshot.data![index].stats.topBtB)} B2B",
Leaderboards.zenithex => "${f2.format(snapshot.data![index].aggregateStats.apm)} APM, ${f2.format(snapshot.data![index].aggregateStats.pps)} PPS, ${intf.format(snapshot.data![index].stats.kills)} KO's, ${f2.format(snapshot.data![index].stats.cps)} climb speed (${f2.format(snapshot.data![index].stats.zenith!.peakrank)} peak), ${intf.format(snapshot.data![index].stats.topBtB)} B2B"
}, style: TextStyle(color: Colors.grey, fontSize: 12)),
}, style: TextStyle(color: Colors.grey, fontSize: 12)) : null,
onTap: () {
Navigator.push(
context,
@ -362,7 +325,73 @@ class _DestinationLeaderboardsState extends State<DestinationLeaderboards> {
},
),
),
);
}
@override
Widget build(BuildContext context) {
return Row(
children: [
SizedBox(
width: widget.constraints.maxWidth > transformThreshold ? 300.0 : widget.constraints.maxWidth,
height: widget.constraints.maxHeight,
child: Column(
children: [
Card(
child: Row(
mainAxisSize: MainAxisSize.min,
children: [
Spacer(),
Text("Leaderboards", style: Theme.of(context).textTheme.headlineMedium!.copyWith(fontSize: 32)),
Spacer()
],
),
),
Expanded(
child: ListView.builder(
itemCount: leaderboards.length,
itemBuilder: (BuildContext context, int index) {
return Card(
child: ListTile(
title: Text(leaderboards.values.elementAt(index)),
trailing: Icon(Icons.arrow_right, color: _currentLb.index == index ? Colors.white : Colors.grey),
subtitle: index == 1 ? Text("Heavy, but allows you to sort players by their stats and filter them by ranks", style: TextStyle(color: Colors.grey, fontSize: 12)) : null,
onTap: () {
if (widget.constraints.maxWidth <= transformThreshold) Navigator.push(
context,
MaterialPageRoute(
builder: (context) => Scaffold(
floatingActionButtonLocation: FloatingActionButtonLocation.endFloat,
floatingActionButton: Padding(
padding: const EdgeInsets.fromLTRB(0.0, 12.0, 0.0, 0.0),
child: FloatingActionButton(
onPressed: () => Navigator.pop(context),
tooltip: 'Fuck go back',
child: const Icon(Icons.arrow_back),
),
),
body: SafeArea(
child: rightSide(widget.constraints.maxWidth)
)
),
maintainState: false,
),
);
_currentLb = leaderboards.keys.elementAt(index);
list.clear();
prisecter = null;
_reachedTheEnd = false;
_fetchData();
},
),
);
}
),
),
],
),
),
if (widget.constraints.maxWidth > transformThreshold) rightSide(widget.constraints.maxWidth - 300 - (widget.noSidebar ? 0 : 88)),
],
);
}

View File

@ -58,49 +58,9 @@ class _DestinationSavedData extends State<DestinationSavedData> {
);
}
@override
Widget build(BuildContext context) {
return FutureBuilder<Map<String, String>>(
future: teto.getAllPlayers(),
builder: (context, snapshot) {
switch (snapshot.connectionState){
case ConnectionState.none:
case ConnectionState.waiting:
case ConnectionState.active:
return const Center(child: CircularProgressIndicator());
case ConnectionState.done:
if (snapshot.hasError){ return FutureError(snapshot); }
if (snapshot.hasData){
return Row(
children: [
SizedBox(
width: 450,
child: Column(
children: [
Card(
child: Row(
mainAxisSize: MainAxisSize.min,
children: [
Spacer(),
Text("Saved Data", style: Theme.of(context).textTheme.headlineMedium),
Spacer()
],
),
),
for (String id in snapshot.data!.keys) Card(
child: ListTile(
title: Text(snapshot.data![id]!),
//subtitle: Text("NaN states, NaN TL records", style: TextStyle(color: Colors.grey)),
onTap: () => setState(() {
selectedID = id;
}),
),
)
],
),
),
SizedBox(
width: widget.constraints.maxWidth - 450 - 80,
Widget rightSide(double width, bool hasSidebar){
return SizedBox(
width: width - (hasSidebar ? 80.0 : 0.00),
child: selectedID != null ? FutureBuilder<(List<TetraLeague>, List<TetraLeague>, List<TetraLeagueAlphaRecord>)>(
future: getDataAbout(selectedID!),
builder: (context, snapshot) {
@ -158,7 +118,71 @@ class _DestinationSavedData extends State<DestinationSavedData> {
}
) :
InfoThingy("Select nickname on the left to see data assosiated with it")
);
}
@override
Widget build(BuildContext context) {
return FutureBuilder<Map<String, String>>(
future: teto.getAllPlayers(),
builder: (context, snapshot) {
switch (snapshot.connectionState){
case ConnectionState.none:
case ConnectionState.waiting:
case ConnectionState.active:
return const Center(child: CircularProgressIndicator());
case ConnectionState.done:
if (snapshot.hasError){ return FutureError(snapshot); }
if (snapshot.hasData){
return Row(
children: [
SizedBox(
width: widget.constraints.maxWidth > 900.0 ? 350 : widget.constraints.maxWidth - (widget.constraints.maxWidth <= 768.0 ? 0 : 80),
child: Column(
children: [
Card(
child: Row(
mainAxisSize: MainAxisSize.min,
children: [
Spacer(),
Text("Saved Data", style: Theme.of(context).textTheme.headlineMedium),
Spacer()
],
),
),
for (String id in snapshot.data!.keys) Card(
child: ListTile(
title: Text(snapshot.data![id]!),
//subtitle: Text("NaN states, NaN TL records", style: TextStyle(color: Colors.grey)),
onTap: () => setState(() {
selectedID = id;
if (widget.constraints.maxWidth <= 900.0) Navigator.push(
context,
MaterialPageRoute(
builder: (context) => Scaffold(
floatingActionButtonLocation: FloatingActionButtonLocation.endFloat,
floatingActionButton: Padding(
padding: const EdgeInsets.fromLTRB(0.0, 12.0, 0.0, 0.0),
child: FloatingActionButton(
onPressed: () => Navigator.pop(context),
tooltip: 'Fuck go back',
child: const Icon(Icons.arrow_back),
),
),
body: SafeArea(
child: rightSide(widget.constraints.maxWidth, false)
)
),
maintainState: false,
),
);
}),
),
)
],
),
),
if (widget.constraints.maxWidth > 900.0) rightSide(widget.constraints.maxWidth - 350, true)
],
);
}

View File

@ -607,6 +607,19 @@ class _DestinationSettings extends State<DestinationSettings> with SingleTickerP
);
}
Widget rightSide(double width, bool hasSidebar){
return SizedBox(
width: width - (hasSidebar ? 80 : 0),
child: SingleChildScrollView(
child: switch (mod){
SettingsCardMod.general => getGeneralSettings(),
SettingsCardMod.customization => getCustomizationSettings(),
SettingsCardMod.database => getDatabaseSettings(),
},
)
);
}
@override
Widget build(BuildContext context) {
final t = Translations.of(context);
@ -618,7 +631,7 @@ class _DestinationSettings extends State<DestinationSettings> with SingleTickerP
crossAxisAlignment: CrossAxisAlignment.start,
children: [
SizedBox(
width: 450,
width: widget.constraints.maxWidth > 900.0 ? 350 : widget.constraints.maxWidth - (widget.constraints.maxWidth <= 768.0 ? 0 : 80),
child: Column(
children: [
Card(
@ -639,22 +652,33 @@ class _DestinationSettings extends State<DestinationSettings> with SingleTickerP
setState(() {
mod = m;
});
if (widget.constraints.maxWidth <= 900.0) Navigator.push(
context,
MaterialPageRoute(
builder: (context) => Scaffold(
floatingActionButtonLocation: FloatingActionButtonLocation.endFloat,
floatingActionButton: Padding(
padding: const EdgeInsets.fromLTRB(0.0, 12.0, 0.0, 0.0),
child: FloatingActionButton(
onPressed: () => Navigator.pop(context),
tooltip: 'Fuck go back',
child: const Icon(Icons.arrow_back),
),
),
body: SafeArea(
child: rightSide(widget.constraints.maxWidth, false)
)
),
maintainState: false,
),
);
},
),
)
],
),
),
SizedBox(
width: widget.constraints.maxWidth - 450 - 80,
child: SingleChildScrollView(
child: switch (mod){
SettingsCardMod.general => getGeneralSettings(),
SettingsCardMod.customization => getCustomizationSettings(),
SettingsCardMod.database => getDatabaseSettings(),
},
)
)
if (widget.constraints.maxWidth > 900.0) rightSide(widget.constraints.maxWidth - 350, true)
],
);
}

View File

@ -27,6 +27,10 @@ late Future<FetchResults> _data;
TetrioPlayersLeaderboard? _everyone;
int destination = 0;
// TODO: Redesign some widgets, so they could look nice on mobile view
// - stats below TL progress bar & similar parts in other widgets
// - APP and VS/APM gadget
Future<FetchResults> getData(String searchFor) async {
TetrioPlayer player;
try{
@ -160,32 +164,9 @@ class _MainState extends State<MainView> with TickerProviderStateMixin {
);
}
@override
Widget build(BuildContext context) {
return LayoutBuilder(
builder: (BuildContext context, BoxConstraints constraints){
bool screenIsBig = constraints.maxWidth > 768.00;
return Scaffold(
key: _scaffoldKey,
drawer: SearchDrawer(changePlayer: changePlayer, controller: _searchController),
endDrawer: DestinationsDrawer(changeDestination: (value) {setState(() {destination = value;});}),
bottomNavigationBar: screenIsBig ? null : BottomAppBar(
shape: const AutomaticNotchedShape(RoundedRectangleBorder(borderRadius: BorderRadius.all(Radius.circular(0.0))), RoundedRectangleBorder(borderRadius: BorderRadius.all(Radius.circular(16.0)))),
notchMargin: 2.0,
height: 88,
child: IconTheme(
data: IconThemeData(color: Theme.of(context).colorScheme.primary),
child: Row(
children: <Widget>[
IconButton(
tooltip: 'Open navigation menu',
icon: const Icon(Icons.menu),
onPressed: () {
_scaffoldKey.currentState!.openEndDrawer();
},
),
Expanded(
child: Column(
Widget pickers(int destination){
return switch (destination) {
0 => Column(
children: [
SingleChildScrollView(
scrollDirection: Axis.horizontal,
@ -232,11 +213,82 @@ class _MainState extends State<MainView> with TickerProviderStateMixin {
});})
],
),
1 => SegmentedButton<Graph>(
showSelectedIcon: false,
segments: <ButtonSegment<Graph>>[
const ButtonSegment<Graph>(
value: Graph.history,
label: Text('Player History')),
ButtonSegment<Graph>(
value: Graph.leagueState,
label: Text('League State')),
ButtonSegment<Graph>(
value: Graph.leagueCutoffs,
label: Text('League Cutoffs'),
),
],
selected: <Graph>{graph},
onSelectionChanged: (Set<Graph> newSelection) {
setState(() {
graph = newSelection.first;
switch (newSelection.first){
case Graph.leagueCutoffs:
case Graph.history:
Ychart = Stats.tr;
case Graph.leagueState:
Ychart = Stats.apm;
}
});}),
4 => SegmentedButton<CalcCards>(
showSelectedIcon: false,
segments: <ButtonSegment<CalcCards>>[
const ButtonSegment<CalcCards>(
value: CalcCards.calc,
label: Text('Stats Calculator'),
),
ButtonSegment<CalcCards>(
value: CalcCards.damage,
label: Text('Damage Calculator'),
),
],
selected: <CalcCards>{calcCard},
onSelectionChanged: (Set<CalcCards> newSelection) {
setState(() {
calcCard = newSelection.first;
});}),
_ => Container()
};
}
@override
Widget build(BuildContext context) {
return LayoutBuilder(
builder: (BuildContext context, BoxConstraints constraints){
bool screenIsBig = constraints.maxWidth > 768.00;
return Scaffold(
key: _scaffoldKey,
drawer: SearchDrawer(changePlayer: changePlayer, controller: _searchController),
endDrawer: DestinationsDrawer(changeDestination: (value) {setState(() {destination = value;});}),
bottomNavigationBar: screenIsBig ? null : BottomAppBar(
shape: const AutomaticNotchedShape(RoundedRectangleBorder(borderRadius: BorderRadius.all(Radius.circular(0.0))), RoundedRectangleBorder(borderRadius: BorderRadius.all(Radius.circular(16.0)))),
notchMargin: 2.0,
height: 88,
child: IconTheme(
data: IconThemeData(color: Theme.of(context).colorScheme.primary),
child: Row(
children: <Widget>[
IconButton(
tooltip: 'Fake "Open navigation menu" button\nHere only for symmetry',
icon: const Icon(Icons.menu, color: Colors.transparent),
onPressed: () {},
tooltip: 'Open navigation menu',
icon: const Icon(Icons.menu),
onPressed: () {
_scaffoldKey.currentState!.openEndDrawer();
},
),
Expanded(
child: pickers(destination),
),
SizedBox(
width: 40.0,
),
],
),
@ -259,7 +311,7 @@ class _MainState extends State<MainView> with TickerProviderStateMixin {
leading: FloatingActionButton(
elevation: 0,
onPressed: () {
Scaffold.of(context).openDrawer();
_scaffoldKey.currentState!.openDrawer();
},
child: const Icon(Icons.search),
),
@ -300,8 +352,8 @@ class _MainState extends State<MainView> with TickerProviderStateMixin {
Expanded(
child: switch (destination){
0 => DestinationHome(searchFor: _searchFor, constraints: constraints, dataFuture: _data, noSidebar: !screenIsBig),
1 => DestinationGraphs(searchFor: _searchFor, constraints: constraints),
2 => DestinationLeaderboards(constraints: constraints),
1 => DestinationGraphs(searchFor: _searchFor, constraints: constraints, noSidebar: !screenIsBig),
2 => DestinationLeaderboards(constraints: constraints, noSidebar: !screenIsBig),
3 => DestinationCutoffs(constraints: constraints),
4 => DestinationCalculator(constraints: constraints),
5 => DestinationInfo(constraints: constraints),

View File

@ -84,7 +84,7 @@
"comparingWith": "Data from ${newDate} comparing with ${oldDate}",
"top": "Top",
"topRank": "Top rank",
"verdictGeneral": "$n $verdict than $rank rank average",
"verdictGeneral": "$n $verdict $rank rank avg",
"verdictBetter": "better",
"verdictWorse": "worse",
"smooth": "Smooth",