anyway/frontend/lib/modules/current_trip_loading_indicator.dart

149 lines
3.5 KiB
Dart

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<String> 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<CurrentTripLoadingIndicator> createState() => _CurrentTripLoadingIndicatorState();
}
class _CurrentTripLoadingIndicatorState extends State<CurrentTripLoadingIndicator> {
@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<StatusText> {
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<String> 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<AnimatedDotsText> {
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 Text(
'${widget.baseText}$dots',
style: widget.style,
);
}
}