show correct landmark types when fetching from api
All checks were successful
Build and push docker image / Build (pull_request) Successful in 1m42s
Build and release APK / Build APK (pull_request) Successful in 5m22s

This commit is contained in:
Remy Moll 2024-08-06 14:34:12 +02:00
parent 89511f39cb
commit f71b9b19a6
5 changed files with 161 additions and 139 deletions

View File

@ -136,12 +136,20 @@ class _BasePageState extends State<BasePage> {
// TODO: Implement this function // TODO: Implement this function
Trip getFirstTrip(Future<List<Trip>> trips) { Trip getFirstTrip(Future<List<Trip>> trips) {
Trip t1 = Trip(uuid: '1', landmarks: LinkedList<Landmark>()); Trip t1 = Trip(uuid: '1', landmarks: LinkedList<Landmark>());
t1.landmarks.add(
Landmark(
uuid: '0',
name: "Start",
location: [48.85, 2.32],
type: start,
),
);
t1.landmarks.add( t1.landmarks.add(
Landmark( Landmark(
uuid: '1', uuid: '1',
name: "Eiffel Tower", name: "Eiffel Tower",
location: [48.859, 2.295], location: [48.859, 2.295],
type: monument, type: sightseeing,
imageURL: "https://upload.wikimedia.org/wikipedia/commons/thumb/a/a8/Tour_Eiffel_Wikimedia_Commons.jpg/1037px-Tour_Eiffel_Wikimedia_Commons.jpg" imageURL: "https://upload.wikimedia.org/wikipedia/commons/thumb/a/a8/Tour_Eiffel_Wikimedia_Commons.jpg/1037px-Tour_Eiffel_Wikimedia_Commons.jpg"
), ),
); );
@ -150,7 +158,7 @@ Trip getFirstTrip(Future<List<Trip>> trips) {
uuid: "2", uuid: "2",
name: "Notre Dame Cathedral", name: "Notre Dame Cathedral",
location: [48.8530, 2.3498], location: [48.8530, 2.3498],
type: monument, type: sightseeing,
imageURL: "https://upload.wikimedia.org/wikipedia/commons/thumb/f/f7/Notre-Dame_de_Paris%2C_4_October_2017.jpg/440px-Notre-Dame_de_Paris%2C_4_October_2017.jpg" imageURL: "https://upload.wikimedia.org/wikipedia/commons/thumb/f/f7/Notre-Dame_de_Paris%2C_4_October_2017.jpg/440px-Notre-Dame_de_Paris%2C_4_October_2017.jpg"
), ),
); );
@ -159,7 +167,7 @@ Trip getFirstTrip(Future<List<Trip>> trips) {
uuid: "3", uuid: "3",
name: "Louvre palace", name: "Louvre palace",
location: [48.8606, 2.3376], location: [48.8606, 2.3376],
type: museum, type: sightseeing,
imageURL: "https://upload.wikimedia.org/wikipedia/commons/thumb/6/66/Louvre_Museum_Wikimedia_Commons.jpg/540px-Louvre_Museum_Wikimedia_Commons.jpg" imageURL: "https://upload.wikimedia.org/wikipedia/commons/thumb/6/66/Louvre_Museum_Wikimedia_Commons.jpg/540px-Louvre_Museum_Wikimedia_Commons.jpg"
), ),
); );
@ -168,7 +176,7 @@ Trip getFirstTrip(Future<List<Trip>> trips) {
uuid: "4", uuid: "4",
name: "Pont-des-arts", name: "Pont-des-arts",
location: [48.8585, 2.3376], location: [48.8585, 2.3376],
type: monument, type: sightseeing,
imageURL: "https://upload.wikimedia.org/wikipedia/commons/thumb/d/d1/Pont_des_Arts%2C_6e_Arrondissement%2C_Paris_%28HDR%29_20140320_1.jpg/560px-Pont_des_Arts%2C_6e_Arrondissement%2C_Paris_%28HDR%29_20140320_1.jpg" imageURL: "https://upload.wikimedia.org/wikipedia/commons/thumb/d/d1/Pont_des_Arts%2C_6e_Arrondissement%2C_Paris_%28HDR%29_20140320_1.jpg/560px-Pont_des_Arts%2C_6e_Arrondissement%2C_Paris_%28HDR%29_20140320_1.jpg"
), ),
); );
@ -177,9 +185,18 @@ Trip getFirstTrip(Future<List<Trip>> trips) {
uuid: "5", uuid: "5",
name: "Panthéon", name: "Panthéon",
location: [48.847, 2.347], location: [48.847, 2.347],
type: monument, type: sightseeing,
imageURL: "https://upload.wikimedia.org/wikipedia/commons/thumb/8/80/Pantheon_of_Paris_007.JPG/1280px-Pantheon_of_Paris_007.JPG" imageURL: "https://upload.wikimedia.org/wikipedia/commons/thumb/8/80/Pantheon_of_Paris_007.JPG/1280px-Pantheon_of_Paris_007.JPG"
), ),
); );
t1.landmarks.add(
Landmark(
uuid: "6",
name: "Galeries Lafayette",
location: [48.87, 2.32],
type: shopping,
imageURL: "https://upload.wikimedia.org/wikipedia/commons/thumb/d/de/GaleriesLafayetteNuit.jpg/220px-GaleriesLafayetteNuit.jpg"
),
);
return t1; return t1;
} }

