bare implementation of comuncation with the api
This commit is contained in:
		| @@ -20,26 +20,40 @@ class Greeter extends StatefulWidget { | ||||
| class _GreeterState extends State<Greeter> { | ||||
|   Widget greeterBuild (BuildContext context, AsyncSnapshot<Trip> snapshot) { | ||||
|     ThemeData theme = Theme.of(context); | ||||
|     String cityName = ""; | ||||
|     Widget topGreeter; | ||||
|     if (snapshot.hasData) { | ||||
|       cityName = snapshot.data?.cityName ?? '...'; | ||||
|       topGreeter = Padding( | ||||
|         padding: const EdgeInsets.only(top: 20, bottom: 20), | ||||
|         child: Text( | ||||
|           'Welcome to ${snapshot.data?.cityName}!', | ||||
|           style: TextStyle(color: theme.primaryColor, fontWeight: FontWeight.bold, fontSize: 24), | ||||
|         ) | ||||
|       ); | ||||
|     } else if (snapshot.hasError) { | ||||
|       cityName = "error"; | ||||
|     } else { // still awaiting the cityname | ||||
|       cityName = "..."; | ||||
|       topGreeter = const Padding( | ||||
|         padding: EdgeInsets.only(top: 20, bottom: 20), | ||||
|         child: Text('Error while fetching trip') | ||||
|       ); | ||||
|     } else { | ||||
|       // still awaiting the cityname | ||||
|       // Show a linear loader at the bottom and an info message above | ||||
|       topGreeter = Column( | ||||
|         mainAxisAlignment: MainAxisAlignment.end, | ||||
|         children: [ | ||||
|           Padding( | ||||
|             padding: const EdgeInsets.only(top: 20, bottom: 20), | ||||
|             child: const Text('Generating your trip...', style: TextStyle(fontSize: 20),) | ||||
|           ), | ||||
|           const LinearProgressIndicator() | ||||
|         ] | ||||
|       ); | ||||
|     } | ||||
|  | ||||
|     Widget topGreeter = Text( | ||||
|       'Welcome to $cityName!', | ||||
|       style: TextStyle(color: theme.primaryColor, fontWeight: FontWeight.bold, fontSize: 24), | ||||
|     ); | ||||
|      | ||||
|  | ||||
|     if (widget.standalone) { | ||||
|       return Center( | ||||
|         child: Padding( | ||||
|           padding: EdgeInsets.only(top: 24.0), | ||||
|         child: topGreeter, | ||||
|         ), | ||||
|       ); | ||||
|     } else { | ||||
|       return Center( | ||||
|   | ||||
| @@ -63,9 +63,8 @@ class _NewTripPageState extends State<NewTripPage> { | ||||
|                         double.parse(latController.text), | ||||
|                         double.parse(lonController.text) | ||||
|                       ]; | ||||
|                       UserPreferences preferences = UserPreferences(); | ||||
|                       preferences.load(); | ||||
|                       Future<Trip> trip = fetchTrip(startPoint, preferences); | ||||
|                       Future<UserPreferences> preferences = loadUserPreferences(); | ||||
|                       Future<Trip>? trip = fetchTrip(startPoint, preferences); | ||||
|                         Navigator.of(context).push( | ||||
|                           MaterialPageRoute( | ||||
|                             builder: (context) => BasePage(mainScreen: "map", trip: trip) | ||||
|   | ||||
| @@ -82,17 +82,15 @@ class UserPreferences { | ||||
|     } | ||||
|   } | ||||
|  | ||||
|   String toJson() { | ||||
|   Map<String, dynamic> toJson() { | ||||
|       // This is "opinionated" JSON, corresponding to the backend's expectations | ||||
|     return ''' | ||||
|     { | ||||
|       "sightseeing": {"type": "sightseeing", "score": ${sightseeing.value}}, | ||||
|       "shopping": {"type": "shopping", "score": ${shopping.value}}, | ||||
|       "nature": {"type": "nature", "score": ${nature.value}}, | ||||
|       "max_time_minutes": ${maxTime.value}, | ||||
|       "detour_tolerance_minute": ${maxDetour.value} | ||||
|     } | ||||
|     '''; | ||||
|       return { | ||||
|         "sightseeing": {"type": "sightseeing", "score": sightseeing.value}, | ||||
|         "shopping": {"type": "shopping", "score": shopping.value}, | ||||
|         "nature": {"type": "nature", "score": nature.value}, | ||||
|         "max_time_minute": maxTime.value, | ||||
|         "detour_tolerance_minute": maxDetour.value | ||||
|       }; | ||||
|     } | ||||
| } | ||||
|  | ||||
|   | ||||
| @@ -11,6 +11,7 @@ class Trip { | ||||
|   final String uuid; | ||||
|   final String cityName; | ||||
|   // TODO: cityName should be inferred from coordinates of the Landmarks | ||||
|   final int totalTime; | ||||
|   final LinkedList<Landmark> landmarks; | ||||
|   // could be empty as well | ||||
|  | ||||
| @@ -19,15 +20,18 @@ class Trip { | ||||
|     required this.uuid, | ||||
|     required this.cityName, | ||||
|     required this.landmarks, | ||||
|     this.totalTime = 0 | ||||
|   }); | ||||
|  | ||||
|  | ||||
|   factory Trip.fromJson(Map<String, dynamic> json) { | ||||
|     return Trip( | ||||
|     Trip trip = Trip( | ||||
|       uuid: json['uuid'], | ||||
|       cityName: json['city_name'], | ||||
|       cityName: json['city_name'] ?? 'Not communicated', | ||||
|       landmarks: LinkedList() | ||||
|     ); | ||||
|  | ||||
|     return trip; | ||||
|   } | ||||
|  | ||||
|  | ||||
| @@ -44,7 +48,7 @@ class Trip { | ||||
|   Map<String, dynamic> toJson() => { | ||||
|     'uuid': uuid, | ||||
|     'city_name': cityName, | ||||
|     'entry_uuid': landmarks.first?.uuid ?? '' | ||||
|     'first_landmark_uuid': landmarks.first.uuid | ||||
|   }; | ||||
|  | ||||
|  | ||||
|   | ||||
| @@ -1,16 +1,19 @@ | ||||
| import "dart:convert"; | ||||
| import "dart:developer"; | ||||
|  | ||||
| import 'package:dio/dio.dart'; | ||||
| import 'package:anyway/constants.dart'; | ||||
| import "package:anyway/structs/landmark.dart"; | ||||
| import "package:anyway/structs/trip.dart"; | ||||
| import "package:anyway/structs/preferences.dart"; | ||||
|  | ||||
| import "package:anyway/structs/linked_landmarks.dart"; | ||||
|  | ||||
| Dio dio = Dio( | ||||
|     BaseOptions( | ||||
|       baseUrl: API_URL_BASE, | ||||
|       // baseUrl: 'http://localhost:8000', | ||||
|       connectTimeout: const Duration(seconds: 5), | ||||
|       receiveTimeout: const Duration(seconds: 60), | ||||
|       receiveTimeout: const Duration(seconds: 120), | ||||
|       // api is notoriously slow | ||||
|       // headers: { | ||||
|       //   HttpHeaders.userAgentHeader: 'dio', | ||||
| @@ -18,19 +21,25 @@ Dio dio = Dio( | ||||
|       // }, | ||||
|       contentType: Headers.jsonContentType, | ||||
|       responseType: ResponseType.json, | ||||
|          | ||||
|   ), | ||||
| ); | ||||
|  | ||||
| Future<Trip> fetchTrip( | ||||
| Future<Trip>? fetchTrip( | ||||
|   List<double> startPoint, | ||||
|   UserPreferences preferences, | ||||
|   Future<UserPreferences> preferences, | ||||
| ) async { | ||||
|   UserPreferences prefs = await preferences; | ||||
|   Map<String, dynamic> data = { | ||||
|     "preferences": prefs.toJson(), | ||||
|     "start": startPoint | ||||
|   }; | ||||
|   String dataString = jsonEncode(data); | ||||
|   log(dataString); | ||||
|  | ||||
|   final response = await dio.post( | ||||
|     "/trip/new", | ||||
|     data: { | ||||
|       'preferences': preferences.toJson(), | ||||
|       'start': startPoint | ||||
|     } | ||||
|     data: data | ||||
|   ); | ||||
|  | ||||
|   // handle errors | ||||
| @@ -40,6 +49,37 @@ Future<Trip> fetchTrip( | ||||
|   if (response.data["error"] != null) { | ||||
|     throw Exception(response.data["error"]); | ||||
|   } | ||||
|   return Trip.fromJson(response.data); | ||||
|   log(response.data.toString()); | ||||
|   Map<String, dynamic> json = response.data; | ||||
|  | ||||
|   // only fetch the trip "meta" data for now | ||||
|   Trip trip = Trip.fromJson(json); | ||||
|  | ||||
|   String? nextUUID = json["first_landmark_uuid"]; | ||||
|   while (nextUUID != null) { | ||||
|     var (landmark, newUUID) = await fetchLandmark(nextUUID); | ||||
|     trip.landmarks.add(landmark); | ||||
|     nextUUID = newUUID; | ||||
|   } | ||||
|   return trip; | ||||
| } | ||||
|  | ||||
|  | ||||
|  | ||||
| Future<(Landmark, String?)> fetchLandmark(String uuid) async { | ||||
|   final response = await dio.get( | ||||
|     "/landmark/$uuid" | ||||
|   ); | ||||
|  | ||||
|   // handle errors | ||||
|   if (response.statusCode != 200) { | ||||
|     throw Exception('Failed to load landmark'); | ||||
|   } | ||||
|   if (response.data["error"] != null) { | ||||
|     throw Exception(response.data["error"]); | ||||
|   } | ||||
|   log(response.data.toString()); | ||||
|   Map<String, dynamic> json = response.data; | ||||
|   String? nextUUID = json["next_uuid"]; | ||||
|   return (Landmark.fromJson(json), nextUUID); | ||||
| } | ||||
|   | ||||
		Reference in New Issue
	
	Block a user