ui improvements for trips and landmarks
All checks were successful
Build and push docker image / Build (pull_request) Successful in 1m48s
Build and release APK / Build APK (pull_request) Successful in 4m51s

This commit is contained in:
Remy Moll 2024-08-05 10:18:00 +02:00
parent c87a01b2e8
commit 71d9554d97
12 changed files with 237 additions and 217 deletions

View File

@ -141,7 +141,7 @@ Trip getFirstTrip(Future<List<Trip>> trips) {
uuid: '1', uuid: '1',
name: "Eiffel Tower", name: "Eiffel Tower",
location: [48.859, 2.295], 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" 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<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: 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" 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<List<Trip>> trips) {
uuid: "3", uuid: "3",
name: "Louvre palace", name: "Louvre palace",
location: [48.8606, 2.3376], 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" 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<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: 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" 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<List<Trip>> trips) {
uuid: "5", uuid: "5",
name: "Panthéon", name: "Panthéon",
location: [48.847, 2.347], 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" imageURL: "https://upload.wikimedia.org/wikipedia/commons/thumb/8/80/Pantheon_of_Paris_007.JPG/1280px-Pantheon_of_Paris_007.JPG"
), ),
); );

View File

@ -1,4 +1,5 @@
import 'package:anyway/structs/trip.dart'; import 'package:anyway/structs/trip.dart';
import 'package:auto_size_text/auto_size_text.dart';
import 'package:flutter/material.dart'; import 'package:flutter/material.dart';
@ -24,14 +25,21 @@ class _GreeterState extends State<Greeter> {
future: widget.trip.cityName, future: widget.trip.cityName,
builder: (BuildContext context, AsyncSnapshot<String> snapshot) { builder: (BuildContext context, AsyncSnapshot<String> snapshot) {
if (snapshot.hasData) { if (snapshot.hasData) {
return Text( return AutoSizeText(
maxLines: 1,
'Welcome to ${snapshot.data}!', 'Welcome to ${snapshot.data}!',
style: TextStyle(color: theme.primaryColor, fontWeight: FontWeight.bold, fontSize: 24), style: TextStyle(color: theme.primaryColor, fontWeight: FontWeight.bold, fontSize: 24),
); );
} else if (snapshot.hasError) { } else if (snapshot.hasError) {
return const Text('Welcome to your trip!'); return const AutoSizeText(
maxLines: 1,
'Welcome to your trip!'
);
} else { } else {
return const Text('Welcome to ...'); return const AutoSizeText(
maxLines: 1,
'Welcome to ...'
);
} }
} }
); );

View File