View File

@ -1,4 +1,5 @@
import 'dart:collection'; import 'dart:collection';
import 'dart:developer';
import 'package:flutter/material.dart'; import 'package:flutter/material.dart';
import 'package:anyway/structs/landmark.dart'; import 'package:anyway/structs/landmark.dart';
@ -21,7 +22,7 @@ class MapWidget extends StatefulWidget {
class _MapWidgetState extends State<MapWidget> { class _MapWidgetState extends State<MapWidget> {
late GoogleMapController mapController; late GoogleMapController mapController;
// coordinates of Paris
CameraPosition _cameraPosition = CameraPosition( CameraPosition _cameraPosition = CameraPosition(
target: LatLng(48.8566, 2.3522), target: LatLng(48.8566, 2.3522),
zoom: 11.0, zoom: 11.0,
@ -36,7 +37,7 @@ class _MapWidgetState extends State<MapWidget> {
CameraUpdate update = CameraUpdate.newLatLng(LatLng(newLocation[0], newLocation[1])); CameraUpdate update = CameraUpdate.newLatLng(LatLng(newLocation[0], newLocation[1]));
controller.moveCamera(update); controller.moveCamera(update);
} }
// addLandmarkMarker(); setMapMarkers();
} }
void _onCameraIdle() { void _onCameraIdle() {
@ -44,45 +45,37 @@ class _MapWidgetState extends State<MapWidget> {
} }
void addLandmarkMarker() async { void setMapMarkers() async {
LinkedList<Landmark>? landmarks = widget.trip?.landmarks; List<Landmark> landmarks = widget.trip?.landmarks.toList() ?? [];
int i = mapMarkers.length; Set<Marker> newMarkers = <Marker>{};
Landmark? current = landmarks!.elementAtOrNull(i); for (int i = 0; i < landmarks.length; i++) {
if (current != null){ Landmark landmark = landmarks[i];
mapMarkers.add( List<double> location = landmark.location;
Marker( Marker marker = Marker(
markerId: MarkerId(current.name), markerId: MarkerId(landmark.uuid),
position: LatLng(current.location[0], current.location[1]), position: LatLng(location[0], location[1]),
icon: await CustomMarker( icon: await CustomMarker(landmark: landmark, position: i).toBitmapDescriptor(
landmark: current, logicalSize: const Size(150, 150),
position: i+1 imageSize: const Size(150, 150)
).toBitmapDescriptor( ),
logicalSize: const Size(150, 150),
imageSize: const Size(150, 150)
)
)
); );
setState(() {}); newMarkers.add(marker);
} }
setState(() {
mapMarkers = newMarkers;
});
} }
@override @override
Widget build(BuildContext context) { Widget build(BuildContext context) {
return ListenableBuilder( widget.trip?.addListener(setMapMarkers);
listenable: widget.trip!, return GoogleMap(
builder: (context, child) { onMapCreated: _onMapCreated,
addLandmarkMarker(); initialCameraPosition: _cameraPosition,
return GoogleMap( onCameraIdle: _onCameraIdle,
onMapCreated: _onMapCreated, // onLongPress: ,
initialCameraPosition: _cameraPosition, markers: mapMarkers,
onCameraIdle: _onCameraIdle, cloudMapId: '41c21ac9b81dbfd8',
// onLongPress: ,
markers: mapMarkers,
cloudMapId: '41c21ac9b81dbfd8',
);
}
); );
} }
} }
@ -103,20 +96,34 @@ class CustomMarker extends StatelessWidget {
// This returns an outlined circle, with an icon corresponding to the landmark type // This returns an outlined circle, with an icon corresponding to the landmark type
// As a small dot, the number of the landmark is displayed in the top right // As a small dot, the number of the landmark is displayed in the top right
Icon icon; Icon icon;
if (landmark.type == museum) { if (landmark.type == sightseeing) {
icon = Icon(Icons.museum, color: Colors.black, size: 50);
} else if (landmark.type == monument) {
icon = Icon(Icons.church, color: Colors.black, size: 50); icon = Icon(Icons.church, color: Colors.black, size: 50);
} else if (landmark.type == park) { } else if (landmark.type == nature) {
icon = Icon(Icons.park, color: Colors.black, size: 50); icon = Icon(Icons.park, color: Colors.black, size: 50);
} else if (landmark.type == restaurant) { } else if (landmark.type == shopping) {
icon = Icon(Icons.restaurant, color: Colors.black, size: 50);
} else if (landmark.type == shop) {
icon = Icon(Icons.shopping_cart, color: Colors.black, size: 50); icon = Icon(Icons.shopping_cart, color: Colors.black, size: 50);
} else if (landmark.type == start || landmark.type == finish) {
icon = Icon(Icons.flag, color: Colors.black, size: 50);
} else { } else {
icon = Icon(Icons.location_on, color: Colors.black, size: 50); icon = Icon(Icons.location_on, color: Colors.black, size: 50);
} }
Widget? positionIndicator;
if (landmark.type != start && landmark.type != finish) {
positionIndicator = Positioned(
top: 0,
right: 0,
child: Container(
padding: EdgeInsets.all(5),
decoration: BoxDecoration(
color: Theme.of(context).primaryColor,
shape: BoxShape.circle,
),
child: Text('$position', style: TextStyle(color: Colors.white, fontSize: 20)),
),
);
}
return RepaintBoundary( return RepaintBoundary(
child: Stack( child: Stack(
children: [ children: [
@ -136,18 +143,7 @@ class CustomMarker extends StatelessWidget {
), ),
child: icon, child: icon,
), ),
Positioned( positionIndicator ?? Container(),
top: 0,
right: 0,
child: Container(
padding: EdgeInsets.all(5),
decoration: BoxDecoration(
color: Theme.of(context).primaryColor,
shape: BoxShape.circle,
),
child: Text('$position', style: TextStyle(color: Colors.white, fontSize: 20)),
),
),
], ],
), ),
); );

