import 'package:anyway/constants.dart'; import 'package:flutter/material.dart'; import 'package:auto_size_text/auto_size_text.dart'; import 'package:anyway/structs/trip.dart'; import 'package:anyway/pages/current_trip.dart'; final List statusTexts = [ 'Parsing your preferences...', 'Finding the best places...', 'Crunching the numbers...', 'Calculating the best route...', 'Making sure you have a great time...', ]; class CurrentTripLoadingIndicator extends StatefulWidget { final Trip trip; const CurrentTripLoadingIndicator({ super.key, required this.trip, }); @override State createState() => _CurrentTripLoadingIndicatorState(); } class _CurrentTripLoadingIndicatorState extends State { @override Widget build(BuildContext context) => Stack( fit: StackFit.expand, children: [ // In the very center of the panel, show the greeter which tells the user that the trip is being generated Center(child: loadingText(widget.trip)), // As a gimmick, and a way to show that the app is still working, show a few loading dots Align( alignment: Alignment.bottomCenter, child: statusText(), ) ], ); } // automatically cycle through the greeter texts class statusText extends StatefulWidget { const statusText({Key? key}) : super(key: key); @override _statusTextState createState() => _statusTextState(); } class _statusTextState extends State { int statusIndex = 0; @override void initState() { super.initState(); Future.delayed(Duration(seconds: 5), () { setState(() { statusIndex = (statusIndex + 1) % statusTexts.length; }); }); } @override Widget build(BuildContext context) { return AutoSizeText( statusTexts[statusIndex], style: Theme.of(context).textTheme.labelSmall, ); } } Widget loadingText(Trip trip) => FutureBuilder( future: trip.cityName, builder: (BuildContext context, AsyncSnapshot snapshot) { Widget greeter; if (snapshot.hasData) { greeter = AnimatedGradientText( text: 'Creating your trip to ${snapshot.data}...', style: greeterStyle, ); } else if (snapshot.hasError) { // the exact error is shown in the central part of the trip overview. No need to show it here greeter = AnimatedGradientText( text: 'Error while loading trip.', style: greeterStyle, ); } else { greeter = AnimatedGradientText( text: 'Creating your trip...', style: greeterStyle, ); } return greeter; } ); class AnimatedGradientText extends StatefulWidget { final String text; final TextStyle style; const AnimatedGradientText({ Key? key, required this.text, required this.style, }) : super(key: key); @override _AnimatedGradientTextState createState() => _AnimatedGradientTextState(); } class _AnimatedGradientTextState extends State with SingleTickerProviderStateMixin { late AnimationController _controller; @override void initState() { super.initState(); _controller = AnimationController( duration: const Duration(seconds: 1), vsync: this, )..repeat(); } @override void dispose() { _controller.dispose(); super.dispose(); } @override Widget build(BuildContext context) { return AnimatedBuilder( animation: _controller, builder: (context, child) { return ShaderMask( shaderCallback: (bounds) { return LinearGradient( colors: [GRADIENT_START, GRADIENT_END, GRADIENT_START], stops: [ _controller.value - 1.0, _controller.value, _controller.value + 1.0, ], tileMode: TileMode.mirror, ).createShader(bounds); }, child: Text( widget.text, style: widget.style, ), ); }, ); } }