I am not sure if this is possible to do or not but I am trying to figure out how to update markers on camera movement, device movement which i am using the centerLongitude and centerLongitude for or data change, is this possible with the current structure of my app? I have tried to add a listener for my locations document in firebase but it didn't work.
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 = {};
// ignore: unused_field
List<LocationsRecord> _list = [];
// ignore: unused_field
StreamSubscription? _locationsSubscription;
late google_maps_flutter.LatLng _center;
@override
void initState() {
super.initState();
_center = google_maps_flutter.LatLng(
widget.centerLatitude, widget.centerLongitude);
_loadMarkerIcons().then((_) {
_listenToLocations();
});
}
void _listenToLocations() {
_locationsSubscription = FirebaseFirestore.instance
.collection('locations')
.snapshots()
.listen((snapshot) {
final locations = snapshot.docs
.map((doc) => LocationsRecord.fromSnapshot(doc))
.toList();
setState(() {
_list = locations;
// Removed the call to _loadMarkerIcons()
});
});
}
Future<void> _loadMarkerIcons() async {
Set<String> uniqueIconPaths =
widget.places?.map((data) => data.coverImage).toSet() ?? {};
for (String urlString in uniqueIconPaths) {
if (urlString.isNotEmpty) {
// Fetch the bytes from the network URL using http package
final response = await http.get(Uri.parse(urlString));
if (response.statusCode == 200) {
// Decode the image from the bytes
img.Image? image = img.decodeImage(response.bodyBytes);
if (image != null) {
// Resize the image
img.Image thumbnail =
img.copyResize(image, width: 30); // Set the desired size
// Create the BitmapDescriptor from resized bytes
final descriptor = google_maps_flutter.BitmapDescriptor.fromBytes(
img.encodePng(thumbnail),
);
// Store the descriptor with the URL as the key for later use with markers
_customIcons[urlString] = descriptor;
} else {
print('Failed to decode image at $urlString.');
}
} else {
// Handle the case when the image is not retrieved from the network
print(
'Failed to load image at $urlString, status code: ${response.statusCode}');
}
}
}
_updateMarkers(); // Update markers once icons are loaded
}
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,
);
}
}
I have tried to use different scenarios but all result in the app crashing.