View File

@ -29,66 +29,64 @@ class _NewTripPageState extends State<NewTripPage> {
), ),
body: Form( body: Form(
key: _formKey, key: _formKey,
child: child: Padding(
Padding( padding: const EdgeInsets.all(15.0),
padding: const EdgeInsets.all(15.0), child: Column(
child: Column( crossAxisAlignment: CrossAxisAlignment.start,
crossAxisAlignment: CrossAxisAlignment.start,
children: <Widget>[
children: <Widget>[ TextFormField(
TextFormField( decoration: const InputDecoration(hintText: 'Lat'),
decoration: const InputDecoration(hintText: 'Lat'), controller: latController,
controller: latController, validator: (String? value) {
validator: (String? value) { if (value == null || value.isEmpty || double.tryParse(value) == null){
if (value == null || value.isEmpty || double.tryParse(value) == null){ return 'Please enter a floating point number';
return 'Please enter a floating point number'; }
} return null;
return null; },
}, ),
), TextFormField(
TextFormField( decoration: const InputDecoration(hintText: 'Lon'),
decoration: const InputDecoration(hintText: 'Lon'), controller: lonController,
controller: lonController,
validator: (String? value) { validator: (String? value) {
if (value == null || value.isEmpty || double.tryParse(value) == null){ if (value == null || value.isEmpty || double.tryParse(value) == null){
return 'Please enter a floating point number'; return 'Please enter a floating point number';
} }
return null; return null;
}, },
), ),
Divider(height: 15, color: Colors.transparent), Divider(height: 15, color: Colors.transparent),
ElevatedButton( ElevatedButton(
onPressed: () { child: const Text('Create trip'),
if (_formKey.currentState!.validate()) { onPressed: () {
List<double> startPoint = [ if (_formKey.currentState!.validate()) {
double.parse(latController.text), List<double> startPoint = [
double.parse(lonController.text) double.parse(latController.text),
]; double.parse(lonController.text)
Future<UserPreferences> preferences = loadUserPreferences(); ];
Trip trip = Trip(); Future<UserPreferences> preferences = loadUserPreferences();
trip.landmarks.add( Trip trip = Trip();
Landmark( trip.landmarks.add(
location: startPoint, Landmark(
name: "start", location: startPoint,
type: LandmarkType(name: 'start'), name: "Start",
uuid: "pending" type: start,
) uuid: "pending"
); )
fetchTrip(trip, preferences); );
Navigator.of(context).push( fetchTrip(trip, preferences);
MaterialPageRoute( Navigator.of(context).push(
builder: (context) => BasePage(mainScreen: "map", trip: trip) MaterialPageRoute(
) builder: (context) => BasePage(mainScreen: "map", trip: trip)
); )
} );
}, }
child: const Text('Create trip'), },
), ),
], ],
), ),
) )
) )
); );
} }

