diff --git a/frontend/lib/layout.dart b/frontend/lib/layout.dart index 43aebde..7a214d3 100644 --- a/frontend/lib/layout.dart +++ b/frontend/lib/layout.dart @@ -136,12 +136,20 @@ class _BasePageState extends State { // TODO: Implement this function Trip getFirstTrip(Future> trips) { Trip t1 = Trip(uuid: '1', landmarks: LinkedList()); + t1.landmarks.add( + Landmark( + uuid: '0', + name: "Start", + location: [48.85, 2.32], + type: start, + ), + ); t1.landmarks.add( Landmark( uuid: '1', name: "Eiffel Tower", 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" ), ); @@ -150,7 +158,7 @@ Trip getFirstTrip(Future> trips) { uuid: "2", name: "Notre Dame Cathedral", 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" ), ); @@ -159,7 +167,7 @@ Trip getFirstTrip(Future> trips) { uuid: "3", name: "Louvre palace", 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" ), ); @@ -168,7 +176,7 @@ Trip getFirstTrip(Future> trips) { uuid: "4", name: "Pont-des-arts", 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" ), ); @@ -177,9 +185,18 @@ Trip getFirstTrip(Future> trips) { uuid: "5", name: "Panthéon", 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" ), ); + 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; } \ No newline at end of file diff --git a/frontend/lib/modules/map.dart b/frontend/lib/modules/map.dart index 199388b..d47f88f 100644 --- a/frontend/lib/modules/map.dart +++ b/frontend/lib/modules/map.dart @@ -1,4 +1,5 @@ import 'dart:collection'; +import 'dart:developer'; import 'package:flutter/material.dart'; import 'package:anyway/structs/landmark.dart'; @@ -21,7 +22,7 @@ class MapWidget extends StatefulWidget { class _MapWidgetState extends State { late GoogleMapController mapController; - // coordinates of Paris + CameraPosition _cameraPosition = CameraPosition( target: LatLng(48.8566, 2.3522), zoom: 11.0, @@ -36,7 +37,7 @@ class _MapWidgetState extends State { CameraUpdate update = CameraUpdate.newLatLng(LatLng(newLocation[0], newLocation[1])); controller.moveCamera(update); } - // addLandmarkMarker(); + setMapMarkers(); } void _onCameraIdle() { @@ -44,45 +45,37 @@ class _MapWidgetState extends State { } - void addLandmarkMarker() async { - LinkedList? landmarks = widget.trip?.landmarks; - int i = mapMarkers.length; - Landmark? current = landmarks!.elementAtOrNull(i); - if (current != null){ - mapMarkers.add( - Marker( - markerId: MarkerId(current.name), - position: LatLng(current.location[0], current.location[1]), - icon: await CustomMarker( - landmark: current, - position: i+1 - ).toBitmapDescriptor( - logicalSize: const Size(150, 150), - imageSize: const Size(150, 150) - ) - ) + void setMapMarkers() async { + List landmarks = widget.trip?.landmarks.toList() ?? []; + Set newMarkers = {}; + for (int i = 0; i < landmarks.length; i++) { + Landmark landmark = landmarks[i]; + List location = landmark.location; + Marker marker = Marker( + markerId: MarkerId(landmark.uuid), + position: LatLng(location[0], location[1]), + icon: await CustomMarker(landmark: landmark, position: i).toBitmapDescriptor( + logicalSize: const Size(150, 150), + imageSize: const Size(150, 150) + ), ); - setState(() {}); + newMarkers.add(marker); } + setState(() { + mapMarkers = newMarkers; + }); } - @override Widget build(BuildContext context) { - return ListenableBuilder( - listenable: widget.trip!, - builder: (context, child) { - addLandmarkMarker(); - return GoogleMap( - onMapCreated: _onMapCreated, - initialCameraPosition: _cameraPosition, - onCameraIdle: _onCameraIdle, - - // onLongPress: , - markers: mapMarkers, - cloudMapId: '41c21ac9b81dbfd8', - ); - } + widget.trip?.addListener(setMapMarkers); + return GoogleMap( + onMapCreated: _onMapCreated, + initialCameraPosition: _cameraPosition, + onCameraIdle: _onCameraIdle, + // 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 // As a small dot, the number of the landmark is displayed in the top right Icon icon; - if (landmark.type == museum) { - icon = Icon(Icons.museum, color: Colors.black, size: 50); - } else if (landmark.type == monument) { + if (landmark.type == sightseeing) { 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); - } else if (landmark.type == restaurant) { - icon = Icon(Icons.restaurant, color: Colors.black, size: 50); - } else if (landmark.type == shop) { + } else if (landmark.type == shopping) { 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 { 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( child: Stack( children: [ @@ -136,18 +143,7 @@ class CustomMarker extends StatelessWidget { ), child: icon, ), - 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)), - ), - ), + positionIndicator ?? Container(), ], ), ); diff --git a/frontend/lib/pages/new_trip.dart b/frontend/lib/pages/new_trip.dart index 79c15ae..f3e97d3 100644 --- a/frontend/lib/pages/new_trip.dart +++ b/frontend/lib/pages/new_trip.dart @@ -29,66 +29,64 @@ class _NewTripPageState extends State { ), body: Form( key: _formKey, - child: - Padding( - padding: const EdgeInsets.all(15.0), - child: Column( - crossAxisAlignment: CrossAxisAlignment.start, - - children: [ - TextFormField( - decoration: const InputDecoration(hintText: 'Lat'), - controller: latController, - validator: (String? value) { - if (value == null || value.isEmpty || double.tryParse(value) == null){ - return 'Please enter a floating point number'; - } - return null; - }, - ), - TextFormField( - decoration: const InputDecoration(hintText: 'Lon'), - controller: lonController, + child: Padding( + padding: const EdgeInsets.all(15.0), + child: Column( + crossAxisAlignment: CrossAxisAlignment.start, + + children: [ + TextFormField( + decoration: const InputDecoration(hintText: 'Lat'), + controller: latController, + validator: (String? value) { + if (value == null || value.isEmpty || double.tryParse(value) == null){ + return 'Please enter a floating point number'; + } + return null; + }, + ), + TextFormField( + decoration: const InputDecoration(hintText: 'Lon'), + controller: lonController, - validator: (String? value) { - if (value == null || value.isEmpty || double.tryParse(value) == null){ - return 'Please enter a floating point number'; - } - return null; - }, - ), - Divider(height: 15, color: Colors.transparent), - ElevatedButton( - onPressed: () { - if (_formKey.currentState!.validate()) { - List startPoint = [ - double.parse(latController.text), - double.parse(lonController.text) - ]; - Future preferences = loadUserPreferences(); - Trip trip = Trip(); - trip.landmarks.add( - Landmark( - location: startPoint, - name: "start", - type: LandmarkType(name: 'start'), - uuid: "pending" - ) - ); - fetchTrip(trip, preferences); - Navigator.of(context).push( - MaterialPageRoute( - builder: (context) => BasePage(mainScreen: "map", trip: trip) - ) - ); - } - }, - child: const Text('Create trip'), - ), - ], - ), - ) - + validator: (String? value) { + if (value == null || value.isEmpty || double.tryParse(value) == null){ + return 'Please enter a floating point number'; + } + return null; + }, + ), + Divider(height: 15, color: Colors.transparent), + ElevatedButton( + child: const Text('Create trip'), + onPressed: () { + if (_formKey.currentState!.validate()) { + List startPoint = [ + double.parse(latController.text), + double.parse(lonController.text) + ]; + Future preferences = loadUserPreferences(); + Trip trip = Trip(); + trip.landmarks.add( + Landmark( + location: startPoint, + name: "Start", + type: start, + uuid: "pending" + ) + ); + fetchTrip(trip, preferences); + Navigator.of(context).push( + MaterialPageRoute( + builder: (context) => BasePage(mainScreen: "map", trip: trip) + ) + ); + } + }, + ), + ], + ), + ) ) ); } diff --git a/frontend/lib/structs/landmark.dart b/frontend/lib/structs/landmark.dart index 0f387af..50918af 100644 --- a/frontend/lib/structs/landmark.dart +++ b/frontend/lib/structs/landmark.dart @@ -3,12 +3,13 @@ import 'dart:convert'; import 'package:shared_preferences/shared_preferences.dart'; - -const LandmarkType museum = LandmarkType(name: 'Museum'); -const LandmarkType monument = LandmarkType(name: 'Monument'); -const LandmarkType park = LandmarkType(name: 'Park'); -const LandmarkType restaurant = LandmarkType(name: 'Restaurant'); -const LandmarkType shop = LandmarkType(name: 'Shop'); +const LandmarkType sightseeing = LandmarkType(name: 'sightseeing'); +const LandmarkType nature = LandmarkType(name: 'nature'); +const LandmarkType shopping = LandmarkType(name: 'shopping'); +// const LandmarkType museum = LandmarkType(name: 'Museum'); +// const LandmarkType restaurant = LandmarkType(name: 'Restaurant'); +const LandmarkType start = LandmarkType(name: 'start'); +const LandmarkType finish = LandmarkType(name: 'finish'); final class Landmark extends LinkedListEntry{ @@ -55,7 +56,7 @@ final class Landmark extends LinkedListEntry{ 'location': List location, 'type': String type, }) { - // refine the parsing on a few + // refine the parsing on a few fields List locationFixed = List.from(location); // parse the rest separately, they could be missing LandmarkType typeFixed = LandmarkType(name: type); @@ -106,6 +107,14 @@ class LandmarkType { // required this.description, // required this.icon, }); + @override + bool operator ==(Object other) { + if (other is LandmarkType) { + return name == other.name; + } else { + return false; + } + } } diff --git a/frontend/lib/utils/fetch_trip.dart b/frontend/lib/utils/fetch_trip.dart index d85ab76..8ed04d3 100644 --- a/frontend/lib/utils/fetch_trip.dart +++ b/frontend/lib/utils/fetch_trip.dart @@ -49,24 +49,26 @@ fetchTrip( trip.updateUUID("error"); if (response.data["detail"] != null) { trip.updateError(response.data["detail"]); + log(response.data["detail"]); // throw Exception(response.data["detail"]); } - } + } else { + Map 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()); - Map 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; } }