import 'dart:async'; 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 const Align( alignment: Alignment.bottomCenter, child: Padding( padding: EdgeInsets.only(bottom: 12), 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(const 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 = AnimatedDotsText( baseText: '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 = Text( 'Error while loading trip.', style: greeterStyle, ); } else { greeter = AnimatedDotsText( baseText: 'Creating your trip', style: greeterStyle, ); } return greeter; } ); class AnimatedDotsText extends StatefulWidget { final String baseText; final TextStyle style; const AnimatedDotsText({ Key? key, required this.baseText, required this.style, }) : super(key: key); @override _AnimatedDotsTextState createState() => _AnimatedDotsTextState(); } class _AnimatedDotsTextState extends State { int dotCount = 0; @override void initState() { super.initState(); Timer.periodic(const Duration(seconds: 1), (timer) { if (mounted) { setState(() { dotCount = (dotCount + 1) % 4; // show up to 3 dots }); } else { timer.cancel(); } }); } @override Widget build(BuildContext context) { String dots = '.' * dotCount; return AutoSizeText( '${widget.baseText}$dots', style: widget.style, maxLines: 2, ); } }