View File

@ -3,12 +3,13 @@ import 'dart:convert';
import 'package:shared_preferences/shared_preferences.dart'; import 'package:shared_preferences/shared_preferences.dart';
const LandmarkType sightseeing = LandmarkType(name: 'sightseeing');
const LandmarkType museum = LandmarkType(name: 'Museum'); const LandmarkType nature = LandmarkType(name: 'nature');
const LandmarkType monument = LandmarkType(name: 'Monument'); const LandmarkType shopping = LandmarkType(name: 'shopping');
const LandmarkType park = LandmarkType(name: 'Park'); // const LandmarkType museum = LandmarkType(name: 'Museum');
const LandmarkType restaurant = LandmarkType(name: 'Restaurant'); // const LandmarkType restaurant = LandmarkType(name: 'Restaurant');
const LandmarkType shop = LandmarkType(name: 'Shop'); const LandmarkType start = LandmarkType(name: 'start');
const LandmarkType finish = LandmarkType(name: 'finish');
final class Landmark extends LinkedListEntry<Landmark>{ final class Landmark extends LinkedListEntry<Landmark>{
@ -55,7 +56,7 @@ final class Landmark extends LinkedListEntry<Landmark>{
'location': List<dynamic> location, 'location': List<dynamic> location,
'type': String type, 'type': String type,
}) { }) {
// refine the parsing on a few // refine the parsing on a few fields
List<double> locationFixed = List<double>.from(location); List<double> locationFixed = List<double>.from(location);
// parse the rest separately, they could be missing // parse the rest separately, they could be missing
LandmarkType typeFixed = LandmarkType(name: type); LandmarkType typeFixed = LandmarkType(name: type);
@ -106,6 +107,14 @@ class LandmarkType {
// required this.description, // required this.description,
// required this.icon, // required this.icon,
}); });
@override
bool operator ==(Object other) {
if (other is LandmarkType) {
return name == other.name;
} else {
return false;
}
}
} }

View File

@ -49,24 +49,26 @@ fetchTrip(
trip.updateUUID("error"); trip.updateUUID("error");
if (response.data["detail"] != null) { if (response.data["detail"] != null) {
trip.updateError(response.data["detail"]); trip.updateError(response.data["detail"]);
log(response.data["detail"]);
// throw Exception(response.data["detail"]); // throw Exception(response.data["detail"]);
} }
} } else {
Map<String, dynamic> json = response.data;
// only fill in the trip "meta" data for now
trip.loadFromJson(json);
// now fill the trip with landmarks
// 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) {
var (landmark, newUUID) = await fetchLandmark(nextUUID);
trip.addLandmark(landmark);
nextUUID = newUUID;
}
log(response.data.toString()); 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
// 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) {
var (landmark, newUUID) = await fetchLandmark(nextUUID);
trip.addLandmark(landmark);
nextUUID = newUUID;
} }
} }