Thinking about animations...

This commit is contained in:
dan63047 2024-09-11 00:22:17 +03:00
parent 500639df05
commit 6b84e67f33
1 changed files with 243 additions and 189 deletions

View File

@ -42,6 +42,8 @@ import 'package:tetra_stats/widgets/tl_progress_bar.dart';
import 'package:tetra_stats/widgets/user_thingy.dart'; import 'package:tetra_stats/widgets/user_thingy.dart';
var fDiff = NumberFormat("+#,###.####;-#,###.####"); var fDiff = NumberFormat("+#,###.####;-#,###.####");
late Future<FetchResults> _data;
late Future<News> _newsData;
class MainView extends StatefulWidget { class MainView extends StatefulWidget {
final String? player; final String? player;
@ -78,12 +80,44 @@ class _MainState extends State<MainView> with TickerProviderStateMixin {
void initState() { void initState() {
teto.open(); teto.open();
controller = ScrollController(); controller = ScrollController();
changePlayer(_searchFor);
super.initState(); super.initState();
} }
Future<FetchResults> _getData() async {
TetrioPlayer player;
try{
if (_searchFor.startsWith("ds:")){
player = await teto.fetchPlayer(_searchFor.substring(3), isItDiscordID: true); // we trying to get him with that
}else{
player = await teto.fetchPlayer(_searchFor); // Otherwise it's probably a user id or username
}
}on TetrioPlayerNotExist{
return FetchResults(false, null, [], null, null, TetrioPlayerNotExist());
}
late Summaries summaries;
late Cutoffs cutoffs;
List<dynamic> requests = await Future.wait([
teto.fetchSummaries(player.userId),
teto.fetchCutoffsBeanserver(),
]);
List<TetraLeague> states = await teto.getStates(player.userId, season: currentSeason);
summaries = requests[0];
cutoffs = requests[1];
bool isTracking = await teto.isPlayerTracking(player.userId);
if (isTracking){ // if tracked - save data to local DB
await teto.storeState(summaries.league);
}
return FetchResults(true, player, states, summaries, cutoffs, null);
}
void changePlayer(String player) { void changePlayer(String player) {
setState(() { setState(() {
_searchFor = player; _searchFor = player;
_data = _getData();
_newsData = teto.fetchNews(_searchFor);
}); });
} }
@ -114,36 +148,47 @@ class _MainState extends State<MainView> with TickerProviderStateMixin {
return Row( return Row(
mainAxisAlignment: MainAxisAlignment.center, mainAxisAlignment: MainAxisAlignment.center,
children: [ children: [
NavigationRail( TweenAnimationBuilder(
leading: FloatingActionButton( child: NavigationRail(
elevation: 0, leading: FloatingActionButton(
onPressed: () { elevation: 0,
Scaffold.of(context).openDrawer(); onPressed: () {
}, Scaffold.of(context).openDrawer();
child: const Icon(Icons.search), },
), child: const Icon(Icons.search),
trailing: IconButton( ),
onPressed: () { trailing: IconButton(
// Add your onPressed code here! onPressed: () {
}, // Add your onPressed code here!
icon: const Icon(Icons.more_horiz_rounded), },
), icon: const Icon(Icons.more_horiz_rounded),
destinations: [ ),
getDestinationButton(Icons.home, "Home"), destinations: [
getDestinationButton(Icons.data_thresholding_outlined, "Graphs"), getDestinationButton(Icons.home, "Home"),
getDestinationButton(Icons.leaderboard, "Leaderboards"), getDestinationButton(Icons.data_thresholding_outlined, "Graphs"),
getDestinationButton(Icons.compress, "Cutoffs"), getDestinationButton(Icons.leaderboard, "Leaderboards"),
getDestinationButton(Icons.calculate, "Calc"), getDestinationButton(Icons.compress, "Cutoffs"),
getDestinationButton(Icons.storage, "Saved Data"), getDestinationButton(Icons.calculate, "Calc"),
getDestinationButton(Icons.settings, "Settings"), getDestinationButton(Icons.storage, "Saved Data"),
], getDestinationButton(Icons.settings, "Settings"),
selectedIndex: destination, ],
onDestinationSelected: (value) { selectedIndex: destination,
setState(() { onDestinationSelected: (value) {
destination = value; setState(() {
}); destination = value;
}, });
), },
),
duration: Durations.long4,
tween: Tween<double>(begin: 0, end: 1),
curve: Easing.emphasizedDecelerate,
builder: (context, value, child) {
return Container(
transform: Matrix4.translationValues(-80+value*80, 0, 0),
child: child,
);
},
),
Expanded( Expanded(
child: switch (destination){ child: switch (destination){
0 => DestinationHome(searchFor: _searchFor, constraints: constraints), 0 => DestinationHome(searchFor: _searchFor, constraints: constraints),
@ -691,7 +736,7 @@ class LeagueCard extends StatelessWidget{
} }
class _DestinationHomeState extends State<DestinationHome> { class _DestinationHomeState extends State<DestinationHome> with SingleTickerProviderStateMixin {
Cards rightCard = Cards.overview; Cards rightCard = Cards.overview;
CardMod cardMod = CardMod.info; CardMod cardMod = CardMod.info;
//Duration postSeasonLeft = seasonStart.difference(DateTime.now()); //Duration postSeasonLeft = seasonStart.difference(DateTime.now());
@ -700,38 +745,10 @@ class _DestinationHomeState extends State<DestinationHome> {
late bool blitzBetterThanClosestAverage; late bool blitzBetterThanClosestAverage;
late MapEntry? closestAverageSprint; late MapEntry? closestAverageSprint;
late bool sprintBetterThanClosestAverage; late bool sprintBetterThanClosestAverage;
late AnimationController _transition;
bool? sprintBetterThanRankAverage; bool? sprintBetterThanRankAverage;
bool? blitzBetterThanRankAverage; bool? blitzBetterThanRankAverage;
Future<FetchResults> _getData() async {
TetrioPlayer player;
try{
if (widget.searchFor.startsWith("ds:")){
player = await teto.fetchPlayer(widget.searchFor.substring(3), isItDiscordID: true); // we trying to get him with that
}else{
player = await teto.fetchPlayer(widget.searchFor); // Otherwise it's probably a user id or username
}
}on TetrioPlayerNotExist{
return FetchResults(false, null, [], null, null, TetrioPlayerNotExist());
}
late Summaries summaries;
late Cutoffs cutoffs;
List<dynamic> requests = await Future.wait([
teto.fetchSummaries(player.userId),
teto.fetchCutoffsBeanserver(),
]);
List<TetraLeague> states = await teto.getStates(player.userId, season: currentSeason);
summaries = requests[0];
cutoffs = requests[1];
bool isTracking = await teto.isPlayerTracking(player.userId);
if (isTracking){ // if tracked - save data to local DB
await teto.storeState(summaries.league);
}
return FetchResults(true, player, states, summaries, cutoffs, null);
}
Widget getOverviewCard(Summaries summaries){ Widget getOverviewCard(Summaries summaries){
return Column( return Column(
children: [ children: [
@ -1537,13 +1554,22 @@ class _DestinationHomeState extends State<DestinationHome> {
) )
] ]
}; };
_transition = AnimationController(vsync: this, value: 0, duration: Durations.long4);
_transition.addListener((){
setState(() {
});
});
super.initState(); super.initState();
} }
@override @override
Widget build(BuildContext context) { Widget build(BuildContext context) {
return FutureBuilder<FetchResults>( return FutureBuilder<FetchResults>(
future: _getData(), future: _data,
builder: (context, snapshot) { builder: (context, snapshot) {
switch (snapshot.connectionState){ switch (snapshot.connectionState){
case ConnectionState.none: case ConnectionState.none:
@ -1576,141 +1602,169 @@ class _DestinationHomeState extends State<DestinationHome> {
closestAverageBlitz = blitzAverages.entries.singleWhere((element) => element.value == blitzAverages.values.reduce((a, b) => (a-snapshot.data!.summaries!.blitz!.stats.score).abs() < (b -snapshot.data!.summaries!.blitz!.stats.score).abs() ? a : b)); closestAverageBlitz = blitzAverages.entries.singleWhere((element) => element.value == blitzAverages.values.reduce((a, b) => (a-snapshot.data!.summaries!.blitz!.stats.score).abs() < (b -snapshot.data!.summaries!.blitz!.stats.score).abs() ? a : b));
blitzBetterThanClosestAverage = snapshot.data!.summaries!.blitz!.stats.score > closestAverageBlitz!.value; blitzBetterThanClosestAverage = snapshot.data!.summaries!.blitz!.stats.score > closestAverageBlitz!.value;
} }
return Row( return TweenAnimationBuilder(
children: [ duration: Durations.long4,
SizedBox( tween: Tween<double>(begin: 0, end: 1),
width: 450, curve: Easing.emphasizedDecelerate,
child: Column( builder: (context, value, child) {
children: [ return Container(
NewUserThingy(player: snapshot.data!.player!, showStateTimestamp: false, setState: setState), transform: Matrix4.translationValues(0, 600-value*600, 0),
if (snapshot.data!.player!.badges.isNotEmpty) BadgesThingy(badges: snapshot.data!.player!.badges), child: child,
if (snapshot.data!.player!.distinguishment != null) DistinguishmentThingy(snapshot.data!.player!.distinguishment!), );
if (snapshot.data!.player!.role == "bot") FakeDistinguishmentThingy(bot: true, botMaintainers: snapshot.data!.player!.botmaster), },
if (snapshot.data!.player!.role == "banned") FakeDistinguishmentThingy(banned: true) child: Row(
else if (snapshot.data!.player!.badstanding == true) FakeDistinguishmentThingy(badStanding: true), children: [
if (snapshot.data!.player!.bio != null) Card( SizedBox(
child: Column( width: 450,
children: [ child: Column(
Row( children: [
children: [ NewUserThingy(player: snapshot.data!.player!, showStateTimestamp: false, setState: setState),
const Spacer(), if (snapshot.data!.player!.badges.isNotEmpty) BadgesThingy(badges: snapshot.data!.player!.badges),
Text(t.bio, style: const TextStyle(fontFamily: "Eurostile Round Extended")), if (snapshot.data!.player!.distinguishment != null) DistinguishmentThingy(snapshot.data!.player!.distinguishment!),
const Spacer() if (snapshot.data!.player!.role == "bot") FakeDistinguishmentThingy(bot: true, botMaintainers: snapshot.data!.player!.botmaster),
], if (snapshot.data!.player!.role == "banned") FakeDistinguishmentThingy(banned: true)
), else if (snapshot.data!.player!.badstanding == true) FakeDistinguishmentThingy(badStanding: true),
Padding( if (snapshot.data!.player!.bio != null) Card(
padding: const EdgeInsets.only(bottom: 8.0), child: Column(
child: MarkdownBody(data: snapshot.data!.player!.bio!, styleSheet: MarkdownStyleSheet(textAlign: WrapAlignment.center)), children: [
) Row(
], children: [
const Spacer(),
Text(t.bio, style: const TextStyle(fontFamily: "Eurostile Round Extended")),
const Spacer()
],
),
Padding(
padding: const EdgeInsets.only(bottom: 8.0),
child: MarkdownBody(data: snapshot.data!.player!.bio!, styleSheet: MarkdownStyleSheet(textAlign: WrapAlignment.center)),
)
],
),
), ),
), //if (testNews != null && testNews!.news.isNotEmpty)
//if (testNews != null && testNews!.news.isNotEmpty) Expanded(
Expanded( child: FutureBuilder<News>(
child: FutureBuilder<News>( future: _newsData,
future: teto.fetchNews(widget.searchFor), builder: (context, snapshot) {
builder: (context, snapshot) { switch (snapshot.connectionState){
switch (snapshot.connectionState){ case ConnectionState.none:
case ConnectionState.none: case ConnectionState.waiting:
case ConnectionState.waiting: case ConnectionState.active:
case ConnectionState.active: return const Card(child: Center(child: CircularProgressIndicator()));
return const Card(child: Center(child: CircularProgressIndicator())); case ConnectionState.done:
case ConnectionState.done: if (snapshot.hasData){
if (snapshot.hasData){ return NewsThingy(snapshot.data!);
return NewsThingy(snapshot.data!); }else if (snapshot.hasError){
}else if (snapshot.hasError){ return Card(child: Column(children: [
return Card(child: Column(children: [ Text(snapshot.error.toString(), style: const TextStyle(fontFamily: "Eurostile Round", fontSize: 42, fontWeight: FontWeight.bold), textAlign: TextAlign.center),
Text(snapshot.error.toString(), style: const TextStyle(fontFamily: "Eurostile Round", fontSize: 42, fontWeight: FontWeight.bold), textAlign: TextAlign.center), Text(snapshot.stackTrace.toString())
Text(snapshot.stackTrace.toString()) ]
] ));
)); }
} }
return const Text("what?");
} }
return const Text("what?"); ),
} )
],
),
),
SizedBox(
width: widget.constraints.maxWidth - 450 - 80,
child: Column(
children: [
SizedBox(
height: rightCard != Cards.overview ? widget.constraints.maxHeight - 64 : widget.constraints.maxHeight - 32,
child: SingleChildScrollView(
child: DualTransitionBuilder(
animation: _transition,
forwardBuilder: (context, animation, child){
print(animation);
return Container(
transform: Matrix4.translationValues(600-animation.value*600, 0, 0),
child: child!
);
},
reverseBuilder: (context, animation, child){
return Container(
transform: Matrix4.translationValues(-600+animation.value*600, 0, 0),
child: child!
);
},
child: switch (rightCard){
Cards.overview => getOverviewCard(snapshot.data!.summaries!),
Cards.tetraLeague => switch (cardMod){
CardMod.info => getTetraLeagueCard(snapshot.data!.summaries!.league, snapshot.data!.cutoffs, snapshot.data!.states),
CardMod.ex => getPreviousSeasonsList(snapshot.data!.summaries!.pastLeague),
CardMod.records => getRecentTLrecords(widget.constraints),
_ => const Center(child: Text("huh?"))
},
Cards.quickPlay => switch (cardMod){
CardMod.info => getZenithCard(snapshot.data?.summaries!.zenith),
CardMod.records => getListOfRecords("zenith/recent", "zenith/top", widget.constraints),
CardMod.ex => getZenithCard(snapshot.data?.summaries!.zenithEx),
CardMod.exRecords => getListOfRecords("zenithex/recent", "zenithex/top", widget.constraints),
},
Cards.sprint => switch (cardMod){
CardMod.info => getRecordCard(snapshot.data?.summaries!.sprint, sprintBetterThanRankAverage, closestAverageSprint, sprintBetterThanClosestAverage, snapshot.data!.summaries!.league.rank),
CardMod.records => getListOfRecords("40l/recent", "40l/top", widget.constraints),
_ => const Center(child: Text("huh?"))
},
Cards.blitz => switch (cardMod){
CardMod.info => getRecordCard(snapshot.data?.summaries!.blitz, blitzBetterThanRankAverage, closestAverageBlitz, blitzBetterThanClosestAverage, snapshot.data!.summaries!.league.rank),
CardMod.records => getListOfRecords("blitz/recent", "blitz/top", widget.constraints),
_ => const Center(child: Text("huh?"))
},
},
),
),
), ),
) if (modeButtons[rightCard]!.length > 1) SegmentedButton<CardMod>(
], showSelectedIcon: false,
), selected: <CardMod>{cardMod},
), segments: modeButtons[rightCard]!,
SizedBox( onSelectionChanged: (p0) {
width: widget.constraints.maxWidth - 450 - 80, setState(() {
child: Column( cardMod = p0.first;
children: [ //_transition.;
SizedBox( });
height: rightCard != Cards.overview ? widget.constraints.maxHeight - 64 : widget.constraints.maxHeight - 32,
child: SingleChildScrollView(
child: switch (rightCard){
Cards.overview => getOverviewCard(snapshot.data!.summaries!),
Cards.tetraLeague => switch (cardMod){
CardMod.info => getTetraLeagueCard(snapshot.data!.summaries!.league, snapshot.data!.cutoffs, snapshot.data!.states),
CardMod.ex => getPreviousSeasonsList(snapshot.data!.summaries!.pastLeague),
CardMod.records => getRecentTLrecords(widget.constraints),
_ => const Center(child: Text("huh?"))
},
Cards.quickPlay => switch (cardMod){
CardMod.info => getZenithCard(snapshot.data?.summaries!.zenith),
CardMod.records => getListOfRecords("zenith/recent", "zenith/top", widget.constraints),
CardMod.ex => getZenithCard(snapshot.data?.summaries!.zenithEx),
CardMod.exRecords => getListOfRecords("zenithex/recent", "zenithex/top", widget.constraints),
},
Cards.sprint => switch (cardMod){
CardMod.info => getRecordCard(snapshot.data?.summaries!.sprint, sprintBetterThanRankAverage, closestAverageSprint, sprintBetterThanClosestAverage, snapshot.data!.summaries!.league.rank),
CardMod.records => getListOfRecords("40l/recent", "40l/top", widget.constraints),
_ => const Center(child: Text("huh?"))
},
Cards.blitz => switch (cardMod){
CardMod.info => getRecordCard(snapshot.data?.summaries!.blitz, blitzBetterThanRankAverage, closestAverageBlitz, blitzBetterThanClosestAverage, snapshot.data!.summaries!.league.rank),
CardMod.records => getListOfRecords("blitz/recent", "blitz/top", widget.constraints),
_ => const Center(child: Text("huh?"))
},
}, },
), ),
), SegmentedButton<Cards>(
if (modeButtons[rightCard]!.length > 1) SegmentedButton<CardMod>( showSelectedIcon: false,
showSelectedIcon: false, segments: <ButtonSegment<Cards>>[
selected: <CardMod>{cardMod}, const ButtonSegment<Cards>(
segments: modeButtons[rightCard]!, value: Cards.overview,
onSelectionChanged: (p0) { //label: Text('Overview'),
setState(() { icon: Icon(Icons.calendar_view_day)),
cardMod = p0.first; ButtonSegment<Cards>(
}); value: Cards.tetraLeague,
}, //label: Text('Tetra League'),
), icon: SvgPicture.asset("res/icons/league.svg", height: 16, colorFilter: ColorFilter.mode(theme.colorScheme.primary, BlendMode.modulate))),
SegmentedButton<Cards>( ButtonSegment<Cards>(
showSelectedIcon: false, value: Cards.quickPlay,
segments: <ButtonSegment<Cards>>[ //label: Text('Quick Play'),
const ButtonSegment<Cards>( icon: SvgPicture.asset("res/icons/qp.svg", height: 16, colorFilter: ColorFilter.mode(theme.colorScheme.primary, BlendMode.modulate))),
value: Cards.overview, ButtonSegment<Cards>(
//label: Text('Overview'), value: Cards.sprint,
icon: Icon(Icons.calendar_view_day)), //label: Text('40 Lines'),
ButtonSegment<Cards>( icon: SvgPicture.asset("res/icons/40l.svg", height: 16, colorFilter: ColorFilter.mode(theme.colorScheme.primary, BlendMode.modulate))),
value: Cards.tetraLeague, ButtonSegment<Cards>(
//label: Text('Tetra League'), value: Cards.blitz,
icon: SvgPicture.asset("res/icons/league.svg", height: 16, colorFilter: ColorFilter.mode(theme.colorScheme.primary, BlendMode.modulate))), //label: Text('Blitz'),
ButtonSegment<Cards>( icon: SvgPicture.asset("res/icons/blitz.svg", height: 16, colorFilter: ColorFilter.mode(theme.colorScheme.primary, BlendMode.modulate))),
value: Cards.quickPlay, ],
//label: Text('Quick Play'), selected: <Cards>{rightCard},
icon: SvgPicture.asset("res/icons/qp.svg", height: 16, colorFilter: ColorFilter.mode(theme.colorScheme.primary, BlendMode.modulate))), onSelectionChanged: (Set<Cards> newSelection) {
ButtonSegment<Cards>( setState(() {
value: Cards.sprint, cardMod = CardMod.info;
//label: Text('40 Lines'), rightCard = newSelection.first;
icon: SvgPicture.asset("res/icons/40l.svg", height: 16, colorFilter: ColorFilter.mode(theme.colorScheme.primary, BlendMode.modulate))), });})
ButtonSegment<Cards>( ],
value: Cards.blitz, )
//label: Text('Blitz'),
icon: SvgPicture.asset("res/icons/blitz.svg", height: 16, colorFilter: ColorFilter.mode(theme.colorScheme.primary, BlendMode.modulate))),
],
selected: <Cards>{rightCard},
onSelectionChanged: (Set<Cards> newSelection) {
setState(() {
cardMod = CardMod.info;
rightCard = newSelection.first;
});})
],
) )
) ],
], ),
); );
} }
} }