better errorhandling, slimmed down optimizer
This commit is contained in:
parent
71d9554d97
commit
89511f39cb
@ -29,9 +29,11 @@ def new_trip(preferences: Preferences, start: tuple[float, float], end: tuple[fl
|
|||||||
:return: the uuid of the first landmark in the optimized route
|
:return: the uuid of the first landmark in the optimized route
|
||||||
'''
|
'''
|
||||||
if preferences is None:
|
if preferences is None:
|
||||||
raise ValueError("Please provide preferences in the form of a 'Preference' BaseModel class.")
|
raise HTTPException(status_code=406, detail="Preferences not provided")
|
||||||
|
if preferences.shopping.score == 0 and preferences.sightseeing.score == 0 and preferences.nature.score == 0:
|
||||||
|
raise HTTPException(status_code=406, detail="All preferences are 0.")
|
||||||
if start is None:
|
if start is None:
|
||||||
raise ValueError("Please provide the starting coordinates as a tuple of floats.")
|
raise HTTPException(status_code=406, detail="Start coordinates not provided")
|
||||||
if end is None:
|
if end is None:
|
||||||
end = start
|
end = start
|
||||||
logger.info("No end coordinates provided. Using start=end.")
|
logger.info("No end coordinates provided. Using start=end.")
|
||||||
@ -50,7 +52,12 @@ def new_trip(preferences: Preferences, start: tuple[float, float], end: tuple[fl
|
|||||||
landmarks_short.append(end_landmark)
|
landmarks_short.append(end_landmark)
|
||||||
|
|
||||||
# First stage optimization
|
# First stage optimization
|
||||||
base_tour = optimizer.solve_optimization(preferences.max_time_minute, landmarks_short)
|
try:
|
||||||
|
base_tour = optimizer.solve_optimization(preferences.max_time_minute, landmarks_short)
|
||||||
|
except ArithmeticError:
|
||||||
|
raise HTTPException(status_code=500, detail="No solution found")
|
||||||
|
except TimeoutError:
|
||||||
|
raise HTTPException(status_code=500, detail="Optimzation took too long")
|
||||||
|
|
||||||
# Second stage optimization
|
# Second stage optimization
|
||||||
refined_tour = refiner.refine_optimization(landmarks, base_tour, preferences.max_time_minute, preferences.detour_tolerance_minute)
|
refined_tour = refiner.refine_optimization(landmarks, base_tour, preferences.max_time_minute, preferences.detour_tolerance_minute)
|
||||||
|
@ -1,6 +1,6 @@
|
|||||||
city_bbox_side: 5000 #m
|
city_bbox_side: 5000 #m
|
||||||
radius_close_to: 50
|
radius_close_to: 50
|
||||||
church_coeff: 0.8
|
church_coeff: 0.8
|
||||||
park_coeff: 1.2
|
park_coeff: 1.0
|
||||||
tag_coeff: 10
|
tag_coeff: 10
|
||||||
N_important: 40
|
N_important: 40
|
||||||
|
@ -21,7 +21,6 @@ class LandmarkManager:
|
|||||||
|
|
||||||
logger = logging.getLogger(__name__)
|
logger = logging.getLogger(__name__)
|
||||||
|
|
||||||
city_bbox_side: int # bbox side in meters
|
|
||||||
radius_close_to: int # radius in meters
|
radius_close_to: int # radius in meters
|
||||||
church_coeff: float # coeff to adjsut score of churches
|
church_coeff: float # coeff to adjsut score of churches
|
||||||
park_coeff: float # coeff to adjust score of parks
|
park_coeff: float # coeff to adjust score of parks
|
||||||
@ -36,12 +35,17 @@ class LandmarkManager:
|
|||||||
|
|
||||||
with constants.LANDMARK_PARAMETERS_PATH.open('r') as f:
|
with constants.LANDMARK_PARAMETERS_PATH.open('r') as f:
|
||||||
parameters = yaml.safe_load(f)
|
parameters = yaml.safe_load(f)
|
||||||
self.city_bbox_side = parameters['city_bbox_side']
|
self.max_bbox_side = parameters['city_bbox_side']
|
||||||
self.radius_close_to = parameters['radius_close_to']
|
self.radius_close_to = parameters['radius_close_to']
|
||||||
self.church_coeff = parameters['church_coeff']
|
self.church_coeff = parameters['church_coeff']
|
||||||
self.park_coeff = parameters['park_coeff']
|
self.park_coeff = parameters['park_coeff']
|
||||||
self.tag_coeff = parameters['tag_coeff']
|
self.tag_coeff = parameters['tag_coeff']
|
||||||
self.N_important = parameters['N_important']
|
self.N_important = parameters['N_important']
|
||||||
|
|
||||||
|
with constants.OPTIMIZER_PARAMETERS_PATH.open('r') as f:
|
||||||
|
parameters = yaml.safe_load(f)
|
||||||
|
self.walking_speed = parameters['average_walking_speed']
|
||||||
|
self.detour_factor = parameters['detour_factor']
|
||||||
|
|
||||||
self.overpass = Overpass()
|
self.overpass = Overpass()
|
||||||
CachingStrategy.use(JSON, cacheDir=constants.OSM_CACHE_DIR)
|
CachingStrategy.use(JSON, cacheDir=constants.OSM_CACHE_DIR)
|
||||||
@ -65,23 +69,26 @@ class LandmarkManager:
|
|||||||
- A list of the most important landmarks based on the user's preferences.
|
- A list of the most important landmarks based on the user's preferences.
|
||||||
"""
|
"""
|
||||||
|
|
||||||
|
max_walk_dist = (preferences.max_time_minute/2)/60*self.walking_speed*1000/self.detour_factor
|
||||||
|
reachable_bbox_side = min(max_walk_dist, self.max_bbox_side)
|
||||||
|
|
||||||
L = []
|
L = []
|
||||||
bbox = self.create_bbox(center_coordinates)
|
bbox = self.create_bbox(center_coordinates, reachable_bbox_side)
|
||||||
# list for sightseeing
|
# list for sightseeing
|
||||||
if preferences.sightseeing.score != 0:
|
if preferences.sightseeing.score != 0:
|
||||||
score_function = lambda loc, n_tags: int((self.count_elements_close_to(loc) + ((n_tags**1.2)*self.tag_coeff) )*self.church_coeff)
|
score_function = lambda loc, n_tags: int((((n_tags**1.2)*self.tag_coeff) )*self.church_coeff) # self.count_elements_close_to(loc) +
|
||||||
L1 = self.fetch_landmarks(bbox, self.amenity_selectors['sightseeing'], preferences.sightseeing.type, score_function)
|
L1 = self.fetch_landmarks(bbox, self.amenity_selectors['sightseeing'], preferences.sightseeing.type, score_function)
|
||||||
L += L1
|
L += L1
|
||||||
|
|
||||||
# list for nature
|
# list for nature
|
||||||
if preferences.nature.score != 0:
|
if preferences.nature.score != 0:
|
||||||
score_function = lambda loc, n_tags: int((self.count_elements_close_to(loc) + ((n_tags**1.2)*self.tag_coeff) )*self.park_coeff)
|
score_function = lambda loc, n_tags: int((((n_tags**1.2)*self.tag_coeff) )*self.park_coeff) # self.count_elements_close_to(loc) +
|
||||||
L2 = self.fetch_landmarks(bbox, self.amenity_selectors['nature'], preferences.nature.type, score_function)
|
L2 = self.fetch_landmarks(bbox, self.amenity_selectors['nature'], preferences.nature.type, score_function)
|
||||||
L += L2
|
L += L2
|
||||||
|
|
||||||
# list for shopping
|
# list for shopping
|
||||||
if preferences.shopping.score != 0:
|
if preferences.shopping.score != 0:
|
||||||
score_function = lambda loc, n_tags: int(self.count_elements_close_to(loc) + ((n_tags**1.2)*self.tag_coeff))
|
score_function = lambda loc, n_tags: int(((n_tags**1.2)*self.tag_coeff)) # self.count_elements_close_to(loc) +
|
||||||
L3 = self.fetch_landmarks(bbox, self.amenity_selectors['shopping'], preferences.shopping.type, score_function)
|
L3 = self.fetch_landmarks(bbox, self.amenity_selectors['shopping'], preferences.shopping.type, score_function)
|
||||||
L += L3
|
L += L3
|
||||||
|
|
||||||
@ -183,12 +190,13 @@ class LandmarkManager:
|
|||||||
return 0
|
return 0
|
||||||
|
|
||||||
|
|
||||||
def create_bbox(self, coordinates: tuple[float, float]) -> tuple[float, float, float, float]:
|
def create_bbox(self, coordinates: tuple[float, float], reachable_bbox_side: int) -> tuple[float, float, float, float]:
|
||||||
"""
|
"""
|
||||||
Create a bounding box around the given coordinates.
|
Create a bounding box around the given coordinates.
|
||||||
|
|
||||||
Args:
|
Args:
|
||||||
coordinates (tuple[float, float]): The latitude and longitude of the center of the bounding box.
|
coordinates (tuple[float, float]): The latitude and longitude of the center of the bounding box.
|
||||||
|
reachable_bbox_side (int): The side length of the bounding box in meters.
|
||||||
|
|
||||||
Returns:
|
Returns:
|
||||||
tuple[float, float, float, float]: The minimum latitude, minimum longitude, maximum latitude, and maximum longitude
|
tuple[float, float, float, float]: The minimum latitude, minimum longitude, maximum latitude, and maximum longitude
|
||||||
@ -199,7 +207,7 @@ class LandmarkManager:
|
|||||||
lon = coordinates[1]
|
lon = coordinates[1]
|
||||||
|
|
||||||
# Half the side length in km (since it's a square bbox)
|
# Half the side length in km (since it's a square bbox)
|
||||||
half_side_length_km = self.city_bbox_side / 2 / 1000
|
half_side_length_km = reachable_bbox_side / 2 / 1000
|
||||||
|
|
||||||
# Convert distance to degrees
|
# Convert distance to degrees
|
||||||
lat_diff = half_side_length_km / 111 # 1 degree latitude is approximately 111 km
|
lat_diff = half_side_length_km / 111 # 1 degree latitude is approximately 111 km
|
||||||
@ -288,19 +296,24 @@ class LandmarkManager:
|
|||||||
break
|
break
|
||||||
|
|
||||||
if "wikipedia" in tag:
|
if "wikipedia" in tag:
|
||||||
n_tags += 3 # wikipedia entries count more
|
n_tags += 1 # wikipedia entries count more
|
||||||
|
|
||||||
if tag == "wikidata":
|
# if tag == "wikidata":
|
||||||
Q = elem.tag('wikidata')
|
# Q = elem.tag('wikidata')
|
||||||
site = Site("wikidata", "wikidata")
|
# site = Site("wikidata", "wikidata")
|
||||||
item = ItemPage(site, Q)
|
# item = ItemPage(site, Q)
|
||||||
item.get()
|
# item.get()
|
||||||
n_languages = len(item.labels)
|
# n_languages = len(item.labels)
|
||||||
n_tags += n_languages/10
|
# n_tags += n_languages/10
|
||||||
|
if "viewpoint" in tag:
|
||||||
|
n_tags += 10
|
||||||
|
|
||||||
if elem_type != "nature":
|
if elem_type != "nature":
|
||||||
if "leisure" in tag and elem.tag('leisure') == "park":
|
if "leisure" in tag and elem.tag('leisure') == "park":
|
||||||
elem_type = "nature"
|
elem_type = "nature"
|
||||||
|
|
||||||
|
if elem_type == "nature":
|
||||||
|
n_tags += 1
|
||||||
|
|
||||||
if landmarktype != "shopping":
|
if landmarktype != "shopping":
|
||||||
if "shop" in tag:
|
if "shop" in tag:
|
||||||
@ -310,7 +323,6 @@ class LandmarkManager:
|
|||||||
if tag == "building" and elem.tag('building') in ['retail', 'supermarket', 'parking']:
|
if tag == "building" and elem.tag('building') in ['retail', 'supermarket', 'parking']:
|
||||||
skip = True
|
skip = True
|
||||||
break
|
break
|
||||||
|
|
||||||
if skip:
|
if skip:
|
||||||
continue
|
continue
|
||||||
|
|
||||||
|
@ -1,4 +1,4 @@
|
|||||||
const String APP_NAME = 'AnyWay';
|
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:anyway/structs/trip.dart';
|
||||||
import 'package:auto_size_text/auto_size_text.dart';
|
import 'package:auto_size_text/auto_size_text.dart';
|
||||||
|
|
||||||
@ -15,12 +17,15 @@ class Greeter extends StatefulWidget {
|
|||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
class _GreeterState extends State<Greeter> {
|
class _GreeterState extends State<Greeter> {
|
||||||
|
|
||||||
Widget greeterBuilder (BuildContext context, Widget? child) {
|
Widget greeterBuilder (BuildContext context, Widget? child) {
|
||||||
ThemeData theme = Theme.of(context);
|
ThemeData theme = Theme.of(context);
|
||||||
|
TextStyle greeterStyle = TextStyle(color: theme.primaryColor, fontWeight: FontWeight.bold, fontSize: 24);
|
||||||
|
|
||||||
Widget topGreeter;
|
Widget topGreeter;
|
||||||
if (widget.trip.landmarks.length > 1) {
|
|
||||||
|
if (widget.trip.uuid != 'pending') {
|
||||||
topGreeter = FutureBuilder(
|
topGreeter = FutureBuilder(
|
||||||
future: widget.trip.cityName,
|
future: widget.trip.cityName,
|
||||||
builder: (BuildContext context, AsyncSnapshot<String> snapshot) {
|
builder: (BuildContext context, AsyncSnapshot<String> snapshot) {
|
||||||
@ -28,17 +33,20 @@ class _GreeterState extends State<Greeter> {
|
|||||||
return AutoSizeText(
|
return AutoSizeText(
|
||||||
maxLines: 1,
|
maxLines: 1,
|
||||||
'Welcome to ${snapshot.data}!',
|
'Welcome to ${snapshot.data}!',
|
||||||
style: TextStyle(color: theme.primaryColor, fontWeight: FontWeight.bold, fontSize: 24),
|
style: greeterStyle
|
||||||
);
|
);
|
||||||
} else if (snapshot.hasError) {
|
} else if (snapshot.hasError) {
|
||||||
return const AutoSizeText(
|
log('Error while fetching city name');
|
||||||
|
return AutoSizeText(
|
||||||
maxLines: 1,
|
maxLines: 1,
|
||||||
'Welcome to your trip!'
|
'Welcome to your trip!',
|
||||||
|
style: greeterStyle
|
||||||
);
|
);
|
||||||
} else {
|
} else {
|
||||||
return const AutoSizeText(
|
return AutoSizeText(
|
||||||
maxLines: 1,
|
maxLines: 1,
|
||||||
'Welcome to ...'
|
'Welcome to ...',
|
||||||
|
style: greeterStyle
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -54,14 +62,24 @@ class _GreeterState extends State<Greeter> {
|
|||||||
future: widget.trip.cityName,
|
future: widget.trip.cityName,
|
||||||
builder: (BuildContext context, AsyncSnapshot<String> snapshot) {
|
builder: (BuildContext context, AsyncSnapshot<String> snapshot) {
|
||||||
if (snapshot.hasData) {
|
if (snapshot.hasData) {
|
||||||
return Text(
|
return AutoSizeText(
|
||||||
|
maxLines: 1,
|
||||||
'Generating your trip to ${snapshot.data}...',
|
'Generating your trip to ${snapshot.data}...',
|
||||||
style: TextStyle(color: theme.primaryColor, fontWeight: FontWeight.bold, fontSize: 24),
|
style: greeterStyle
|
||||||
);
|
);
|
||||||
} else if (snapshot.hasError) {
|
} 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(
|
Padding(
|
||||||
|
@ -1,4 +1,3 @@
|
|||||||
import 'dart:collection';
|
|
||||||
import 'dart:developer';
|
import 'dart:developer';
|
||||||
import 'package:flutter/material.dart';
|
import 'package:flutter/material.dart';
|
||||||
import 'package:shared_preferences/shared_preferences.dart';
|
import 'package:shared_preferences/shared_preferences.dart';
|
||||||
@ -19,32 +18,19 @@ class LandmarksOverview extends StatefulWidget {
|
|||||||
}
|
}
|
||||||
|
|
||||||
class _LandmarksOverviewState extends State<LandmarksOverview> {
|
class _LandmarksOverviewState extends State<LandmarksOverview> {
|
||||||
// final Future<List<Landmark>> _landmarks = fetchLandmarks();
|
|
||||||
|
|
||||||
@override
|
@override
|
||||||
Widget build(BuildContext context) {
|
Widget build(BuildContext context) {
|
||||||
return ListenableBuilder(//<LinkedList<Landmark>>
|
return ListenableBuilder(
|
||||||
listenable: widget.trip!,
|
listenable: widget.trip!,
|
||||||
builder: (BuildContext context, Widget? child) {
|
builder: (BuildContext context, Widget? child) {
|
||||||
Trip trip = widget.trip!;
|
Trip trip = widget.trip!;
|
||||||
log("Trip ${trip.uuid} ${trip.landmarks.length} landmarks");
|
log("Trip ${trip.uuid} ${trip.landmarks.length} landmarks");
|
||||||
|
|
||||||
List<Widget> children;
|
List<Widget> children;
|
||||||
if (trip.uuid == 'pending') {
|
|
||||||
// the trip is still being fetched from the api
|
if (trip.uuid != 'pending' && trip.uuid != 'error') {
|
||||||
children = [Center(child: CircularProgressIndicator())];
|
log("Trip ${trip.uuid} ${trip.landmarks.length} landmarks");
|
||||||
} 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.landmarks.length <= 1) {
|
if (trip.landmarks.length <= 1) {
|
||||||
children = [
|
children = [
|
||||||
const Text("No landmarks in this trip"),
|
const Text("No landmarks in this trip"),
|
||||||
@ -55,7 +41,26 @@ class _LandmarksOverviewState extends State<LandmarksOverview> {
|
|||||||
saveButton(),
|
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(
|
return Column(
|
||||||
children: children,
|
children: children,
|
||||||
);
|
);
|
||||||
@ -119,11 +124,6 @@ class _LandmarksOverviewState extends State<LandmarksOverview> {
|
|||||||
|
|
||||||
|
|
||||||
Widget stepBetweenLandmarks(Landmark current, Landmark next) {
|
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;
|
int timeRounded = 5 * (current.tripTime?.inMinutes ?? 0) ~/ 5;
|
||||||
// ~/ is integer division (rounding)
|
// ~/ is integer division (rounding)
|
||||||
return Container(
|
return Container(
|
||||||
|
@ -1,3 +1,4 @@
|
|||||||
|
import 'package:anyway/constants.dart';
|
||||||
import 'package:anyway/structs/preferences.dart';
|
import 'package:anyway/structs/preferences.dart';
|
||||||
import 'package:flutter/material.dart';
|
import 'package:flutter/material.dart';
|
||||||
|
|
||||||
@ -24,6 +25,32 @@ class _ProfilePageState extends State<ProfilePage> {
|
|||||||
onChanged: (bool? newValue) {
|
onChanged: (bool? newValue) {
|
||||||
setState(() {
|
setState(() {
|
||||||
debugMode = newValue!;
|
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;
|
int totalTime;
|
||||||
LinkedList<Landmark> landmarks;
|
LinkedList<Landmark> landmarks;
|
||||||
// could be empty as well
|
// could be empty as well
|
||||||
|
String? errorDescription;
|
||||||
|
|
||||||
Future<String> get cityName async {
|
Future<String> get cityName async {
|
||||||
List<double>? location = landmarks.firstOrNull?.location;
|
List<double>? location = landmarks.firstOrNull?.location;
|
||||||
@ -64,6 +65,11 @@ class Trip with ChangeNotifier {
|
|||||||
landmarks.remove(landmark);
|
landmarks.remove(landmark);
|
||||||
notifyListeners();
|
notifyListeners();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void updateError(String error) {
|
||||||
|
errorDescription = error;
|
||||||
|
notifyListeners();
|
||||||
|
}
|
||||||
|
|
||||||
factory Trip.fromPrefs(SharedPreferences prefs, String uuid) {
|
factory Trip.fromPrefs(SharedPreferences prefs, String uuid) {
|
||||||
String? content = prefs.getString('trip_$uuid');
|
String? content = prefs.getString('trip_$uuid');
|
||||||
|
@ -11,9 +11,11 @@ import "package:anyway/structs/preferences.dart";
|
|||||||
Dio dio = Dio(
|
Dio dio = Dio(
|
||||||
BaseOptions(
|
BaseOptions(
|
||||||
baseUrl: API_URL_BASE,
|
baseUrl: API_URL_BASE,
|
||||||
// baseUrl: 'http://localhost:8000',
|
|
||||||
connectTimeout: const Duration(seconds: 5),
|
connectTimeout: const Duration(seconds: 5),
|
||||||
receiveTimeout: const Duration(seconds: 120),
|
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
|
// api is notoriously slow
|
||||||
// headers: {
|
// headers: {
|
||||||
// HttpHeaders.userAgentHeader: 'dio',
|
// HttpHeaders.userAgentHeader: 'dio',
|
||||||
@ -45,24 +47,20 @@ fetchTrip(
|
|||||||
// handle errors
|
// handle errors
|
||||||
if (response.statusCode != 200) {
|
if (response.statusCode != 200) {
|
||||||
trip.updateUUID("error");
|
trip.updateUUID("error");
|
||||||
throw Exception('Failed to load trip');
|
if (response.data["detail"] != null) {
|
||||||
}
|
trip.updateError(response.data["detail"]);
|
||||||
if (response.data["error"] != null) {
|
// throw Exception(response.data["detail"]);
|
||||||
trip.updateUUID("error");
|
}
|
||||||
throw Exception(response.data["error"]);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
log(response.data.toString());
|
log(response.data.toString());
|
||||||
Map<String, dynamic> json = response.data;
|
Map<String, dynamic> json = response.data;
|
||||||
|
|
||||||
// only fill in the trip "meta" data for now
|
// only fill in the trip "meta" data for now
|
||||||
trip.loadFromJson(json);
|
trip.loadFromJson(json);
|
||||||
|
|
||||||
|
|
||||||
// now fill the trip with landmarks
|
// now fill the trip with landmarks
|
||||||
// if (trip.landmarks.isNotEmpty) {
|
// we are going to recreate ALL the landmarks from the information given by the api
|
||||||
// trip.landmarks.clear();
|
|
||||||
// }
|
|
||||||
// we are going to recreate all the landmarks from the information given by the api
|
|
||||||
trip.landmarks.remove(trip.landmarks.first);
|
trip.landmarks.remove(trip.landmarks.first);
|
||||||
String? nextUUID = json["first_landmark_uuid"];
|
String? nextUUID = json["first_landmark_uuid"];
|
||||||
while (nextUUID != null) {
|
while (nextUUID != null) {
|
||||||
@ -83,8 +81,8 @@ Future<(Landmark, String?)> fetchLandmark(String uuid) async {
|
|||||||
if (response.statusCode != 200) {
|
if (response.statusCode != 200) {
|
||||||
throw Exception('Failed to load landmark');
|
throw Exception('Failed to load landmark');
|
||||||
}
|
}
|
||||||
if (response.data["error"] != null) {
|
if (response.data["detail"] != null) {
|
||||||
throw Exception(response.data["error"]);
|
throw Exception(response.data["detail"]);
|
||||||
}
|
}
|
||||||
log(response.data.toString());
|
log(response.data.toString());
|
||||||
Map<String, dynamic> json = response.data;
|
Map<String, dynamic> json = response.data;
|
||||||
|
Loading…
x
Reference in New Issue
Block a user