bare implementation of comuncation with the api
All checks were successful
Build and push docker image / Build (pull_request) Successful in 2m6s
Build and release APK / Build APK (pull_request) Successful in 4m32s

This commit is contained in:
Remy Moll 2024-08-01 22:48:28 +02:00
parent 016622c7af
commit 5748630b99
5 changed files with 94 additions and 39 deletions

View File

@ -20,26 +20,40 @@ class Greeter extends StatefulWidget {
class _GreeterState extends State<Greeter> { class _GreeterState extends State<Greeter> {
Widget greeterBuild (BuildContext context, AsyncSnapshot<Trip> snapshot) { Widget greeterBuild (BuildContext context, AsyncSnapshot<Trip> snapshot) {
ThemeData theme = Theme.of(context); ThemeData theme = Theme.of(context);
String cityName = ""; Widget topGreeter;
if (snapshot.hasData) { 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) { } else if (snapshot.hasError) {
cityName = "error"; topGreeter = const Padding(
} else { // still awaiting the cityname padding: EdgeInsets.only(top: 20, bottom: 20),
cityName = "..."; 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) { if (widget.standalone) {
return Center( return Center(
child: Padding(
padding: EdgeInsets.only(top: 24.0),
child: topGreeter, child: topGreeter,
),
); );
} else { } else {
return Center( return Center(

View File

@ -63,9 +63,8 @@ class _NewTripPageState extends State<NewTripPage> {
double.parse(latController.text), double.parse(latController.text),
double.parse(lonController.text) double.parse(lonController.text)
]; ];
UserPreferences preferences = UserPreferences(); Future<UserPreferences> preferences = loadUserPreferences();
preferences.load(); Future<Trip>? trip = fetchTrip(startPoint, preferences);
Future<Trip> trip = fetchTrip(startPoint, preferences);
Navigator.of(context).push( Navigator.of(context).push(
MaterialPageRoute( MaterialPageRoute(
builder: (context) => BasePage(mainScreen: "map", trip: trip) builder: (context) => BasePage(mainScreen: "map", trip: trip)

View File

@ -82,17 +82,15 @@ class UserPreferences {
} }
} }
String toJson() { Map<String, dynamic> toJson() {
// This is "opinionated" JSON, corresponding to the backend's expectations // This is "opinionated" JSON, corresponding to the backend's expectations
return ''' return {
{ "sightseeing": {"type": "sightseeing", "score": sightseeing.value},
"sightseeing": {"type": "sightseeing", "score": ${sightseeing.value}}, "shopping": {"type": "shopping", "score": shopping.value},
"shopping": {"type": "shopping", "score": ${shopping.value}}, "nature": {"type": "nature", "score": nature.value},
"nature": {"type": "nature", "score": ${nature.value}}, "max_time_minute": maxTime.value,
"max_time_minutes": ${maxTime.value}, "detour_tolerance_minute": maxDetour.value
"detour_tolerance_minute": ${maxDetour.value} };
}
''';
} }
} }

View File

@ -11,6 +11,7 @@ class Trip {
final String uuid; final String uuid;
final String cityName; final String cityName;
// TODO: cityName should be inferred from coordinates of the Landmarks // TODO: cityName should be inferred from coordinates of the Landmarks
final int totalTime;
final LinkedList<Landmark> landmarks; final LinkedList<Landmark> landmarks;
// could be empty as well // could be empty as well
@ -19,15 +20,18 @@ class Trip {
required this.uuid, required this.uuid,
required this.cityName, required this.cityName,
required this.landmarks, required this.landmarks,
this.totalTime = 0
}); });
factory Trip.fromJson(Map<String, dynamic> json) { factory Trip.fromJson(Map<String, dynamic> json) {
return Trip( Trip trip = Trip(
uuid: json['uuid'], uuid: json['uuid'],
cityName: json['city_name'], cityName: json['city_name'] ?? 'Not communicated',
landmarks: LinkedList() landmarks: LinkedList()
); );
return trip;
} }
@ -44,7 +48,7 @@ class Trip {
Map<String, dynamic> toJson() => { Map<String, dynamic> toJson() => {
'uuid': uuid, 'uuid': uuid,
'city_name': cityName, 'city_name': cityName,
'entry_uuid': landmarks.first?.uuid ?? '' 'first_landmark_uuid': landmarks.first.uuid
}; };

View File

@ -1,16 +1,19 @@
import "dart:convert";
import "dart:developer";
import 'package:dio/dio.dart'; import 'package:dio/dio.dart';
import 'package:anyway/constants.dart'; import 'package:anyway/constants.dart';
import "package:anyway/structs/landmark.dart"; import "package:anyway/structs/landmark.dart";
import "package:anyway/structs/trip.dart"; import "package:anyway/structs/trip.dart";
import "package:anyway/structs/preferences.dart"; import "package:anyway/structs/preferences.dart";
import "package:anyway/structs/linked_landmarks.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: 60), receiveTimeout: const Duration(seconds: 120),
// api is notoriously slow // api is notoriously slow
// headers: { // headers: {
// HttpHeaders.userAgentHeader: 'dio', // HttpHeaders.userAgentHeader: 'dio',
@ -18,19 +21,25 @@ Dio dio = Dio(
// }, // },
contentType: Headers.jsonContentType, contentType: Headers.jsonContentType,
responseType: ResponseType.json, responseType: ResponseType.json,
), ),
); );
Future<Trip> fetchTrip( Future<Trip>? fetchTrip(
List<double> startPoint, List<double> startPoint,
UserPreferences preferences, Future<UserPreferences> preferences,
) async { ) 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( final response = await dio.post(
"/trip/new", "/trip/new",
data: { data: data
'preferences': preferences.toJson(),
'start': startPoint
}
); );
// handle errors // handle errors
@ -40,6 +49,37 @@ Future<Trip> fetchTrip(
if (response.data["error"] != null) { if (response.data["error"] != null) {
throw Exception(response.data["error"]); 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);
}