Hello to all the Flutter community! I am about to finish an app, but I have this issue that I cannot solve, I looked online for correct implementation of what I'm trying to achieve without luck.
As you can see in the next image when the user opens this page see a map with the original red marker for the user location and then the markers of the shops.
In order to show this, I create a future builder who first checks the location of the user and then makes an API call who retrieves the shops surrounding the user.
Also, the user can select categories, but this is not important for the problem.
All that I describe before works fine, but my client ask that if the user moves the map, the location of the user should update (considering the new user location as the center of the map) and make the API call again to update the shops surrounding.
import 'package:app_pickolos/generated/l10n.dart';
import 'package:app_pickolos/src/providers/categories_list_provider.dart';
import 'package:flutter/material.dart';
import 'package:google_maps_flutter/google_maps_flutter.dart';
import 'package:geolocator/geolocator.dart';
import 'package:provider/provider.dart';
import '../styles.dart';
import 'widgets/background_gradient.dart';
class SearchMap extends StatelessWidget {
@override
Widget build(BuildContext context) {
var colorValue = Theme.of(context).primaryColorLight;
Locale myLocale = Localizations.localeOf(context);
CategoriesListProvider categoriesListProvider =
Provider.of<CategoriesListProvider>(context);
LatLng _locationSelected;
LatLng _lastMapPosition;
Future _getUserLocation(locationSelected) async {
Position position = await Geolocator()
.getCurrentPosition(desiredAccuracy: LocationAccuracy.high);
if (locationSelected == null) {
categoriesListProvider.userPositionLon = position.longitude;
categoriesListProvider.userPositionLat = position.latitude;
await categoriesListProvider.getMapMarkers(
context: context,
lat: position.latitude,
lon: position.longitude,
);
} else {
categoriesListProvider.userPositionLon = locationSelected.longitude;
categoriesListProvider.userPositionLat = locationSelected.latitude;
await categoriesListProvider.getMapMarkers(
context: context,
lat: locationSelected.latitude,
lon: locationSelected.longitude,
);
}
}
void _onCameraMove(CameraPosition position) {
_lastMapPosition = (position.target);
categoriesListProvider.userPositionLon = position.target.longitude;
categoriesListProvider.userPositionLat = position.target.latitude;
}
void _onCameraIdle() {
if (_lastMapPosition != _locationSelected) {
_getUserLocation(_locationSelected);
_locationSelected = _lastMapPosition;
}
}
return Scaffold(
appBar: AppBar(
title: Text(AppLocalizations.of(context).mapTitle),
),
body: Container(
decoration: buildBackgroundGradient(context),
child: Column(
mainAxisAlignment: MainAxisAlignment.start,
mainAxisSize: MainAxisSize.min,
children: [
DropDownSelect(
categoriesListProvider: categoriesListProvider,
myLocale: myLocale),
SizedBox(
height: 20,
),
FutureBuilder(
future: _getUserLocation(_locationSelected),
builder: (
context,
snapshot,
) {
switch (snapshot.connectionState) {
case ConnectionState.none:
return Text(AppLocalizations.of(context).errorNoConection);
case ConnectionState.waiting:
return Container(
height: 320,
child: Center(
child: CircularProgressIndicator(
valueColor:
AlwaysStoppedAnimation<Color>(colorValue)),
),
);
case ConnectionState.active:
return Container(
height: 320,
child: Center(
child: CircularProgressIndicator(
valueColor:
AlwaysStoppedAnimation<Color>(colorValue)),
),
);
case ConnectionState.done:
if (snapshot.hasError) {
return Text(
'${snapshot.error}',
style: TextStyle(color: Colors.red),
);
} else {
return Container(
width: MediaQuery.of(context).size.width * 0.8,
height: 320,
margin: EdgeInsets.symmetric(horizontal: 16.0),
child: ClipRRect(
borderRadius: borderRadiusPickolos(),
child: Stack(
children: [
GoogleMap(
onCameraMove: _onCameraMove,
onCameraIdle: _onCameraIdle,
mapType: MapType.normal,
initialCameraPosition: CameraPosition(
target: LatLng(
categoriesListProvider.userPositionLat,
categoriesListProvider.userPositionLon),
zoom: 14,
),
markers: Set<Marker>.of(
categoriesListProvider.markersList),
),
],
),
),
);
}
}
return Container(
height: 320,
child: Center(
child: CircularProgressIndicator(
valueColor: AlwaysStoppedAnimation<Color>(colorValue)),
),
);
},
),
Expanded(child: Container()),
Container(
width: 60,
height: 60,
decoration: BoxDecoration(
shape: BoxShape.circle,
color: Colors.white38,
),
child: IconButton(
icon: Icon(
Icons.close,
size: 40,
),
onPressed: () {
Navigator.popAndPushNamed(context, 'home');
},
),
),
SizedBox(
height: 40,
),
],
),
),
);
}
}
class DropDownSelect extends StatelessWidget {
***Not important
}
Future getMapMarkers({context, double lat, double lon}) async {
final Map<String, String> headers = {
'Api-Token': _apitoken,
'Session-Token': _prefs.sessionId,
'Content-Type': 'application/json'
};
var body = {
"longitude": lon,
"latitude": lat,
"maxDistance": 10000,
};
final url =
'XXXXXXXm/api/v1/businesses/by-location';
url,
body: json.encode(body),
headers: headers,
);
final mapBusinessListModel = mapBusinessListFromJson(response.body);
final bitmapIcon = await BitmapDescriptor.fromAssetImage(
ImageConfiguration(size: Size(48, 48)), 'assets/map_icon.png');
_markers = mapBusinessListModel
.map(
(mapBusinessListModel) => Marker(
markerId: MarkerId(mapBusinessListModel.id),
position: LatLng(
mapBusinessListModel.location.latitude,
mapBusinessListModel.location.longitude,
),
icon: bitmapIcon,
infoWindow: InfoWindow(
snippet: AppLocalizations.of(context).tapToView,
onTap: () {
Provider.of<UserProvider>(context, listen: false)
.setBusinessDetailID = mapBusinessListModel.id;
Navigator.pushNamed(context, 'businessPreview');
print('tap sobre icono mapa');
},
title: mapBusinessListModel.name,
),
),
)
.toList();
_markers.add(Marker(
markerId: MarkerId('user'),
position: LatLng(lat, lon),
));
//notifyListeners();
print('agrgegue a marker list ${_markers.toString()}');
}