make ui at least usable throughout
Some checks failed
Build and release APK / Build APK (pull_request) Has been cancelled
Some checks failed
Build and release APK / Build APK (pull_request) Has been cancelled
This commit is contained in:
parent
39df97f4d1
commit
55b0a1b793
37
frontend/lib/modules/current_trip_error_message.dart
Normal file
37
frontend/lib/modules/current_trip_error_message.dart
Normal file
@ -0,0 +1,37 @@
|
|||||||
|
import 'package:anyway/structs/trip.dart';
|
||||||
|
import 'package:auto_size_text/auto_size_text.dart';
|
||||||
|
import 'package:flutter/material.dart';
|
||||||
|
|
||||||
|
class CurrentTripErrorMessage extends StatefulWidget {
|
||||||
|
final Trip trip;
|
||||||
|
const CurrentTripErrorMessage({
|
||||||
|
super.key,
|
||||||
|
required this.trip,
|
||||||
|
});
|
||||||
|
|
||||||
|
@override
|
||||||
|
State<CurrentTripErrorMessage> createState() => _CurrentTripErrorMessageState();
|
||||||
|
}
|
||||||
|
|
||||||
|
class _CurrentTripErrorMessageState extends State<CurrentTripErrorMessage> {
|
||||||
|
@override
|
||||||
|
Widget build(BuildContext context) => Center(
|
||||||
|
child: Row(
|
||||||
|
mainAxisAlignment: MainAxisAlignment.center,
|
||||||
|
children: [
|
||||||
|
const Icon(
|
||||||
|
Icons.error_outline,
|
||||||
|
color: Colors.red,
|
||||||
|
size: 50,
|
||||||
|
),
|
||||||
|
const Padding(
|
||||||
|
padding: EdgeInsets.only(left: 10),
|
||||||
|
),
|
||||||
|
AutoSizeText(
|
||||||
|
'Error: ${widget.trip.errorDescription}',
|
||||||
|
maxLines: 3,
|
||||||
|
),
|
||||||
|
],
|
||||||
|
)
|
||||||
|
);
|
||||||
|
}
|
@ -1,111 +1,50 @@
|
|||||||
import 'dart:developer';
|
import 'package:flutter/material.dart';
|
||||||
|
|
||||||
import 'package:anyway/constants.dart';
|
|
||||||
import 'package:anyway/structs/trip.dart';
|
|
||||||
import 'package:auto_size_text/auto_size_text.dart';
|
import 'package:auto_size_text/auto_size_text.dart';
|
||||||
|
|
||||||
import 'package:flutter/material.dart';
|
import 'package:anyway/pages/current_trip.dart';
|
||||||
|
import 'package:anyway/structs/trip.dart';
|
||||||
|
|
||||||
class Greeter extends StatefulWidget {
|
|
||||||
|
class CurrentTripGreeter extends StatefulWidget {
|
||||||
final Trip trip;
|
final Trip trip;
|
||||||
|
|
||||||
Greeter({
|
CurrentTripGreeter({
|
||||||
|
super.key,
|
||||||
required this.trip,
|
required this.trip,
|
||||||
});
|
});
|
||||||
|
|
||||||
@override
|
@override
|
||||||
State<Greeter> createState() => _GreeterState();
|
State<CurrentTripGreeter> createState() => _CurrentTripGreeterState();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
class _GreeterState extends State<Greeter> {
|
class _CurrentTripGreeterState extends State<CurrentTripGreeter> {
|
||||||
|
|
||||||
Widget greeterBuilder (BuildContext context, Widget? child) {
|
|
||||||
final Shader textGradient = APP_GRADIENT.createShader(Rect.fromLTWH(0.0, 0.0, 200.0, 70.0));
|
|
||||||
TextStyle greeterStyle = TextStyle(
|
|
||||||
foreground: Paint()..shader = textGradient,
|
|
||||||
fontWeight: FontWeight.bold,
|
|
||||||
fontSize: 26
|
|
||||||
);
|
|
||||||
|
|
||||||
Widget topGreeter;
|
|
||||||
|
|
||||||
if (widget.trip.uuid != 'pending') {
|
|
||||||
topGreeter = FutureBuilder(
|
|
||||||
future: widget.trip.cityName,
|
|
||||||
builder: (BuildContext context, AsyncSnapshot<String> snapshot) {
|
|
||||||
if (snapshot.hasData) {
|
|
||||||
return AutoSizeText(
|
|
||||||
maxLines: 1,
|
|
||||||
'Welcome to ${snapshot.data}!',
|
|
||||||
style: greeterStyle
|
|
||||||
);
|
|
||||||
} else if (snapshot.hasError) {
|
|
||||||
log('Error while fetching city name');
|
|
||||||
return AutoSizeText(
|
|
||||||
maxLines: 1,
|
|
||||||
'Welcome to your trip!',
|
|
||||||
style: greeterStyle
|
|
||||||
);
|
|
||||||
} else {
|
|
||||||
return AutoSizeText(
|
|
||||||
maxLines: 1,
|
|
||||||
'Welcome to ...',
|
|
||||||
style: greeterStyle
|
|
||||||
);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
);
|
|
||||||
} else {
|
|
||||||
// still awaiting the trip
|
|
||||||
// We can hopefully infer the city name from the cityName future
|
|
||||||
// Show a linear loader at the bottom and an info message above
|
|
||||||
topGreeter = Column(
|
|
||||||
mainAxisAlignment: MainAxisAlignment.end,
|
|
||||||
children: [
|
|
||||||
FutureBuilder(
|
|
||||||
future: widget.trip.cityName,
|
|
||||||
builder: (BuildContext context, AsyncSnapshot<String> snapshot) {
|
|
||||||
if (snapshot.hasData) {
|
|
||||||
return AutoSizeText(
|
|
||||||
maxLines: 1,
|
|
||||||
'Generating 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
|
|
||||||
return AutoSizeText(
|
|
||||||
maxLines: 1,
|
|
||||||
'Error while loading trip.',
|
|
||||||
style: greeterStyle
|
|
||||||
);
|
|
||||||
}
|
|
||||||
return AutoSizeText(
|
|
||||||
maxLines: 1,
|
|
||||||
'Generating your trip...',
|
|
||||||
style: greeterStyle
|
|
||||||
);
|
|
||||||
}
|
|
||||||
),
|
|
||||||
Padding(
|
|
||||||
padding: EdgeInsets.all(5),
|
|
||||||
child: const LinearProgressIndicator()
|
|
||||||
)
|
|
||||||
]
|
|
||||||
);
|
|
||||||
}
|
|
||||||
|
|
||||||
return Center(
|
|
||||||
child: topGreeter,
|
|
||||||
);
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
@override
|
@override
|
||||||
Widget build(BuildContext context) {
|
Widget build(BuildContext context) => Center(
|
||||||
return ListenableBuilder(
|
child: FutureBuilder(
|
||||||
listenable: widget.trip,
|
future: widget.trip.cityName,
|
||||||
builder: greeterBuilder,
|
builder: (BuildContext context, AsyncSnapshot<String> snapshot) {
|
||||||
);
|
if (snapshot.hasData) {
|
||||||
}
|
return AutoSizeText(
|
||||||
|
maxLines: 1,
|
||||||
|
'Welcome to ${snapshot.data}!',
|
||||||
|
style: greeterStyle
|
||||||
|
);
|
||||||
|
} else if (snapshot.hasError) {
|
||||||
|
return AutoSizeText(
|
||||||
|
maxLines: 1,
|
||||||
|
'Welcome to your trip!',
|
||||||
|
style: greeterStyle
|
||||||
|
);
|
||||||
|
} else {
|
||||||
|
return AutoSizeText(
|
||||||
|
maxLines: 1,
|
||||||
|
'Welcome to ...',
|
||||||
|
style: greeterStyle
|
||||||
|
);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
)
|
||||||
|
);
|
||||||
|
|
||||||
}
|
}
|
60
frontend/lib/modules/current_trip_loading_indicator.dart
Normal file
60
frontend/lib/modules/current_trip_loading_indicator.dart
Normal file
@ -0,0 +1,60 @@
|
|||||||
|
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';
|
||||||
|
|
||||||
|
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) => Center(
|
||||||
|
child: FutureBuilder(
|
||||||
|
future: widget.trip.cityName,
|
||||||
|
builder: (BuildContext context, AsyncSnapshot<String> snapshot) {
|
||||||
|
Widget greeter;
|
||||||
|
Widget loadingIndicator = const Padding(
|
||||||
|
padding: EdgeInsets.only(top: 10),
|
||||||
|
child: CircularProgressIndicator()
|
||||||
|
);
|
||||||
|
|
||||||
|
if (snapshot.hasData) {
|
||||||
|
greeter = AutoSizeText(
|
||||||
|
maxLines: 1,
|
||||||
|
'Generating 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 = AutoSizeText(
|
||||||
|
maxLines: 1,
|
||||||
|
'Error while loading trip.',
|
||||||
|
style: greeterStyle,
|
||||||
|
);
|
||||||
|
} else {
|
||||||
|
greeter = AutoSizeText(
|
||||||
|
maxLines: 1,
|
||||||
|
'Generating your trip...',
|
||||||
|
style: greeterStyle,
|
||||||
|
);
|
||||||
|
}
|
||||||
|
return Column(
|
||||||
|
mainAxisAlignment: MainAxisAlignment.center,
|
||||||
|
children: [
|
||||||
|
greeter,
|
||||||
|
loadingIndicator,
|
||||||
|
],
|
||||||
|
);
|
||||||
|
}
|
||||||
|
)
|
||||||
|
);
|
||||||
|
}
|
@ -1,4 +1,6 @@
|
|||||||
import 'package:anyway/constants.dart';
|
import 'package:anyway/constants.dart';
|
||||||
|
import 'package:anyway/modules/current_trip_error_message.dart';
|
||||||
|
import 'package:anyway/modules/current_trip_loading_indicator.dart';
|
||||||
import 'package:flutter/material.dart';
|
import 'package:flutter/material.dart';
|
||||||
|
|
||||||
import 'package:anyway/structs/trip.dart';
|
import 'package:anyway/structs/trip.dart';
|
||||||
@ -28,16 +30,36 @@ class _CurrentTripPanelState extends State<CurrentTripPanel> {
|
|||||||
return ListenableBuilder(
|
return ListenableBuilder(
|
||||||
listenable: widget.trip,
|
listenable: widget.trip,
|
||||||
builder: (context, child) {
|
builder: (context, child) {
|
||||||
if (widget.trip.uuid != 'pending' && widget.trip.uuid != 'error') {
|
if (widget.trip.uuid == 'error') {
|
||||||
|
return Align(
|
||||||
|
alignment: Alignment.topCenter,
|
||||||
|
child: SizedBox(
|
||||||
|
// reuse the exact same height as the panel has when collapsed
|
||||||
|
// this way the greeter will be centered when the panel is collapsed
|
||||||
|
height: MediaQuery.of(context).size.height * TRIP_PANEL_MIN_HEIGHT - 20,
|
||||||
|
child: CurrentTripErrorMessage(trip: widget.trip)
|
||||||
|
),
|
||||||
|
);
|
||||||
|
} else if (widget.trip.uuid == 'pending') {
|
||||||
|
return Align(
|
||||||
|
alignment: Alignment.topCenter,
|
||||||
|
child: SizedBox(
|
||||||
|
// reuse the exact same height as the panel has when collapsed
|
||||||
|
// this way the greeter will be centered when the panel is collapsed
|
||||||
|
height: MediaQuery.of(context).size.height * TRIP_PANEL_MIN_HEIGHT - 20,
|
||||||
|
child: CurrentTripLoadingIndicator(trip: widget.trip),
|
||||||
|
),
|
||||||
|
);
|
||||||
|
} else {
|
||||||
return ListView(
|
return ListView(
|
||||||
controller: widget.controller,
|
controller: widget.controller,
|
||||||
padding: const EdgeInsets.only(bottom: 30, left: 5, right: 5),
|
padding: const EdgeInsets.only(bottom: 30),
|
||||||
children: [
|
children: [
|
||||||
SizedBox(
|
SizedBox(
|
||||||
// reuse the exact same height as the panel has when collapsed
|
// reuse the exact same height as the panel has when collapsed
|
||||||
// this way the greeter will be centered when the panel is collapsed
|
// this way the greeter will be centered when the panel is collapsed
|
||||||
height: MediaQuery.of(context).size.height * TRIP_PANEL_MIN_HEIGHT - 20,
|
height: MediaQuery.of(context).size.height * TRIP_PANEL_MIN_HEIGHT - 20,
|
||||||
child: Greeter(trip: widget.trip),
|
child: CurrentTripGreeter(trip: widget.trip),
|
||||||
),
|
),
|
||||||
|
|
||||||
const Padding(padding: EdgeInsets.only(top: 10)),
|
const Padding(padding: EdgeInsets.only(top: 10)),
|
||||||
@ -53,28 +75,6 @@ class _CurrentTripPanelState extends State<CurrentTripPanel> {
|
|||||||
Center(child: saveButton(widget.trip)),
|
Center(child: saveButton(widget.trip)),
|
||||||
],
|
],
|
||||||
);
|
);
|
||||||
} else if(widget.trip.uuid == 'pending') {
|
|
||||||
return SizedBox(
|
|
||||||
// reuse the exact same height as the panel has when collapsed
|
|
||||||
// this way the greeter will be centered when the panel is collapsed
|
|
||||||
height: MediaQuery.of(context).size.height * TRIP_PANEL_MIN_HEIGHT - 20,
|
|
||||||
child: Greeter(trip: widget.trip)
|
|
||||||
);
|
|
||||||
} else {
|
|
||||||
return Row(
|
|
||||||
mainAxisAlignment: MainAxisAlignment.center,
|
|
||||||
children: [
|
|
||||||
const Icon(
|
|
||||||
Icons.error_outline,
|
|
||||||
color: Colors.red,
|
|
||||||
size: 50,
|
|
||||||
),
|
|
||||||
Padding(
|
|
||||||
padding: const EdgeInsets.only(left: 10),
|
|
||||||
child: Text('Error: ${widget.trip.errorDescription}'),
|
|
||||||
),
|
|
||||||
],
|
|
||||||
);
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
);
|
);
|
||||||
|
@ -6,6 +6,12 @@ import 'package:anyway/structs/trip.dart';
|
|||||||
import 'package:anyway/modules/current_trip_map.dart';
|
import 'package:anyway/modules/current_trip_map.dart';
|
||||||
import 'package:anyway/modules/current_trip_panel.dart';
|
import 'package:anyway/modules/current_trip_panel.dart';
|
||||||
|
|
||||||
|
final Shader textGradient = APP_GRADIENT.createShader(Rect.fromLTWH(0.0, 0.0, 200.0, 70.0));
|
||||||
|
TextStyle greeterStyle = TextStyle(
|
||||||
|
foreground: Paint()..shader = textGradient,
|
||||||
|
fontWeight: FontWeight.bold,
|
||||||
|
fontSize: 26
|
||||||
|
);
|
||||||
|
|
||||||
|
|
||||||
class TripPage extends StatefulWidget {
|
class TripPage extends StatefulWidget {
|
||||||
@ -35,7 +41,7 @@ class _TripPageState extends State<TripPage> {
|
|||||||
maxHeight: MediaQuery.of(context).size.height * TRIP_PANEL_MAX_HEIGHT,
|
maxHeight: MediaQuery.of(context).size.height * TRIP_PANEL_MAX_HEIGHT,
|
||||||
// padding in this context is annoying: it offsets the notion of vertical alignment.
|
// padding in this context is annoying: it offsets the notion of vertical alignment.
|
||||||
// children that want to be centered vertically need to have their size adjusted by 2x the padding
|
// children that want to be centered vertically need to have their size adjusted by 2x the padding
|
||||||
padding: const EdgeInsets.only(top: 10),
|
padding: const EdgeInsets.all(10.0),
|
||||||
// Panel snapping should not be disabled because it significantly improves the user experience
|
// Panel snapping should not be disabled because it significantly improves the user experience
|
||||||
// panelSnapping: false
|
// panelSnapping: false
|
||||||
borderRadius: const BorderRadius.only(topLeft: Radius.circular(25), topRight: Radius.circular(25)),
|
borderRadius: const BorderRadius.only(topLeft: Radius.circular(25), topRight: Radius.circular(25)),
|
||||||
|
@ -38,10 +38,18 @@ fetchTrip(
|
|||||||
String dataString = jsonEncode(data);
|
String dataString = jsonEncode(data);
|
||||||
log(dataString);
|
log(dataString);
|
||||||
|
|
||||||
final response = await dio.post(
|
late Response response;
|
||||||
"/trip/new",
|
try {
|
||||||
data: data
|
response = await dio.post(
|
||||||
);
|
"/trip/new",
|
||||||
|
data: data
|
||||||
|
);
|
||||||
|
} catch (e) {
|
||||||
|
trip.updateUUID("error");
|
||||||
|
trip.updateError(e.toString());
|
||||||
|
log(e.toString());
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
// handle errors
|
// handle errors
|
||||||
if (response.statusCode != 200) {
|
if (response.statusCode != 200) {
|
||||||
|
Loading…
x
Reference in New Issue
Block a user