@ -51,7 +51,7 @@ class _LandmarksOverviewState extends State<LandmarksOverview> {
]; ];
} else { } else {
children = [ children = [
landmarksWithSteps(trip.landmarks), landmarksWithSteps(),
saveButton(), saveButton(),
]; ];
} }
@ -71,25 +71,27 @@ class _LandmarksOverviewState extends State<LandmarksOverview> {
child: const Text('Save'), child: const Text('Save'),
); );
} Widget landmarksWithSteps() {
return ListenableBuilder(
Widget landmarksWithSteps(LinkedList<Landmark> landmarks) { listenable: widget.trip!,
builder: (BuildContext context, Widget? child) {
List<Widget> children = []; List<Widget> children = [];
int lkey = 0; for (Landmark landmark in widget.trip!.landmarks) {
for (Landmark landmark in landmarks) {
children.add( children.add(
Dismissible( Dismissible(
key: ValueKey<int>(lkey), key: ValueKey<int>(landmark.hashCode),
child: LandmarkCard(landmark), child: LandmarkCard(landmark),
// onDismissed: (direction) { dismissThresholds: {DismissDirection.endToStart: 0.6},
// // Remove the item from the data source. onDismissed: (direction) {
// setState(() { // Remove the item from the data source.
// landmarks.remove(landmark); log(landmark.name);
// }); setState(() {
// // Then show a snackbar. widget.trip!.removeLandmark(landmark);
// ScaffoldMessenger.of(context) });
// .showSnackBar(SnackBar(content: Text("${landmark.name} dismissed"))); // Then show a snackbar.
// }, ScaffoldMessenger.of(context)
.showSnackBar(SnackBar(content: Text("We won't show ${landmark.name} again")));
},
background: Container(color: Colors.red), background: Container(color: Colors.red),
secondaryBackground: Container( secondaryBackground: Container(
color: Colors.red, color: Colors.red,
@ -102,24 +104,28 @@ Widget landmarksWithSteps(LinkedList<Landmark> landmarks) {
), ),
) )
); );
lkey++;
if (landmark.next != null) { if (landmark.next != null) {
Widget step = stepBetweenLandmarks(landmark); Widget step = stepBetweenLandmarks(landmark, landmark.next!);
children.add(step); children.add(step);
} }
} }
return Column( return Column(
children: children children: children
); );
},
);
}
} }
Widget stepBetweenLandmarks(Landmark landmark) { Widget stepBetweenLandmarks(Landmark current, Landmark next) {
// This is a simple widget that draws a line between landmark-cards // This is a simple widget that draws a line between landmark-cards
// It's a vertical dotted line // 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 // 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 // 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( return Container(
margin: EdgeInsets.all(10), margin: EdgeInsets.all(10),
padding: EdgeInsets.all(10), padding: EdgeInsets.all(10),
@ -138,7 +144,7 @@ Widget stepBetweenLandmarks(Landmark landmark) {
Column( Column(
children: [ children: [
Icon(Icons.directions_walk), Icon(Icons.directions_walk),
Text("${landmark.tripTime} min", style: TextStyle(fontSize: 10)), Text("~$timeRounded min", style: TextStyle(fontSize: 10)),
], ],
), ),
Spacer(), Spacer(),
@ -146,8 +152,13 @@ Widget stepBetweenLandmarks(Landmark landmark) {
onPressed: () { onPressed: () {
// Open navigation instructions // Open navigation instructions
}, },
child: Text("Navigate"), child: Row(
children: [
Icon(Icons.directions),
Text("Directions"),
],
), ),
)
], ],
), ),
); );

View File

@ -4,7 +4,8 @@ import 'package:flutter/material.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:google_maps_flutter/google_maps_flutter.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 { class MapWidget extends StatefulWidget {
@ -25,38 +26,42 @@ class _MapWidgetState extends State<MapWidget> {
target: LatLng(48.8566, 2.3522), target: LatLng(48.8566, 2.3522),
zoom: 11.0, zoom: 11.0,
); );
Set<Marker> markers = <Marker>{}; Set<Marker> mapMarkers = <Marker>{};
final GlobalKey globalKey = GlobalKey();
void _onMapCreated(GoogleMapController controller) async { void _onMapCreated(GoogleMapController controller) async {
mapController = controller; mapController = controller;
List<double>? newLocation = widget.trip?.landmarks.first.location; List<double>? newLocation = widget.trip?.landmarks.firstOrNull?.location;
if (newLocation != null) { if (newLocation != null) {
CameraUpdate update = CameraUpdate.newLatLng(LatLng(newLocation[0], newLocation[1])); CameraUpdate update = CameraUpdate.newLatLng(LatLng(newLocation[0], newLocation[1]));
controller.moveCamera(update); controller.moveCamera(update);
} }
drawLandmarks(); // addLandmarkMarker();
} }
void _onCameraIdle() { void _onCameraIdle() {
// print(mapController.getLatLng(ScreenCoordinate(x: 0, y: 0))); // print(mapController.getLatLng(ScreenCoordinate(x: 0, y: 0)));
} }
void drawLandmarks() async { void addLandmarkMarker() async {
// (re)draws landmarks on the map
LinkedList<Landmark>? landmarks = widget.trip?.landmarks; LinkedList<Landmark>? landmarks = widget.trip?.landmarks;
if (landmarks != null){ int i = mapMarkers.length;
for (Landmark landmark in landmarks) { Landmark? current = landmarks!.elementAtOrNull(i);
markers.add(Marker( if (current != null){
markerId: MarkerId(landmark.name), mapMarkers.add(
position: LatLng(landmark.location[0], landmark.location[1]), Marker(
// infoWindow: InfoWindow(title: landmark.name, snippet: landmark.type.name), markerId: MarkerId(current.name),
icon: await MarkerIcon.widgetToIcon(globalKey), 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(() {}); setState(() {});
} }
} }
@ -64,39 +69,60 @@ class _MapWidgetState extends State<MapWidget> {
@override @override
Widget build(BuildContext context) { Widget build(BuildContext context) {
return Stack( return ListenableBuilder(
children: [ listenable: widget.trip!,
MyMarker(globalKey), builder: (context, child) {
addLandmarkMarker();
GoogleMap( return GoogleMap(
onMapCreated: _onMapCreated, onMapCreated: _onMapCreated,
initialCameraPosition: _cameraPosition, initialCameraPosition: _cameraPosition,
onCameraIdle: _onCameraIdle, onCameraIdle: _onCameraIdle,
// onLongPress: , // onLongPress: ,
markers: markers, markers: mapMarkers,
cloudMapId: '41c21ac9b81dbfd8', cloudMapId: '41c21ac9b81dbfd8',
) );
] }
); );
} }
} }
class MyMarker extends StatelessWidget { class CustomMarker extends StatelessWidget {
// declare a global key and get it trough Constructor final Landmark landmark;
final int position;
MyMarker(this.globalKeyMyWidget); CustomMarker({
final GlobalKey globalKeyMyWidget; super.key,
required this.landmark,
required this.position
});
@override @override
Widget build(BuildContext context) { Widget build(BuildContext context) {
// 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;
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( return RepaintBoundary(
key: globalKeyMyWidget,
child: Stack( child: Stack(
children: [ children: [
Container( 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, width: 75,
height: 75, height: 75,
decoration: BoxDecoration( decoration: BoxDecoration(
@ -108,7 +134,7 @@ class MyMarker extends StatelessWidget {
shape: BoxShape.circle, shape: BoxShape.circle,
border: Border.all(color: Colors.black, width: 5), border: Border.all(color: Colors.black, width: 5),
), ),
child: Icon(Icons.location_on, color: Colors.black, size: 50), child: icon,
), ),
Positioned( Positioned(
top: 0, top: 0,
@ -119,7 +145,7 @@ class MyMarker extends StatelessWidget {
color: Theme.of(context).primaryColor, color: Theme.of(context).primaryColor,
shape: BoxShape.circle, shape: BoxShape.circle,
), ),
child: Text('1', style: TextStyle(color: Colors.white, fontSize: 20)), child: Text('$position', style: TextStyle(color: Colors.white, fontSize: 20)),
), ),
), ),
], ],

View File

@ -25,7 +25,18 @@ class _TripsOverviewState extends State<TripsOverview> {
children = List<Widget>.generate(snapshot.data!.length, (index) { children = List<Widget>.generate(snapshot.data!.length, (index) {
Trip trip = snapshot.data![index]; Trip trip = snapshot.data![index];
return ListTile( return ListTile(
title: Text("Trip to ${trip.cityName}"), title: FutureBuilder(
future: trip.cityName,
builder: (BuildContext context, AsyncSnapshot<String> 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), leading: Icon(Icons.pin_drop),
onTap: () { onTap: () {
Navigator.of(context).push( Navigator.of(context).push(

View File

@ -2,6 +2,7 @@ import 'package:anyway/structs/preferences.dart';
import 'package:flutter/material.dart'; import 'package:flutter/material.dart';
bool debugMode = false;
class ProfilePage extends StatefulWidget { class ProfilePage extends StatefulWidget {
@override @override
@ -12,6 +13,27 @@ class _ProfilePageState extends State<ProfilePage> {
Future<UserPreferences> _prefs = loadUserPreferences(); Future<UserPreferences> _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 @override
Widget build(BuildContext context) { Widget build(BuildContext context) {
return ListView( return ListView(
@ -36,7 +58,8 @@ class _ProfilePageState extends State<ProfilePage> {
), ),
), ),
FutureBuilder(future: _prefs, builder: futureSliders) FutureBuilder(future: _prefs, builder: futureSliders),
debugButton()
] ]
); );
} }
@ -59,7 +82,6 @@ class _ProfilePageState extends State<ProfilePage> {
} }
class PreferenceSliders extends StatefulWidget { class PreferenceSliders extends StatefulWidget {
final List<SinglePreference> prefs; final List<SinglePreference> prefs;

View File

@ -3,6 +3,14 @@ import 'dart:convert';
import 'package:shared_preferences/shared_preferences.dart'; 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<Landmark>{ final class Landmark extends LinkedListEntry<Landmark>{
// A linked node of a list of Landmarks // A linked node of a list of Landmarks
final String uuid; final String uuid;
@ -55,11 +63,12 @@ final class Landmark extends LinkedListEntry<Landmark>{
final imageURL = json['image_url'] as String?; final imageURL = json['image_url'] as String?;
final description = json['description'] as String?; final description = json['description'] as String?;
var duration = Duration(minutes: json['duration'] ?? 0) as Duration?; 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?; final visited = json['visited'] as bool?;
var tripTime = Duration(minutes: json['time_to_reach_next'] ?? 0) as Duration?;
return Landmark( 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 { } else {
throw FormatException('Invalid JSON: $json'); throw FormatException('Invalid JSON: $json');
} }
@ -81,7 +90,8 @@ final class Landmark extends LinkedListEntry<Landmark>{
'image_url': imageURL, 'image_url': imageURL,
'description': description, 'description': description,
'duration': duration?.inMinutes, 'duration': duration?.inMinutes,
'visited': visited 'visited': visited,
'trip_time': tripTime?.inMinutes,
}; };
} }

View File

@ -1,46 +0,0 @@
// import "package:anyway/structs/landmark.dart";
// class Linked<Landmark> {
// 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;
// }
// }
// }

View File

@ -16,12 +16,16 @@ class Trip with ChangeNotifier {
// could be empty as well // could be empty as well
Future<String> get cityName async { Future<String> get cityName async {
List<double>? location = landmarks.firstOrNull?.location;
if (GeocodingPlatform.instance == null) { if (GeocodingPlatform.instance == null) {
return '${landmarks.first.location[0]}, ${landmarks.first.location[1]}'; return '$location';
} } else if (location == null) {
List<Placemark> placemarks = await placemarkFromCoordinates(landmarks.first.location[0], landmarks.first.location[1]); return 'Unknown';
} else{
List<Placemark> placemarks = await placemarkFromCoordinates(location[0], location[1]);
return placemarks.first.locality ?? 'Unknown'; return placemarks.first.locality ?? 'Unknown';
} }
}
Trip({ Trip({
@ -56,6 +60,11 @@ class Trip with ChangeNotifier {
notifyListeners(); notifyListeners();
} }
void removeLandmark(Landmark landmark) {
landmarks.remove(landmark);
notifyListeners();
}
factory Trip.fromPrefs(SharedPreferences prefs, String uuid) { factory Trip.fromPrefs(SharedPreferences prefs, String uuid) {
String? content = prefs.getString('trip_$uuid'); String? content = prefs.getString('trip_$uuid');
Map<String, dynamic> json = jsonDecode(content!); Map<String, dynamic> json = jsonDecode(content!);

View File

@ -57,6 +57,13 @@ fetchTrip(
// only fill in the trip "meta" data for now // only fill in the trip "meta" data for now
trip.loadFromJson(json); 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"]; String? nextUUID = json["first_landmark_uuid"];
while (nextUUID != null) { while (nextUUID != null) {
var (landmark, newUUID) = await fetchLandmark(nextUUID); var (landmark, newUUID) = await fetchLandmark(nextUUID);

View File

@ -1,14 +1,6 @@
# Generated by pub # Generated by pub
# See https://dart.dev/tools/pub/glossary#lockfile # See https://dart.dev/tools/pub/glossary#lockfile
packages: packages:
args:
dependency: transitive
description:
name: args
sha256: "7cf60b9f0cc88203c5a190b4cd62a99feea42759a7fa695010eb5de1c0b2252a"
url: "https://pub.dev"
source: hosted
version: "2.5.0"
async: async:
dependency: transitive dependency: transitive
description: description:
@ -17,6 +9,14 @@ packages:
url: "https://pub.dev" url: "https://pub.dev"
source: hosted source: hosted
version: "2.11.0" 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: boolean_selector:
dependency: transitive dependency: transitive
description: description:
@ -174,14 +174,6 @@ packages:
url: "https://pub.dev" url: "https://pub.dev"
source: hosted source: hosted
version: "2.0.21" 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: flutter_test:
dependency: "direct dev" dependency: "direct dev"
description: flutter description: flutter
@ -352,6 +344,14 @@ packages:
url: "https://pub.dev" url: "https://pub.dev"
source: hosted source: hosted
version: "1.12.0" version: "1.12.0"
nested:
dependency: transitive
description:
name: nested
sha256: "03bac4c528c64c95c722ec99280375a6f2fc708eec17c7b3f07253b626cd2a20"
url: "https://pub.dev"
source: hosted
version: "1.0.0"
octo_image: octo_image:
dependency: transitive dependency: transitive
description: description:
@ -368,14 +368,6 @@ packages:
url: "https://pub.dev" url: "https://pub.dev"
source: hosted source: hosted
version: "1.9.0" 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: path_provider:
dependency: transitive dependency: transitive
description: description:
@ -424,14 +416,6 @@ packages:
url: "https://pub.dev" url: "https://pub.dev"
source: hosted source: hosted
version: "2.3.0" version: "2.3.0"
petitparser:
dependency: transitive
description:
name: petitparser
sha256: c15605cd28af66339f8eb6fbe0e541bfe2d1b72d5825efc6598f3e0a31b9ad27
url: "https://pub.dev"
source: hosted
version: "6.0.2"
platform: platform:
dependency: transitive dependency: transitive
description: description:
@ -448,6 +432,14 @@ packages:
url: "https://pub.dev" url: "https://pub.dev"
source: hosted source: hosted
version: "2.1.8" version: "2.1.8"
provider:
dependency: "direct main"
description:
name: provider
sha256: c8a055ee5ce3fd98d6fc872478b03823ffdb448699c6ebdbbc71d59b596fd48c
url: "https://pub.dev"
source: hosted
version: "6.1.2"
rxdart: rxdart:
dependency: transitive dependency: transitive
description: description:
@ -621,14 +613,6 @@ packages:
url: "https://pub.dev" url: "https://pub.dev"
source: hosted source: hosted
version: "0.7.0" 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: typed_data:
dependency: transitive dependency: transitive
description: description:
@ -645,30 +629,6 @@ packages:
url: "https://pub.dev" url: "https://pub.dev"
source: hosted source: hosted
version: "4.4.2" 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: vector_math:
dependency: transitive dependency: transitive
description: description:
@ -693,6 +653,14 @@ packages:
url: "https://pub.dev" url: "https://pub.dev"
source: hosted source: hosted
version: "0.5.1" 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: xdg_directories:
dependency: transitive dependency: transitive
description: description:
@ -701,14 +669,6 @@ packages:
url: "https://pub.dev" url: "https://pub.dev"
source: hosted source: hosted
version: "1.0.4" version: "1.0.4"
xml:
dependency: transitive
description:
name: xml
sha256: b015a8ad1c488f66851d762d3090a21c600e479dc75e68328c52774040cf9226
url: "https://pub.dev"
source: hosted
version: "6.5.0"
sdks: sdks:
dart: ">=3.4.0 <4.0.0" dart: ">=3.4.0 <4.0.0"
flutter: ">=3.22.0" flutter: ">=3.22.0"

View File

@ -40,9 +40,11 @@ dependencies:
shared_preferences: ^2.2.3 shared_preferences: ^2.2.3
dio: ^5.5.0+1 dio: ^5.5.0+1
google_maps_flutter: ^2.7.0 google_maps_flutter: ^2.7.0
the_widget_marker: ^1.0.0
cached_network_image: ^3.4.0 cached_network_image: ^3.4.0
geocoding: ^3.0.0 geocoding: ^3.0.0
widget_to_marker: ^1.0.6
provider: ^6.1.2
auto_size_text: ^3.0.0
dev_dependencies: dev_dependencies:
flutter_test: flutter_test: