better errorhandling, slimmed down optimizer
This commit is contained in:
@@ -1,4 +1,4 @@
|
||||
const String APP_NAME = 'AnyWay';
|
||||
|
||||
const String API_URL_BASE = 'https://anyway.kluster.moll.re';
|
||||
String API_URL_BASE = 'https://anyway.kluster.moll.re';
|
||||
|
||||
|
@@ -1,3 +1,5 @@
|
||||
import 'dart:developer';
|
||||
|
||||
import 'package:anyway/structs/trip.dart';
|
||||
import 'package:auto_size_text/auto_size_text.dart';
|
||||
|
||||
@@ -15,12 +17,15 @@ class Greeter extends StatefulWidget {
|
||||
}
|
||||
|
||||
|
||||
|
||||
class _GreeterState extends State<Greeter> {
|
||||
|
||||
Widget greeterBuilder (BuildContext context, Widget? child) {
|
||||
ThemeData theme = Theme.of(context);
|
||||
TextStyle greeterStyle = TextStyle(color: theme.primaryColor, fontWeight: FontWeight.bold, fontSize: 24);
|
||||
|
||||
Widget topGreeter;
|
||||
if (widget.trip.landmarks.length > 1) {
|
||||
|
||||
if (widget.trip.uuid != 'pending') {
|
||||
topGreeter = FutureBuilder(
|
||||
future: widget.trip.cityName,
|
||||
builder: (BuildContext context, AsyncSnapshot<String> snapshot) {
|
||||
@@ -28,17 +33,20 @@ class _GreeterState extends State<Greeter> {
|
||||
return AutoSizeText(
|
||||
maxLines: 1,
|
||||
'Welcome to ${snapshot.data}!',
|
||||
style: TextStyle(color: theme.primaryColor, fontWeight: FontWeight.bold, fontSize: 24),
|
||||
style: greeterStyle
|
||||
);
|
||||
} else if (snapshot.hasError) {
|
||||
return const AutoSizeText(
|
||||
log('Error while fetching city name');
|
||||
return AutoSizeText(
|
||||
maxLines: 1,
|
||||
'Welcome to your trip!'
|
||||
'Welcome to your trip!',
|
||||
style: greeterStyle
|
||||
);
|
||||
} else {
|
||||
return const AutoSizeText(
|
||||
return AutoSizeText(
|
||||
maxLines: 1,
|
||||
'Welcome to ...'
|
||||
'Welcome to ...',
|
||||
style: greeterStyle
|
||||
);
|
||||
}
|
||||
}
|
||||
@@ -54,14 +62,24 @@ class _GreeterState extends State<Greeter> {
|
||||
future: widget.trip.cityName,
|
||||
builder: (BuildContext context, AsyncSnapshot<String> snapshot) {
|
||||
if (snapshot.hasData) {
|
||||
return Text(
|
||||
return AutoSizeText(
|
||||
maxLines: 1,
|
||||
'Generating your trip to ${snapshot.data}...',
|
||||
style: TextStyle(color: theme.primaryColor, fontWeight: FontWeight.bold, fontSize: 24),
|
||||
style: greeterStyle
|
||||
);
|
||||
} else if (snapshot.hasError) {
|
||||
return const Text('Error while fetching city name');
|
||||
// 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 const Text('Generating your trip...');
|
||||
return AutoSizeText(
|
||||
maxLines: 1,
|
||||
'Generating your trip...',
|
||||
style: greeterStyle
|
||||
);
|
||||
}
|
||||
),
|
||||
Padding(
|
||||
|
@@ -1,4 +1,3 @@
|
||||
import 'dart:collection';
|
||||
import 'dart:developer';
|
||||
import 'package:flutter/material.dart';
|
||||
import 'package:shared_preferences/shared_preferences.dart';
|
||||
@@ -19,32 +18,19 @@ class LandmarksOverview extends StatefulWidget {
|
||||
}
|
||||
|
||||
class _LandmarksOverviewState extends State<LandmarksOverview> {
|
||||
// final Future<List<Landmark>> _landmarks = fetchLandmarks();
|
||||
|
||||
@override
|
||||
Widget build(BuildContext context) {
|
||||
return ListenableBuilder(//<LinkedList<Landmark>>
|
||||
return ListenableBuilder(
|
||||
listenable: widget.trip!,
|
||||
builder: (BuildContext context, Widget? child) {
|
||||
Trip trip = widget.trip!;
|
||||
log("Trip ${trip.uuid} ${trip.landmarks.length} landmarks");
|
||||
|
||||
List<Widget> children;
|
||||
if (trip.uuid == 'pending') {
|
||||
// the trip is still being fetched from the api
|
||||
children = [Center(child: CircularProgressIndicator())];
|
||||
} else if (trip.uuid == 'error') {
|
||||
children = [
|
||||
const Icon(
|
||||
Icons.error_outline,
|
||||
color: Colors.red,
|
||||
size: 60,
|
||||
),
|
||||
Padding(
|
||||
padding: const EdgeInsets.only(top: 16),
|
||||
child: Text('Error: ${trip.cityName}'),
|
||||
),
|
||||
];
|
||||
} else {
|
||||
|
||||
if (trip.uuid != 'pending' && trip.uuid != 'error') {
|
||||
log("Trip ${trip.uuid} ${trip.landmarks.length} landmarks");
|
||||
if (trip.landmarks.length <= 1) {
|
||||
children = [
|
||||
const Text("No landmarks in this trip"),
|
||||
@@ -55,7 +41,26 @@ class _LandmarksOverviewState extends State<LandmarksOverview> {
|
||||
saveButton(),
|
||||
];
|
||||
}
|
||||
} else if(trip.uuid == 'pending') {
|
||||
// the trip is still being fetched from the api
|
||||
children = [Center(child: CircularProgressIndicator())];
|
||||
} else {
|
||||
// trip.uuid == 'error'
|
||||
// show the error raised by the api
|
||||
// String error =
|
||||
children = [
|
||||
const Icon(
|
||||
Icons.error_outline,
|
||||
color: Colors.red,
|
||||
size: 60,
|
||||
),
|
||||
Padding(
|
||||
padding: const EdgeInsets.only(top: 16),
|
||||
child: Text('Error: ${trip.errorDescription}'),
|
||||
),
|
||||
];
|
||||
}
|
||||
|
||||
return Column(
|
||||
children: children,
|
||||
);
|
||||
@@ -119,11 +124,6 @@ class _LandmarksOverviewState extends State<LandmarksOverview> {
|
||||
|
||||
|
||||
Widget stepBetweenLandmarks(Landmark current, Landmark next) {
|
||||
// This is a simple widget that draws a line between landmark-cards
|
||||
// It's a vertical dotted line
|
||||
// Next to the line is the icon for the mode of transport (walking for now) and the estimated time
|
||||
// There is also a button to open the navigation instructions as a new intent
|
||||
// next landmark is not actually required, but it ensures that the widget is deleted when the next landmark is removed (which makes sense, because then there will be another step)
|
||||
int timeRounded = 5 * (current.tripTime?.inMinutes ?? 0) ~/ 5;
|
||||
// ~/ is integer division (rounding)
|
||||
return Container(
|
||||
|
@@ -1,3 +1,4 @@
|
||||
import 'package:anyway/constants.dart';
|
||||
import 'package:anyway/structs/preferences.dart';
|
||||
import 'package:flutter/material.dart';
|
||||
|
||||
@@ -24,6 +25,32 @@ class _ProfilePageState extends State<ProfilePage> {
|
||||
onChanged: (bool? newValue) {
|
||||
setState(() {
|
||||
debugMode = newValue!;
|
||||
showDialog(
|
||||
context: context,
|
||||
builder: (BuildContext context) {
|
||||
return AlertDialog(
|
||||
title: Text('Debug mode - custom API'),
|
||||
content: TextField(
|
||||
decoration: InputDecoration(
|
||||
hintText: 'http://localhost:8000'
|
||||
),
|
||||
onChanged: (value) {
|
||||
setState(() {
|
||||
API_URL_BASE = value;
|
||||
});
|
||||
},
|
||||
),
|
||||
actions: [
|
||||
TextButton(
|
||||
child: Text('OK'),
|
||||
onPressed: () {
|
||||
Navigator.of(context).pop();
|
||||
},
|
||||
),
|
||||
],
|
||||
);
|
||||
}
|
||||
);
|
||||
});
|
||||
}
|
||||
)
|
||||
|
@@ -14,6 +14,7 @@ class Trip with ChangeNotifier {
|
||||
int totalTime;
|
||||
LinkedList<Landmark> landmarks;
|
||||
// could be empty as well
|
||||
String? errorDescription;
|
||||
|
||||
Future<String> get cityName async {
|
||||
List<double>? location = landmarks.firstOrNull?.location;
|
||||
@@ -64,6 +65,11 @@ class Trip with ChangeNotifier {
|
||||
landmarks.remove(landmark);
|
||||
notifyListeners();
|
||||
}
|
||||
|
||||
void updateError(String error) {
|
||||
errorDescription = error;
|
||||
notifyListeners();
|
||||
}
|
||||
|
||||
factory Trip.fromPrefs(SharedPreferences prefs, String uuid) {
|
||||
String? content = prefs.getString('trip_$uuid');
|
||||
|
@@ -11,9 +11,11 @@ import "package:anyway/structs/preferences.dart";
|
||||
Dio dio = Dio(
|
||||
BaseOptions(
|
||||
baseUrl: API_URL_BASE,
|
||||
// baseUrl: 'http://localhost:8000',
|
||||
connectTimeout: const Duration(seconds: 5),
|
||||
receiveTimeout: const Duration(seconds: 120),
|
||||
// also accept 500 errors, since we cannot rule out that the server is at fault. We still want to gracefully handle these errors
|
||||
validateStatus: (status) => status! <= 500,
|
||||
receiveDataWhenStatusError: true,
|
||||
// api is notoriously slow
|
||||
// headers: {
|
||||
// HttpHeaders.userAgentHeader: 'dio',
|
||||
@@ -45,24 +47,20 @@ fetchTrip(
|
||||
// handle errors
|
||||
if (response.statusCode != 200) {
|
||||
trip.updateUUID("error");
|
||||
throw Exception('Failed to load trip');
|
||||
}
|
||||
if (response.data["error"] != null) {
|
||||
trip.updateUUID("error");
|
||||
throw Exception(response.data["error"]);
|
||||
if (response.data["detail"] != null) {
|
||||
trip.updateError(response.data["detail"]);
|
||||
// throw Exception(response.data["detail"]);
|
||||
}
|
||||
}
|
||||
|
||||
log(response.data.toString());
|
||||
Map<String, dynamic> json = response.data;
|
||||
|
||||
// only fill in the trip "meta" data for now
|
||||
trip.loadFromJson(json);
|
||||
|
||||
|
||||
// now fill the trip with landmarks
|
||||
// if (trip.landmarks.isNotEmpty) {
|
||||
// trip.landmarks.clear();
|
||||
// }
|
||||
// we are going to recreate all the landmarks from the information given by the api
|
||||
// we are going to recreate ALL the landmarks from the information given by the api
|
||||
trip.landmarks.remove(trip.landmarks.first);
|
||||
String? nextUUID = json["first_landmark_uuid"];
|
||||
while (nextUUID != null) {
|
||||
@@ -83,8 +81,8 @@ Future<(Landmark, String?)> fetchLandmark(String uuid) async {
|
||||
if (response.statusCode != 200) {
|
||||
throw Exception('Failed to load landmark');
|
||||
}
|
||||
if (response.data["error"] != null) {
|
||||
throw Exception(response.data["error"]);
|
||||
if (response.data["detail"] != null) {
|
||||
throw Exception(response.data["detail"]);
|
||||
}
|
||||
log(response.data.toString());
|
||||
Map<String, dynamic> json = response.data;
|
||||
|
Reference in New Issue
Block a user