diff --git a/frontend/lib/layout.dart b/frontend/lib/layout.dart index fbfc6ca..43aebde 100644 --- a/frontend/lib/layout.dart +++ b/frontend/lib/layout.dart @@ -141,7 +141,7 @@ Trip getFirstTrip(Future> trips) { uuid: '1', name: "Eiffel Tower", location: [48.859, 2.295], - type: LandmarkType(name: "Tower"), + type: monument, imageURL: "https://upload.wikimedia.org/wikipedia/commons/thumb/a/a8/Tour_Eiffel_Wikimedia_Commons.jpg/1037px-Tour_Eiffel_Wikimedia_Commons.jpg" ), ); @@ -150,7 +150,7 @@ Trip getFirstTrip(Future> trips) { uuid: "2", name: "Notre Dame Cathedral", location: [48.8530, 2.3498], - type: LandmarkType(name: "Monument"), + type: monument, 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 +159,7 @@ Trip getFirstTrip(Future> trips) { uuid: "3", name: "Louvre palace", location: [48.8606, 2.3376], - type: LandmarkType(name: "Museum"), + type: museum, imageURL: "https://upload.wikimedia.org/wikipedia/commons/thumb/6/66/Louvre_Museum_Wikimedia_Commons.jpg/540px-Louvre_Museum_Wikimedia_Commons.jpg" ), ); @@ -168,7 +168,7 @@ Trip getFirstTrip(Future> trips) { uuid: "4", name: "Pont-des-arts", location: [48.8585, 2.3376], - type: LandmarkType(name: "Bridge"), + type: monument, 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,7 +177,7 @@ Trip getFirstTrip(Future> trips) { uuid: "5", name: "Panthéon", location: [48.847, 2.347], - type: LandmarkType(name: "Monument"), + type: monument, imageURL: "https://upload.wikimedia.org/wikipedia/commons/thumb/8/80/Pantheon_of_Paris_007.JPG/1280px-Pantheon_of_Paris_007.JPG" ), ); diff --git a/frontend/lib/modules/greeter.dart b/frontend/lib/modules/greeter.dart index 6b74c13..034720e 100644 --- a/frontend/lib/modules/greeter.dart +++ b/frontend/lib/modules/greeter.dart @@ -1,4 +1,5 @@ import 'package:anyway/structs/trip.dart'; +import 'package:auto_size_text/auto_size_text.dart'; import 'package:flutter/material.dart'; @@ -24,14 +25,21 @@ class _GreeterState extends State { future: widget.trip.cityName, builder: (BuildContext context, AsyncSnapshot snapshot) { if (snapshot.hasData) { - return Text( + return AutoSizeText( + maxLines: 1, 'Welcome to ${snapshot.data}!', style: TextStyle(color: theme.primaryColor, fontWeight: FontWeight.bold, fontSize: 24), ); } else if (snapshot.hasError) { - return const Text('Welcome to your trip!'); + return const AutoSizeText( + maxLines: 1, + 'Welcome to your trip!' + ); } else { - return const Text('Welcome to ...'); + return const AutoSizeText( + maxLines: 1, + 'Welcome to ...' + ); } } ); diff --git a/frontend/lib/modules/landmarks_overview.dart b/frontend/lib/modules/landmarks_overview.dart index 387bf11..844673d 100644 --- a/frontend/lib/modules/landmarks_overview.dart +++ b/frontend/lib/modules/landmarks_overview.dart @@ -51,7 +51,7 @@ class _LandmarksOverviewState extends State { ]; } else { children = [ - landmarksWithSteps(trip.landmarks), + landmarksWithSteps(), saveButton(), ]; } @@ -71,55 +71,61 @@ class _LandmarksOverviewState extends State { child: const Text('Save'), ); -} - -Widget landmarksWithSteps(LinkedList landmarks) { - List children = []; - int lkey = 0; - for (Landmark landmark in landmarks) { - children.add( - Dismissible( - key: ValueKey(lkey), - child: LandmarkCard(landmark), - // onDismissed: (direction) { - // // Remove the item from the data source. - // setState(() { - // landmarks.remove(landmark); - // }); - // // Then show a snackbar. - // ScaffoldMessenger.of(context) - // .showSnackBar(SnackBar(content: Text("${landmark.name} dismissed"))); - // }, - background: Container(color: Colors.red), - secondaryBackground: Container( - color: Colors.red, - child: Icon( - Icons.delete, - color: Colors.white, - ), - padding: EdgeInsets.all(15), - alignment: Alignment.centerRight, - ), - ) + Widget landmarksWithSteps() { + return ListenableBuilder( + listenable: widget.trip!, + builder: (BuildContext context, Widget? child) { + List children = []; + for (Landmark landmark in widget.trip!.landmarks) { + children.add( + Dismissible( + key: ValueKey(landmark.hashCode), + child: LandmarkCard(landmark), + dismissThresholds: {DismissDirection.endToStart: 0.6}, + onDismissed: (direction) { + // Remove the item from the data source. + log(landmark.name); + setState(() { + widget.trip!.removeLandmark(landmark); + }); + // Then show a snackbar. + ScaffoldMessenger.of(context) + .showSnackBar(SnackBar(content: Text("We won't show ${landmark.name} again"))); + }, + background: Container(color: Colors.red), + secondaryBackground: Container( + color: Colors.red, + child: Icon( + Icons.delete, + color: Colors.white, + ), + padding: EdgeInsets.all(15), + alignment: Alignment.centerRight, + ), + ) + ); + if (landmark.next != null) { + Widget step = stepBetweenLandmarks(landmark, landmark.next!); + children.add(step); + } + } + return Column( + children: children + ); + }, ); - lkey++; - if (landmark.next != null) { - Widget step = stepBetweenLandmarks(landmark); - children.add(step); - } } - - return Column( - children: children - ); } -Widget stepBetweenLandmarks(Landmark landmark) { +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; + // ~/ is integer division (rounding) return Container( margin: EdgeInsets.all(10), padding: EdgeInsets.all(10), @@ -138,7 +144,7 @@ Widget stepBetweenLandmarks(Landmark landmark) { Column( children: [ Icon(Icons.directions_walk), - Text("${landmark.tripTime} min", style: TextStyle(fontSize: 10)), + Text("~$timeRounded min", style: TextStyle(fontSize: 10)), ], ), Spacer(), @@ -146,8 +152,13 @@ Widget stepBetweenLandmarks(Landmark landmark) { onPressed: () { // Open navigation instructions }, - child: Text("Navigate"), - ), + child: Row( + children: [ + Icon(Icons.directions), + Text("Directions"), + ], + ), + ) ], ), ); diff --git a/frontend/lib/modules/map.dart b/frontend/lib/modules/map.dart index 2e95ccd..199388b 100644 --- a/frontend/lib/modules/map.dart +++ b/frontend/lib/modules/map.dart @@ -4,7 +4,8 @@ import 'package:flutter/material.dart'; import 'package:anyway/structs/landmark.dart'; import 'package:anyway/structs/trip.dart'; import 'package:google_maps_flutter/google_maps_flutter.dart'; -import 'package:the_widget_marker/the_widget_marker.dart'; +import 'package:widget_to_marker/widget_to_marker.dart'; + class MapWidget extends StatefulWidget { @@ -25,38 +26,42 @@ class _MapWidgetState extends State { target: LatLng(48.8566, 2.3522), zoom: 11.0, ); - Set markers = {}; - final GlobalKey globalKey = GlobalKey(); + Set mapMarkers = {}; void _onMapCreated(GoogleMapController controller) async { mapController = controller; - List? newLocation = widget.trip?.landmarks.first.location; + List? newLocation = widget.trip?.landmarks.firstOrNull?.location; if (newLocation != null) { CameraUpdate update = CameraUpdate.newLatLng(LatLng(newLocation[0], newLocation[1])); controller.moveCamera(update); } - drawLandmarks(); + // addLandmarkMarker(); } - void _onCameraIdle() { // print(mapController.getLatLng(ScreenCoordinate(x: 0, y: 0))); } - void drawLandmarks() async { - // (re)draws landmarks on the map + void addLandmarkMarker() async { LinkedList? landmarks = widget.trip?.landmarks; - if (landmarks != null){ - for (Landmark landmark in landmarks) { - markers.add(Marker( - markerId: MarkerId(landmark.name), - position: LatLng(landmark.location[0], landmark.location[1]), - // infoWindow: InfoWindow(title: landmark.name, snippet: landmark.type.name), - icon: await MarkerIcon.widgetToIcon(globalKey), - )); - } + 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) + ) + ) + ); setState(() {}); } } @@ -64,39 +69,60 @@ class _MapWidgetState extends State { @override Widget build(BuildContext context) { - return Stack( - children: [ - MyMarker(globalKey), - - GoogleMap( - onMapCreated: _onMapCreated, - initialCameraPosition: _cameraPosition, - onCameraIdle: _onCameraIdle, - // onLongPress: , - markers: markers, - cloudMapId: '41c21ac9b81dbfd8', - ) - ] + return ListenableBuilder( + listenable: widget.trip!, + builder: (context, child) { + addLandmarkMarker(); + return GoogleMap( + onMapCreated: _onMapCreated, + initialCameraPosition: _cameraPosition, + onCameraIdle: _onCameraIdle, + + // onLongPress: , + markers: mapMarkers, + cloudMapId: '41c21ac9b81dbfd8', + ); + } ); } } -class MyMarker extends StatelessWidget { - // declare a global key and get it trough Constructor +class CustomMarker extends StatelessWidget { + final Landmark landmark; + final int position; - MyMarker(this.globalKeyMyWidget); - final GlobalKey globalKeyMyWidget; + CustomMarker({ + super.key, + required this.landmark, + required this.position + }); @override Widget build(BuildContext context) { // 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) { + icon = Icon(Icons.church, color: Colors.black, size: 50); + } else if (landmark.type == park) { + 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) { + icon = Icon(Icons.shopping_cart, color: Colors.black, size: 50); + } else { + icon = Icon(Icons.location_on, color: Colors.black, size: 50); + } + return RepaintBoundary( - key: globalKeyMyWidget, child: Stack( children: [ Container( + // these are not the final sizes, since the final size is set in the toBitmapDescriptor method + // they are useful nevertheless to ensure the scale of the components are correct width: 75, height: 75, decoration: BoxDecoration( @@ -108,7 +134,7 @@ class MyMarker extends StatelessWidget { shape: BoxShape.circle, border: Border.all(color: Colors.black, width: 5), ), - child: Icon(Icons.location_on, color: Colors.black, size: 50), + child: icon, ), Positioned( top: 0, @@ -119,7 +145,7 @@ class MyMarker extends StatelessWidget { color: Theme.of(context).primaryColor, shape: BoxShape.circle, ), - child: Text('1', style: TextStyle(color: Colors.white, fontSize: 20)), + child: Text('$position', style: TextStyle(color: Colors.white, fontSize: 20)), ), ), ], diff --git a/frontend/lib/modules/trips_overview.dart b/frontend/lib/modules/trips_overview.dart index fec7f2a..765ef0e 100644 --- a/frontend/lib/modules/trips_overview.dart +++ b/frontend/lib/modules/trips_overview.dart @@ -25,7 +25,18 @@ class _TripsOverviewState extends State { children = List.generate(snapshot.data!.length, (index) { Trip trip = snapshot.data![index]; return ListTile( - title: Text("Trip to ${trip.cityName}"), + title: FutureBuilder( + future: trip.cityName, + builder: (BuildContext context, AsyncSnapshot snapshot) { + if (snapshot.hasData) { + return Text("Trip to ${snapshot.data}"); + } else if (snapshot.hasError) { + return Text("Error: ${snapshot.error}"); + } else { + return const Text("Trip to ..."); + } + }, + ), leading: Icon(Icons.pin_drop), onTap: () { Navigator.of(context).push( diff --git a/frontend/lib/pages/profile.dart b/frontend/lib/pages/profile.dart index 9371e87..0ee2b8f 100644 --- a/frontend/lib/pages/profile.dart +++ b/frontend/lib/pages/profile.dart @@ -2,6 +2,7 @@ import 'package:anyway/structs/preferences.dart'; import 'package:flutter/material.dart'; +bool debugMode = false; class ProfilePage extends StatefulWidget { @override @@ -12,6 +13,27 @@ class _ProfilePageState extends State { Future _prefs = loadUserPreferences(); + Widget debugButton() { + return Padding( + padding: EdgeInsets.only(top: 20), + child: Row( + children: [ + Text('Debug mode'), + Switch( + value: debugMode, + onChanged: (bool? newValue) { + setState(() { + debugMode = newValue!; + }); + } + ) + ], + ) + ); + } + + + @override Widget build(BuildContext context) { return ListView( @@ -36,7 +58,8 @@ class _ProfilePageState extends State { ), ), - FutureBuilder(future: _prefs, builder: futureSliders) + FutureBuilder(future: _prefs, builder: futureSliders), + debugButton() ] ); } @@ -59,7 +82,6 @@ class _ProfilePageState extends State { } - class PreferenceSliders extends StatefulWidget { final List prefs; diff --git a/frontend/lib/structs/landmark.dart b/frontend/lib/structs/landmark.dart index 9e5e1ef..0f387af 100644 --- a/frontend/lib/structs/landmark.dart +++ b/frontend/lib/structs/landmark.dart @@ -3,6 +3,14 @@ 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'); + + final class Landmark extends LinkedListEntry{ // A linked node of a list of Landmarks final String uuid; @@ -55,11 +63,12 @@ final class Landmark extends LinkedListEntry{ final imageURL = json['image_url'] as String?; final description = json['description'] as String?; var duration = Duration(minutes: json['duration'] ?? 0) as Duration?; - if (duration == const Duration()) {duration = null;}; + // if (duration == const Duration()) {duration = null;}; final visited = json['visited'] as bool?; + var tripTime = Duration(minutes: json['time_to_reach_next'] ?? 0) as Duration?; return Landmark( - uuid: uuid, name: name, location: locationFixed, type: typeFixed, isSecondary: isSecondary, imageURL: imageURL, description: description, duration: duration, visited: visited); + uuid: uuid, name: name, location: locationFixed, type: typeFixed, isSecondary: isSecondary, imageURL: imageURL, description: description, duration: duration, visited: visited, tripTime: tripTime); } else { throw FormatException('Invalid JSON: $json'); } @@ -81,7 +90,8 @@ final class Landmark extends LinkedListEntry{ 'image_url': imageURL, 'description': description, 'duration': duration?.inMinutes, - 'visited': visited + 'visited': visited, + 'trip_time': tripTime?.inMinutes, }; } diff --git a/frontend/lib/structs/linked_landmarks.dart b/frontend/lib/structs/linked_landmarks.dart deleted file mode 100644 index c995ed0..0000000 --- a/frontend/lib/structs/linked_landmarks.dart +++ /dev/null @@ -1,46 +0,0 @@ -// import "package:anyway/structs/landmark.dart"; - -// class Linked { -// Landmark? head; - -// Linked(); - -// // class methods -// bool get isEmpty => head == null; - -// // Add a new node to the end of the list -// void add(Landmark value) { -// if (isEmpty) { -// // If the list is empty, set the new node as the head -// head = value; -// } else { -// Landmark? current = head; -// while (current!.next != null) { -// // Traverse the list to find the last node -// current = current.next; -// } -// current.next = value; // Set the new node as the next node of the last node -// } -// } - -// // Remove the first node with the given value -// void remove(Landmark value) { -// if (isEmpty) return; - -// // If the value is in the head node, update the head to the next node -// if (head! == value) { -// head = head.next; -// return; -// } - -// var current = head; -// while (current!.next != null) { -// if (current.next! == value) { -// // If the value is found in the next node, skip the next node -// current.next = current.next.next; -// return; -// } -// current = current.next; -// } -// } -// } \ No newline at end of file diff --git a/frontend/lib/structs/trip.dart b/frontend/lib/structs/trip.dart index 3b8c1ff..b8176db 100644 --- a/frontend/lib/structs/trip.dart +++ b/frontend/lib/structs/trip.dart @@ -16,11 +16,15 @@ class Trip with ChangeNotifier { // could be empty as well Future get cityName async { + List? location = landmarks.firstOrNull?.location; if (GeocodingPlatform.instance == null) { - return '${landmarks.first.location[0]}, ${landmarks.first.location[1]}'; + return '$location'; + } else if (location == null) { + return 'Unknown'; + } else{ + List placemarks = await placemarkFromCoordinates(location[0], location[1]); + return placemarks.first.locality ?? 'Unknown'; } - List placemarks = await placemarkFromCoordinates(landmarks.first.location[0], landmarks.first.location[1]); - return placemarks.first.locality ?? 'Unknown'; } @@ -56,6 +60,11 @@ class Trip with ChangeNotifier { notifyListeners(); } + void removeLandmark(Landmark landmark) { + landmarks.remove(landmark); + notifyListeners(); + } + factory Trip.fromPrefs(SharedPreferences prefs, String uuid) { String? content = prefs.getString('trip_$uuid'); Map json = jsonDecode(content!); diff --git a/frontend/lib/utils/fetch_trip.dart b/frontend/lib/utils/fetch_trip.dart index 54d9365..cf76d8b 100644 --- a/frontend/lib/utils/fetch_trip.dart +++ b/frontend/lib/utils/fetch_trip.dart @@ -57,6 +57,13 @@ fetchTrip( // only fill in the trip "meta" data for now trip.loadFromJson(json); + + // now fill the trip with landmarks + // if (trip.landmarks.isNotEmpty) { + // trip.landmarks.clear(); + // } + // 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); diff --git a/frontend/pubspec.lock b/frontend/pubspec.lock index a891618..6f808e0 100644 --- a/frontend/pubspec.lock +++ b/frontend/pubspec.lock @@ -1,14 +1,6 @@ # Generated by pub # See https://dart.dev/tools/pub/glossary#lockfile packages: - args: - dependency: transitive - description: - name: args - sha256: "7cf60b9f0cc88203c5a190b4cd62a99feea42759a7fa695010eb5de1c0b2252a" - url: "https://pub.dev" - source: hosted - version: "2.5.0" async: dependency: transitive description: @@ -17,6 +9,14 @@ packages: url: "https://pub.dev" source: hosted version: "2.11.0" + auto_size_text: + dependency: "direct main" + description: + name: auto_size_text + sha256: "3f5261cd3fb5f2a9ab4e2fc3fba84fd9fcaac8821f20a1d4e71f557521b22599" + url: "https://pub.dev" + source: hosted + version: "3.0.0" boolean_selector: dependency: transitive description: @@ -174,14 +174,6 @@ packages: url: "https://pub.dev" source: hosted version: "2.0.21" - flutter_svg: - dependency: transitive - description: - name: flutter_svg - sha256: "7b4ca6cf3304575fe9c8ec64813c8d02ee41d2afe60bcfe0678bcb5375d596a2" - url: "https://pub.dev" - source: hosted - version: "2.0.10+1" flutter_test: dependency: "direct dev" description: flutter @@ -352,6 +344,14 @@ packages: url: "https://pub.dev" source: hosted version: "1.12.0" + nested: + dependency: transitive + description: + name: nested + sha256: "03bac4c528c64c95c722ec99280375a6f2fc708eec17c7b3f07253b626cd2a20" + url: "https://pub.dev" + source: hosted + version: "1.0.0" octo_image: dependency: transitive description: @@ -368,14 +368,6 @@ packages: url: "https://pub.dev" source: hosted version: "1.9.0" - path_parsing: - dependency: transitive - description: - name: path_parsing - sha256: e3e67b1629e6f7e8100b367d3db6ba6af4b1f0bb80f64db18ef1fbabd2fa9ccf - url: "https://pub.dev" - source: hosted - version: "1.0.1" path_provider: dependency: transitive description: @@ -424,14 +416,6 @@ packages: url: "https://pub.dev" source: hosted version: "2.3.0" - petitparser: - dependency: transitive - description: - name: petitparser - sha256: c15605cd28af66339f8eb6fbe0e541bfe2d1b72d5825efc6598f3e0a31b9ad27 - url: "https://pub.dev" - source: hosted - version: "6.0.2" platform: dependency: transitive description: @@ -448,6 +432,14 @@ packages: url: "https://pub.dev" source: hosted version: "2.1.8" + provider: + dependency: "direct main" + description: + name: provider + sha256: c8a055ee5ce3fd98d6fc872478b03823ffdb448699c6ebdbbc71d59b596fd48c + url: "https://pub.dev" + source: hosted + version: "6.1.2" rxdart: dependency: transitive description: @@ -621,14 +613,6 @@ packages: url: "https://pub.dev" source: hosted version: "0.7.0" - the_widget_marker: - dependency: "direct main" - description: - name: the_widget_marker - sha256: "2476ae6b1fe29bbffa3596546871bd26f724c223ea7da74775801d9b70d64811" - url: "https://pub.dev" - source: hosted - version: "1.0.0" typed_data: dependency: transitive description: @@ -645,30 +629,6 @@ packages: url: "https://pub.dev" source: hosted version: "4.4.2" - vector_graphics: - dependency: transitive - description: - name: vector_graphics - sha256: "32c3c684e02f9bc0afb0ae0aa653337a2fe022e8ab064bcd7ffda27a74e288e3" - url: "https://pub.dev" - source: hosted - version: "1.1.11+1" - vector_graphics_codec: - dependency: transitive - description: - name: vector_graphics_codec - sha256: c86987475f162fadff579e7320c7ddda04cd2fdeffbe1129227a85d9ac9e03da - url: "https://pub.dev" - source: hosted - version: "1.1.11+1" - vector_graphics_compiler: - dependency: transitive - description: - name: vector_graphics_compiler - sha256: "12faff3f73b1741a36ca7e31b292ddeb629af819ca9efe9953b70bd63fc8cd81" - url: "https://pub.dev" - source: hosted - version: "1.1.11+1" vector_math: dependency: transitive description: @@ -693,6 +653,14 @@ packages: url: "https://pub.dev" source: hosted version: "0.5.1" + widget_to_marker: + dependency: "direct main" + description: + name: widget_to_marker + sha256: badc36f23c76f3ca9d43d7780058096be774adf0f661bdb6eb6f6b893f648ab9 + url: "https://pub.dev" + source: hosted + version: "1.0.6" xdg_directories: dependency: transitive description: @@ -701,14 +669,6 @@ packages: url: "https://pub.dev" source: hosted version: "1.0.4" - xml: - dependency: transitive - description: - name: xml - sha256: b015a8ad1c488f66851d762d3090a21c600e479dc75e68328c52774040cf9226 - url: "https://pub.dev" - source: hosted - version: "6.5.0" sdks: dart: ">=3.4.0 <4.0.0" flutter: ">=3.22.0" diff --git a/frontend/pubspec.yaml b/frontend/pubspec.yaml index a2f41d4..bb46eb7 100644 --- a/frontend/pubspec.yaml +++ b/frontend/pubspec.yaml @@ -40,9 +40,11 @@ dependencies: shared_preferences: ^2.2.3 dio: ^5.5.0+1 google_maps_flutter: ^2.7.0 - the_widget_marker: ^1.0.0 cached_network_image: ^3.4.0 geocoding: ^3.0.0 + widget_to_marker: ^1.0.6 + provider: ^6.1.2 + auto_size_text: ^3.0.0 dev_dependencies: flutter_test: