I have been trying to figure out what is wrong with the following code as it has no errors... I am trying to pull from a firestore collection which contains String fields that have the url to the firebase storage asset. When I compile and run everything is working as expected apart from the markers, they are defaulting to the default marker and the only reason that would happen is if it's getting a return null from the firestore field right? Anyways any help would be greatly appreciated.
flutter[tag:google Maps]
- I have tried the util and pulling from local assets and it doesn't work either.
- I have tried to rewrite the code different ways and simplifying it to only pull one url.
- Even tried ai but i still have the same results but with more errors instead of none..
as google_maps_flutter;
import '/flutter_flow/lat_lng.dart' as latlng;
import 'dart:async';
export 'dart:async' show Completer;
export 'package:google_maps_flutter/google_maps_flutter.dart' hide LatLng;
export '/flutter_flow/lat_lng.dart' show LatLng;
import 'package:google_maps_flutter_platform_interface/google_maps_flutter_platform_interface.dart';
import 'dart:ui';
import 'package:cloud_firestore/cloud_firestore.dart';
import 'dart:typed_data';
class FirestoreMap extends StatefulWidget {
const FirestoreMap({
super.key,
this.width,
this.height,
this.places,
required this.centerLatitude,
required this.centerLongitude,
required this.showLocation,
required this.showCompass,
required this.showMapToolbar,
required this.showTraffic,
required this.allowZoom,
required this.showZoomControls,
required this.defaultZoom,
this.mapStyleJson,
this.onClickMarker,
});
final double? width;
final double? height;
final List<LocationsRecord>? places;
final double centerLatitude;
final double centerLongitude;
final bool showLocation;
final bool showCompass;
final bool showMapToolbar;
final bool showTraffic;
final bool allowZoom;
final bool showZoomControls;
final double defaultZoom;
final Future Function(LocationsRecord? placeRow)? onClickMarker;
final String? mapStyleJson;
@override
State<FirestoreMap> createState() => _FirestoreMapState();
}
class _FirestoreMapState extends State<FirestoreMap> {
Completer<google_maps_flutter.GoogleMapController> _controller = Completer();
Map<String, google_maps_flutter.BitmapDescriptor> _customIcons = {};
Set<google_maps_flutter.Marker> _markers = {};
List<LocationsRecord> _currentPlaces = [];
StreamSubscription? _locationsSubscription;
late google_maps_flutter.LatLng _center;
@override
void initState() {
super.initState();
_center = google_maps_flutter.LatLng(
widget.centerLatitude, widget.centerLongitude);
_listenToLocations();
}
void _listenToLocations() {
_locationsSubscription = FirebaseFirestore.instance
.collection('locations')
.snapshots()
.listen((snapshot) {
final locations = snapshot.docs
.map((doc) => LocationsRecord.fromSnapshot(doc))
.toList();
setState(() {
_currentPlaces = locations;
_loadMarkerIcons(); // Ensure this uses _currentPlaces
});
});
}
// Be sure to cancel the subscription when the widget is disposed
@override
void dispose() {
_locationsSubscription?.cancel(); // Cancel the Firestore subscription
super.dispose();
}
Future<void> _loadMarkerIcons() async {
// First, ensure we're working with the current list of places.
final uniqueIconPaths = _currentPlaces
.map((place) =>
place.coverImage) // Use _currentPlaces instead of widget.places
.where((image) => image.isNotEmpty)
.toSet();
// Initialize an empty map to store the future tasks of loading icons.
final Map<String, Future<google_maps_flutter.BitmapDescriptor>>
iconLoadTasks = {};
// Iterate over uniqueIconPaths and initiate loading for each icon.
for (var path in uniqueIconPaths) {
if (path.isNotEmpty) {
// For network images
iconLoadTasks[path] = loadNetworkImage(path).then((imageData) =>
google_maps_flutter.BitmapDescriptor.fromBytes(imageData));
} else {
// For asset images
iconLoadTasks[path] =
google_maps_flutter.BitmapDescriptor.fromAssetImage(
const ImageConfiguration(devicePixelRatio: 2.5),
"assets/images/$path",
);
}
}
// Await all load tasks and update _customIcons map.
final icons = await Future.wait(iconLoadTasks.values);
final paths = iconLoadTasks.keys.toList();
// Assign loaded icons to the _customIcons map.
for (int i = 0; i < paths.length; i++) {
_customIcons[paths[i]] = icons[i];
}
// With icons loaded, update the markers.
_updateMarkers();
}
Future<Uint8List> loadNetworkImage(String imageUrl) async {
final ImageStream stream =
NetworkImage(imageUrl).resolve(ImageConfiguration());
final Completer<Uint8List> completer = Completer();
void listener(ImageInfo info, bool _) async {
// Made the listener asynchronous
final ByteData? byteData = await info.image
.toByteData(format: ImageByteFormat.png); // Awaiting the ByteData
if (byteData != null) {
completer.complete(byteData.buffer.asUint8List());
} else {
completer.completeError(Exception('Failed to obtain image bytes.'));
}
// Remove the listener once the image data is received or failed to fetch.
stream.removeListener(ImageStreamListener(listener));
}
// Adding the listener
stream.addListener(ImageStreamListener(listener));
// Waiting for the completer to finish.
return completer.future;
}
void _updateMarkers() {
setState(() {
_markers = _createMarkers();
});
}
void _onMapCreated(google_maps_flutter.GoogleMapController controller) {
_controller.complete(controller);
if (widget.mapStyleJson != null) {
// Apply the map style if provided
controller.setMapStyle(widget.mapStyleJson);
}
}
Set<google_maps_flutter.Marker> _createMarkers() {
var tmp = <google_maps_flutter.Marker>{};
for (int i = 0; i < (widget.places ?? []).length; i++) {
var place = widget.places?[i];
final latlng.LatLng coordinates = latlng.LatLng(
place?.tempAddress?.latitude ?? 0.0,
place?.tempAddress?.longitude ?? 0.0);
final google_maps_flutter.LatLng googleMapsLatLng =
google_maps_flutter.LatLng(
coordinates.latitude, coordinates.longitude);
google_maps_flutter.BitmapDescriptor icon =
_customIcons[place?.coverImage] ??
google_maps_flutter.BitmapDescriptor.defaultMarker;
final google_maps_flutter.Marker marker = google_maps_flutter.Marker(
markerId: google_maps_flutter.MarkerId('${place?.name ?? "Marker"}_$i'),
position: googleMapsLatLng,
icon: icon,
infoWindow: google_maps_flutter.InfoWindow(
title: place?.name, snippet: place?.description),
onTap: () async {
// Animate camera to the marker's position when tapped
final google_maps_flutter.GoogleMapController controller =
await _controller.future;
controller
.animateCamera(google_maps_flutter.CameraUpdate.newCameraPosition(
google_maps_flutter.CameraPosition(
target: googleMapsLatLng,
zoom: 15.0, // Adjust zoom level as needed
),
));
// Execute additional callback if provided
final callback = widget.onClickMarker;
if (callback != null) {
await callback(place);
}
},
);
tmp.add(marker);
}
return tmp;
}
@override
Widget build(BuildContext context) {
return google_maps_flutter.GoogleMap(
onMapCreated: _onMapCreated,
onCameraMove: (cameraPosition) {
// This callback is triggered on every camera move
// If you need to update the map based on camera movement, add your logic here
},
onCameraIdle: () {
// This callback is triggered when the camera stops moving
// You can fetch and update locations here if necessary
},
zoomGesturesEnabled: widget.allowZoom,
zoomControlsEnabled: widget.showZoomControls,
myLocationEnabled: widget.showLocation,
myLocationButtonEnabled: true,
compassEnabled: widget.showCompass,
mapToolbarEnabled: widget.showMapToolbar,
mapType: google_maps_flutter.MapType.normal,
trafficEnabled: widget.showTraffic,
initialCameraPosition: google_maps_flutter.CameraPosition(
target: _center,
zoom: widget.defaultZoom,
),
markers: _markers,
);
}
}````