2024-10-17 22:17:23 +00:00
import ' dart:async ' ;
import ' package:flutter/material.dart ' ;
import ' package:syncfusion_flutter_charts/charts.dart ' ;
import ' package:tetra_stats/data_objects/p1nkl0bst3r.dart ' ;
import ' package:tetra_stats/data_objects/tetra_league.dart ' ;
import ' package:tetra_stats/data_objects/tetrio_constants.dart ' ;
import ' package:tetra_stats/data_objects/tetrio_player_from_leaderboard.dart ' ;
import ' package:tetra_stats/data_objects/tetrio_players_leaderboard.dart ' ;
import ' package:tetra_stats/gen/strings.g.dart ' ;
import ' package:tetra_stats/main.dart ' ;
import ' package:tetra_stats/services/crud_exceptions.dart ' ;
import ' package:tetra_stats/utils/numers_formats.dart ' ;
2024-11-05 23:07:43 +00:00
import ' package:tetra_stats/views/main_view.dart ' ;
import ' package:tetra_stats/widgets/error_thingy.dart ' ;
import ' package:tetra_stats/widgets/future_error.dart ' ;
2024-10-17 22:17:23 +00:00
import ' package:tetra_stats/widgets/text_timestamp.dart ' ;
class DestinationGraphs extends StatefulWidget {
final String searchFor ;
//final Function setState;
final BoxConstraints constraints ;
2024-11-22 22:35:16 +00:00
final bool noSidebar ;
2024-10-17 22:17:23 +00:00
2024-11-22 22:35:16 +00:00
const DestinationGraphs ( { super . key , required this . searchFor , required this . constraints , required this . noSidebar } ) ;
2024-10-17 22:17:23 +00:00
@ override
State < DestinationGraphs > createState ( ) = > _DestinationGraphsState ( ) ;
}
2024-11-22 22:35:16 +00:00
Graph graph = Graph . history ;
Stats Ychart = Stats . tr ;
2024-10-17 22:17:23 +00:00
enum Graph {
history ,
leagueState ,
leagueCutoffs
}
class _DestinationGraphsState extends State < DestinationGraphs > {
bool fetchData = false ;
bool _gamesPlayedInsteadOfDateAndTime = false ;
late ZoomPanBehavior _zoomPanBehavior ;
late TooltipBehavior _historyTooltipBehavior ;
late TooltipBehavior _tooltipBehavior ;
late TooltipBehavior _leagueTooltipBehavior ;
String yAxisTitle = " " ;
bool _smooth = false ;
final List < DropdownMenuItem < Stats > > _yAxis = [ for ( MapEntry e in chartsShortTitles . entries ) DropdownMenuItem ( value: e . key , child: Text ( e . value ) ) ] ;
Stats _Xchart = Stats . tr ;
int _season = currentSeason - 1 ;
2024-10-29 22:10:19 +00:00
ValueNotifier < String > historyPlayerUsername = ValueNotifier ( " " ) ;
ValueNotifier < String > historyPlayerAvatarRevizion = ValueNotifier ( " " ) ;
2024-10-28 21:55:38 +00:00
List < String > excludeRanks = [ ] ;
2025-01-17 22:00:46 +00:00
late Future < Map < int , Map < Stats , List < _HistoryChartSpot > > > > playerHistory = getHistoryData ( fetchData ) ;
2024-11-22 22:35:16 +00:00
late Future < List < _MyScatterSpot > > futureLeague = getTetraLeagueData ( _Xchart , Ychart ) ;
2024-10-28 21:55:38 +00:00
String searchLeague = " " ;
2024-12-31 19:51:10 +00:00
int ? TLstatePlayers ;
DateTime ? TLrelevance ;
2024-10-17 22:17:23 +00:00
@ override
void initState ( ) {
_historyTooltipBehavior = TooltipBehavior (
color: Colors . black ,
borderColor: Colors . white ,
enable: true ,
animationDuration: 0 ,
builder: ( dynamic data , dynamic point , dynamic series ,
int pointIndex , int seriesIndex ) {
return Padding (
padding: const EdgeInsets . all ( 8.0 ) ,
child: Column (
mainAxisSize: MainAxisSize . min ,
children: [
Padding (
padding: const EdgeInsets . only ( bottom: 8.0 ) ,
child: Text (
" ${ f4 . format ( data . stat ) } $ yAxisTitle " ,
style: const TextStyle ( fontFamily: " Eurostile Round " , fontSize: 20 ) ,
) ,
) ,
2024-11-28 20:37:07 +00:00
Text ( _gamesPlayedInsteadOfDateAndTime ? t . graphsDestination . gamesPlayed ( games: t . stats . games ( n: data . gamesPlayed ) ) : timestamp ( data . timestamp ) )
2024-10-17 22:17:23 +00:00
] ,
) ,
) ;
}
) ;
_tooltipBehavior = TooltipBehavior (
color: Colors . black ,
borderColor: Colors . white ,
enable: true ,
animationDuration: 0 ,
builder: ( dynamic data , dynamic point , dynamic series ,
int pointIndex , int seriesIndex ) {
return Padding (
padding: const EdgeInsets . all ( 8.0 ) ,
child: Column (
mainAxisSize: MainAxisSize . min ,
children: [
Padding (
padding: const EdgeInsets . only ( bottom: 8.0 ) ,
child: Text (
" ${ data . nickname } ( ${ data . rank . toUpperCase ( ) } ) " ,
style: const TextStyle ( fontFamily: " Eurostile Round Extended " , fontSize: 20 ) ,
) ,
) ,
2024-11-22 22:35:16 +00:00
Text ( ' ${ f4 . format ( data . x ) } ${ chartsShortTitles [ _Xchart ] } \n ${ f4 . format ( data . y ) } ${ chartsShortTitles [ Ychart ] } ' )
2024-10-17 22:17:23 +00:00
] ,
) ,
) ;
}
) ;
_leagueTooltipBehavior = TooltipBehavior (
color: Colors . black ,
borderColor: Colors . white ,
enable: true ,
animationDuration: 0 ,
builder: ( dynamic data , dynamic point , dynamic series ,
int pointIndex , int seriesIndex ) {
return Padding (
padding: const EdgeInsets . all ( 8.0 ) ,
child: Column (
mainAxisSize: MainAxisSize . min ,
children: [
Padding (
padding: const EdgeInsets . only ( bottom: 8.0 ) ,
child: Text (
" ${ f4 . format ( point . y ) } $ yAxisTitle " ,
style: const TextStyle ( fontFamily: " Eurostile Round " , fontSize: 20 ) ,
) ,
) ,
Text ( timestamp ( data . ts ) )
] ,
) ,
) ;
}
) ;
_zoomPanBehavior = ZoomPanBehavior (
enablePinching: true ,
enableSelectionZooming: true ,
enableMouseWheelZooming : true ,
enablePanning: true ,
) ;
super . initState ( ) ;
}
2024-10-20 23:05:23 +00:00
Future < Map < int , Map < Stats , List < _HistoryChartSpot > > > > getHistoryData ( bool fetchHistory ) async {
2025-01-17 22:00:46 +00:00
var playerID = ( await teto . fetchPlayer ( widget . searchFor ) ) . userId ;
2024-10-17 22:17:23 +00:00
if ( fetchHistory ) {
try {
2025-01-17 22:00:46 +00:00
//var history = await Future.wait([teto.fetchAndsaveS1TLHistory(widget.searchFor), teto.fetchAndsaveS2TLHistory(widget.searchFor)]); // S1 history unavaliable because of certificate issue on p1nkl0bst3r side
var history = await teto . fetchAndsaveS2TLHistory ( playerID ) ;
2024-11-28 20:37:07 +00:00
if ( context . mounted ) ScaffoldMessenger . of ( context ) . showSnackBar ( SnackBar ( content: Text ( t . graphsDestination . fetchAndsaveTLHistoryResult ( number: history . length ) ) ) ) ;
2024-10-17 22:17:23 +00:00
} on TetrioHistoryNotExist {
2024-11-28 20:37:07 +00:00
if ( context . mounted ) ScaffoldMessenger . of ( context ) . showSnackBar ( SnackBar ( content: Text ( t . errors . noHistorySaved ) ) ) ;
2024-10-17 22:17:23 +00:00
} on P1nkl0bst3rForbidden {
if ( context . mounted ) ScaffoldMessenger . of ( context ) . showSnackBar ( SnackBar ( content: Text ( t . errors . p1nkl0bst3rForbidden ) ) ) ;
} on P1nkl0bst3rInternalProblem {
if ( context . mounted ) ScaffoldMessenger . of ( context ) . showSnackBar ( SnackBar ( content: Text ( t . errors . p1nkl0bst3rinternal ) ) ) ;
} on P1nkl0bst3rTooManyRequests {
if ( context . mounted ) ScaffoldMessenger . of ( context ) . showSnackBar ( SnackBar ( content: Text ( t . errors . p1nkl0bst3rTooManyRequests ) ) ) ;
}
}
List < List < TetraLeague > > states = await Future . wait < List < TetraLeague > > ( [
2025-01-17 22:00:46 +00:00
teto . getStates ( playerID , season: 1 ) , teto . getStates ( playerID , season: 2 ) ,
2024-10-17 22:17:23 +00:00
] ) ;
2024-10-20 23:05:23 +00:00
Map < int , Map < Stats , List < _HistoryChartSpot > > > historyData = { } ; // [season][metric][spot]
2024-10-17 22:17:23 +00:00
for ( int season = 0 ; season < currentSeason ; season + + ) {
if ( states [ season ] . length > = 2 ) {
Map < Stats , List < _HistoryChartSpot > > statsMap = { } ;
2025-01-17 22:00:46 +00:00
for ( var stat in Stats . values ) statsMap [ stat ] = [ for ( var tl in states [ season ] ) if ( tl . getStatByEnum ( stat ) ! = null & & tl . getStatByEnum ( stat ) ! = - 1.00 ) _HistoryChartSpot ( tl . timestamp , tl . gamesPlayed , tl . rank , tl . getStatByEnum ( stat ) ! . toDouble ( ) ) ] ;
2024-10-20 23:05:23 +00:00
historyData [ season ] = statsMap ;
2024-10-17 22:17:23 +00:00
}
}
fetchData = false ;
2025-01-17 22:00:46 +00:00
historyPlayerUsername . value = await teto . getNicknameByID ( playerID ) ;
2024-11-01 00:05:26 +00:00
2024-10-17 22:17:23 +00:00
return historyData ;
}
Future < List < _MyScatterSpot > > getTetraLeagueData ( Stats x , Stats y ) async {
TetrioPlayersLeaderboard leaderboard = await teto . fetchTLLeaderboard ( ) ;
2024-12-31 19:51:10 +00:00
TLrelevance = leaderboard . timestamp ;
TLstatePlayers = leaderboard . leaderboard . length ;
2024-10-17 22:17:23 +00:00
List < _MyScatterSpot > _spots = [
for ( TetrioPlayerFromLeaderboard entry in leaderboard . leaderboard )
2024-10-28 21:55:38 +00:00
if ( excludeRanks . indexOf ( entry . rank ) = = - 1 ) _MyScatterSpot (
2024-10-17 22:17:23 +00:00
entry . getStatByEnum ( x ) . toDouble ( ) ,
entry . getStatByEnum ( y ) . toDouble ( ) ,
entry . userId ,
entry . username ,
entry . rank ,
2024-10-29 22:10:19 +00:00
( rankColors [ entry . rank ] ? ? Colors . white ) . withOpacity ( ( searchLeague . isEmpty | | entry . username . startsWith ( searchLeague . toLowerCase ( ) ) ) ? 1.0 : 0.005 )
2024-10-17 22:17:23 +00:00
)
] ;
return _spots ;
}
2024-10-28 21:55:38 +00:00
bool ? getTotalFilterValue ( ) {
if ( excludeRanks . isEmpty ) return true ;
if ( excludeRanks . length = = ranks . length ) return false ;
return null ;
}
2024-10-17 22:17:23 +00:00
Widget getHistoryGraph ( ) {
2024-10-20 23:05:23 +00:00
return FutureBuilder < Map < int , Map < Stats , List < _HistoryChartSpot > > > > (
2024-10-17 22:17:23 +00:00
future: getHistoryData ( fetchData ) ,
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 . hasData ) {
2024-11-28 20:37:07 +00:00
if ( snapshot . data ! . isEmpty | | ! snapshot . data ! . containsKey ( _season ) ) return ErrorThingy ( eText: t . errors . notEnoughData ) ;
2024-11-22 22:35:16 +00:00
List < _HistoryChartSpot > selectedGraph = snapshot . data ! [ _season ] ! [ Ychart ] ! ;
yAxisTitle = chartsShortTitles [ Ychart ] ! ;
2024-10-17 22:17:23 +00:00
return SfCartesianChart (
tooltipBehavior: _historyTooltipBehavior ,
zoomPanBehavior: _zoomPanBehavior ,
primaryXAxis: _gamesPlayedInsteadOfDateAndTime ? const NumericAxis ( ) : const DateTimeAxis ( ) ,
primaryYAxis: const NumericAxis (
rangePadding: ChartRangePadding . additional ,
) ,
margin: const EdgeInsets . all ( 0 ) ,
series: < CartesianSeries > [
if ( _gamesPlayedInsteadOfDateAndTime ) StepLineSeries < _HistoryChartSpot , int > (
enableTooltip: true ,
dataSource: selectedGraph ,
animationDuration: 0 ,
opacity: _smooth ? 0 : 1 ,
xValueMapper: ( _HistoryChartSpot data , _ ) = > data . gamesPlayed ,
yValueMapper: ( _HistoryChartSpot data , _ ) = > data . stat ,
color: Theme . of ( context ) . colorScheme . primary ,
trendlines: < Trendline > [
Trendline (
isVisible: _smooth ,
2025-01-17 22:00:46 +00:00
period: ( selectedGraph . length / 100 ) . floor ( ) ,
2024-10-17 22:17:23 +00:00
type: TrendlineType . movingAverage ,
color: Theme . of ( context ) . colorScheme . primary )
] ,
)
else StepLineSeries < _HistoryChartSpot , DateTime > (
enableTooltip: true ,
dataSource: selectedGraph ,
animationDuration: 0 ,
opacity: _smooth ? 0 : 1 ,
xValueMapper: ( _HistoryChartSpot data , _ ) = > data . timestamp ,
yValueMapper: ( _HistoryChartSpot data , _ ) = > data . stat ,
color: Theme . of ( context ) . colorScheme . primary ,
trendlines: < Trendline > [
Trendline (
isVisible: _smooth ,
2025-01-17 22:00:46 +00:00
period: ( selectedGraph . length / 100 ) . floor ( ) ,
2024-10-17 22:17:23 +00:00
type: TrendlineType . movingAverage ,
color: Theme . of ( context ) . colorScheme . primary )
] ,
) ,
] ,
) ;
} else { return FutureError ( snapshot ) ; }
}
}
) ;
}
Widget getLeagueState ( ) {
return FutureBuilder < List < _MyScatterSpot > > (
2024-10-28 21:55:38 +00:00
future: futureLeague ,
2024-10-17 22:17:23 +00:00
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 . hasData ) {
return SfCartesianChart (
tooltipBehavior: _tooltipBehavior ,
zoomPanBehavior: _zoomPanBehavior ,
//primaryXAxis: CategoryAxis(),
series: [
ScatterSeries (
enableTooltip: true ,
dataSource: snapshot . data ,
animationDuration: 0 ,
pointColorMapper: ( data , _ ) = > data . color ,
2024-10-29 22:10:19 +00:00
markerSettings: MarkerSettings (
isVisible: false ,
borderColor: Colors . black ,
) ,
2024-10-17 22:17:23 +00:00
xValueMapper: ( data , _ ) = > data . x ,
yValueMapper: ( data , _ ) = > data . y ,
2024-11-23 18:41:48 +00:00
onPointTap: ( point ) = > Navigator . push ( context , MaterialPageRoute ( builder: ( context ) = > MainView ( player: snapshot . data ! [ point . pointIndex ! ] . nickname ) ) ) ,
2024-10-17 22:17:23 +00:00
)
] ,
) ;
} else { return FutureError ( snapshot ) ; }
}
}
) ;
}
Widget getCutoffsHistory ( ) {
return FutureBuilder < List < Cutoffs > > (
future: teto . fetchCutoffsHistory ( ) ,
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 . hasData ) {
2024-11-22 22:35:16 +00:00
yAxisTitle = chartsShortTitles [ Ychart ] ! ;
2024-10-17 22:17:23 +00:00
return SfCartesianChart (
tooltipBehavior: _leagueTooltipBehavior ,
zoomPanBehavior: _zoomPanBehavior ,
primaryXAxis: const DateTimeAxis ( ) ,
primaryYAxis: NumericAxis (
// isInversed: true,
2024-11-22 22:35:16 +00:00
maximum: switch ( Ychart ) {
2024-10-17 22:17:23 +00:00
Stats . tr = > 25000.0 ,
Stats . gxe = > 100.00 ,
_ = > null
} ,
) ,
margin: const EdgeInsets . all ( 0 ) ,
series: < CartesianSeries > [
for ( String rank in ranks ) StepLineSeries < Cutoffs , DateTime > (
enableTooltip: true ,
dataSource: snapshot . data ,
animationDuration: 0 ,
//opacity: 0.5,
xValueMapper: ( Cutoffs data , _ ) = > data . ts ,
2024-11-22 22:35:16 +00:00
yValueMapper: ( Cutoffs data , _ ) = > switch ( Ychart ) {
2024-10-17 22:17:23 +00:00
Stats . glicko = > data . glicko [ rank ] ,
Stats . gxe = > data . gxe [ rank ] ,
_ = > data . tr [ rank ]
} ,
color: rankColors [ rank ] !
)
] ,
) ;
} else { return FutureError ( snapshot ) ; }
}
}
) ;
}
@ override
Widget build ( BuildContext context ) {
2024-11-22 22:35:16 +00:00
return SingleChildScrollView (
child: Column (
mainAxisSize: MainAxisSize . min ,
children: [
Column (
2024-10-17 22:17:23 +00:00
mainAxisSize: MainAxisSize . min ,
children: [
Card (
child: Wrap (
spacing: 20 ,
crossAxisAlignment: WrapCrossAlignment . center ,
2024-11-22 22:35:16 +00:00
alignment: WrapAlignment . center ,
2024-10-17 22:17:23 +00:00
children: [
2024-12-31 19:51:10 +00:00
if ( graph = = Graph . leagueState & & TLstatePlayers ! = null & & TLrelevance ! = null ) Row (
mainAxisSize: MainAxisSize . min ,
children: [
Padding (
padding: const EdgeInsets . only ( left: 8.0 ) ,
child: RichText (
textAlign: TextAlign . right ,
text: TextSpan (
style: TextStyle ( color: Colors . white , fontFamily: " Eurostile Round " ) ,
children: [
TextSpan ( text: t . stats . players ( n: TLstatePlayers ! ) ) ,
TextSpan ( text: " \n " ) ,
TextSpan ( text: timestamp ( TLrelevance ! ) )
]
)
) ,
)
] ,
) ,
2024-11-22 22:35:16 +00:00
if ( graph = = Graph . history ) Row (
2024-10-29 22:10:19 +00:00
mainAxisSize: MainAxisSize . min ,
children: [
Icon ( Icons . person ) ,
Padding (
padding: EdgeInsets . all ( 8.0 ) ,
child: ValueListenableBuilder < String > (
valueListenable: historyPlayerUsername ,
builder: ( context , value , child ) {
return Text ( value , style: TextStyle ( fontSize: 22 , fontFamily: " Eurostile Round Extended " ) ) ;
} ,
)
) ,
] ,
) ,
2024-11-22 22:35:16 +00:00
if ( graph = = Graph . leagueState ) SizedBox (
2024-10-28 21:55:38 +00:00
width: 300 ,
child: TextField (
2024-10-29 22:10:19 +00:00
style: TextStyle ( fontSize: 18.0000 ) ,
2024-10-28 21:55:38 +00:00
decoration: InputDecoration (
2024-10-29 22:10:19 +00:00
icon: Icon ( Icons . search ) ,
isDense: true
2024-10-28 21:55:38 +00:00
) ,
onChanged: ( v ) {
searchLeague = v ;
} ,
onSubmitted: ( v ) {
searchLeague = v ;
2024-11-22 22:35:16 +00:00
setState ( ( ) { futureLeague = getTetraLeagueData ( _Xchart , Ychart ) ; } ) ;
2024-10-28 21:55:38 +00:00
} ,
)
) ,
2024-11-22 22:35:16 +00:00
if ( graph = = Graph . history ) Row (
2024-10-17 22:17:23 +00:00
mainAxisSize: MainAxisSize . min ,
children: [
2024-11-28 20:37:07 +00:00
Padding ( padding: EdgeInsets . all ( 8.0 ) , child: Text ( " ${ t . season } : " , style: TextStyle ( fontSize: 22 ) ) ) ,
2024-10-17 22:17:23 +00:00
DropdownButton (
items: [ for ( int i = 1 ; i < = currentSeason ; i + + ) DropdownMenuItem ( value: i - 1 , child: Text ( " $ i " ) ) ] ,
value: _season ,
onChanged: ( value ) {
setState ( ( ) {
_season = value ! ;
} ) ;
}
) ,
] ,
) ,
2024-11-22 22:35:16 +00:00
if ( graph ! = Graph . leagueCutoffs ) Row (
2024-10-17 22:17:23 +00:00
mainAxisSize: MainAxisSize . min ,
children: [
const Padding ( padding: EdgeInsets . all ( 8.0 ) , child: Text ( " X: " , style: TextStyle ( fontSize: 22 ) ) ) ,
DropdownButton (
2024-11-22 22:35:16 +00:00
items: switch ( graph ) {
2024-11-28 20:37:07 +00:00
Graph . history = > [ DropdownMenuItem ( value: false , child: Text ( t . graphsDestination . dateAndTime ) ) , DropdownMenuItem ( value: true , child: Text ( t . stats . gp . full ) ) ] ,
2024-10-17 22:17:23 +00:00
Graph . leagueState = > _yAxis ,
Graph . leagueCutoffs = > [ ] ,
} ,
2024-11-22 22:35:16 +00:00
value: graph = = Graph . history ? _gamesPlayedInsteadOfDateAndTime : _Xchart ,
2024-10-17 22:17:23 +00:00
onChanged: ( value ) {
setState ( ( ) {
2024-11-22 22:35:16 +00:00
if ( graph = = Graph . history )
2024-10-17 22:17:23 +00:00
_gamesPlayedInsteadOfDateAndTime = value ! as bool ;
2024-12-31 19:51:10 +00:00
else {
_Xchart = value ! as Stats ;
setState ( ( ) { futureLeague = getTetraLeagueData ( _Xchart , Ychart ) ; } ) ;
}
2024-10-17 22:17:23 +00:00
} ) ;
}
) ,
] ,
) ,
Row (
mainAxisSize: MainAxisSize . min ,
children: [
const Padding ( padding: EdgeInsets . all ( 8.0 ) , child: Text ( " Y: " , style: TextStyle ( fontSize: 22 ) ) ) ,
DropdownButton < Stats > (
2024-11-22 22:35:16 +00:00
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 ,
2024-10-17 22:17:23 +00:00
onChanged: ( value ) {
setState ( ( ) {
2024-11-22 22:35:16 +00:00
Ychart = value ! ;
2024-12-31 19:51:10 +00:00
futureLeague = getTetraLeagueData ( _Xchart , Ychart ) ;
2024-10-17 22:17:23 +00:00
} ) ;
}
) ,
] ,
) ,
2024-11-22 22:35:16 +00:00
if ( graph = = Graph . history ) Row (
2024-10-17 22:17:23 +00:00
mainAxisSize: MainAxisSize . min ,
children: [
Checkbox ( value: _smooth ,
checkColor: Colors . black ,
onChanged: ( ( value ) {
setState ( ( ) {
_smooth = value ! ;
} ) ;
} ) ) ,
Text ( t . smooth , style: const TextStyle ( color: Colors . white , fontSize: 22 ) )
] ,
) ,
2024-11-22 22:35:16 +00:00
if ( graph = = Graph . leagueState ) IconButton (
2024-10-28 21:55:38 +00:00
color: excludeRanks . isNotEmpty ? Theme . of ( context ) . colorScheme . primary : null ,
onPressed: ( ) {
showDialog ( context: context , builder: ( BuildContext context ) {
return StatefulBuilder (
builder: ( context , StateSetter setAlertState ) {
return AlertDialog (
2024-11-28 20:37:07 +00:00
title: Text ( t . graphsDestination . filterModaleTitle , textAlign: TextAlign . center ) ,
2024-10-28 21:55:38 +00:00
content: SingleChildScrollView (
child: Column (
children: [
2024-11-28 20:37:07 +00:00
CheckboxListTile ( value: getTotalFilterValue ( ) , tristate: true , title: Text ( t . filterModale . all , style: TextStyle ( fontFamily: " Eurostile Round Extended " ) ) , onChanged: ( value ) {
2024-10-28 21:55:38 +00:00
setAlertState (
( ) {
if ( excludeRanks . length * 2 > ranks . length ) {
excludeRanks . clear ( ) ;
} else {
excludeRanks = List . of ( ranks ) ;
}
}
) ;
} ) ,
for ( String rank in ranks . reversed ) CheckboxListTile ( value: excludeRanks . indexOf ( rank ) = = - 1 , onChanged: ( value ) {
setAlertState (
( ) {
if ( excludeRanks . indexOf ( rank ) = = - 1 ) {
excludeRanks . add ( rank ) ;
} else {
excludeRanks . remove ( rank ) ;
}
}
) ;
} , title: Text ( rank . toUpperCase ( ) ) , )
] ,
) ,
) ,
actions: < Widget > [
TextButton (
2024-11-28 20:37:07 +00:00
child: Text ( t . actions . cancel ) ,
onPressed: ( ) { Navigator . of ( context ) . pop ( ) ; }
) ,
TextButton (
child: Text ( t . actions . apply ) ,
2024-11-22 22:35:16 +00:00
onPressed: ( ) { Navigator . of ( context ) . pop ( ) ; setState ( ( ) { futureLeague = getTetraLeagueData ( _Xchart , Ychart ) ; } ) ; }
2024-11-28 20:37:07 +00:00
)
2024-10-28 21:55:38 +00:00
]
) ;
}
) ;
} ) ;
} , icon: Icon ( Icons . filter_alt ) ) ,
2025-01-17 22:00:46 +00:00
IconButton ( onPressed: ( ) = > _zoomPanBehavior . reset ( ) , icon: const Icon ( Icons . refresh ) , alignment: Alignment . center , ) ,
if ( graph = = Graph . history ) ElevatedButton . icon (
onPressed: ( ) {
setState ( ( ) {
fetchData = true ;
} ) ;
} ,
label: Text ( t . graphsDestination . fetchAndsaveTLHistory ) ,
icon: Icon ( Icons . download ) ,
)
2024-10-17 22:17:23 +00:00
] ,
) ,
) ,
Card (
child: SizedBox (
2024-11-22 22:35:16 +00:00
width: MediaQuery . of ( context ) . size . width - ( widget . noSidebar ? 0 : 88 ) ,
2024-10-17 22:17:23 +00:00
height: MediaQuery . of ( context ) . size . height - 96 ,
child: Padding ( padding: const EdgeInsets . fromLTRB ( 40 , 30 , 40 , 30 ) ,
2024-11-22 22:35:16 +00:00
child: switch ( graph ) {
2024-10-17 22:17:23 +00:00
Graph . history = > getHistoryGraph ( ) ,
Graph . leagueState = > getLeagueState ( ) ,
Graph . leagueCutoffs = > getCutoffsHistory ( )
} ,
)
) ,
)
] ,
) ,
2024-11-22 22:35:16 +00:00
if ( ! widget . noSidebar ) SegmentedButton < Graph > (
showSelectedIcon: false ,
segments: < ButtonSegment < Graph > > [
2024-11-28 20:37:07 +00:00
ButtonSegment < Graph > (
2024-11-22 22:35:16 +00:00
value: Graph . history ,
2024-11-28 20:37:07 +00:00
label: Text ( t . graphsNavigation . history ) ) ,
2024-11-22 22:35:16 +00:00
ButtonSegment < Graph > (
value: Graph . leagueState ,
2024-11-28 20:37:07 +00:00
label: Text ( t . graphsNavigation . league ) ) ,
2024-11-22 22:35:16 +00:00
ButtonSegment < Graph > (
value: Graph . leagueCutoffs ,
2024-11-28 20:37:07 +00:00
label: Text ( t . graphsNavigation . cutoffs ) ,
2024-11-22 22:35:16 +00:00
) ,
] ,
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 ;
}
} ) ; } )
] ,
) ,
2024-10-17 22:17:23 +00:00
) ;
}
2025-01-17 22:00:46 +00:00
void markNeedsBuild ( ) {
}
2024-10-17 22:17:23 +00:00
}
class _HistoryChartSpot {
final DateTime timestamp ;
final int gamesPlayed ;
final String rank ;
final double stat ;
const _HistoryChartSpot ( this . timestamp , this . gamesPlayed , this . rank , this . stat ) ;
}
class _MyScatterSpot {
num x ;
num y ;
String id ;
String nickname ;
String rank ;
Color color ;
_MyScatterSpot ( this . x , this . y , this . id , this . nickname , this . rank , this . color ) ;
}