I am currently making a maps page and I need to get the user's current location and pass it into google maps. I am using GetX. However I am currently getting an error about type 'Future<dynamic>' is not a subtype of type 'LatLng' and I do not know what to do to fix this. Essentially I just want to get the user's location and pass it in to a GoogleMap as initial camera position.
Here is my controller:
class LocationController extends GetxController {
static LocationController instance = Get.find();
#override
void onReady() {
super.onReady();
getlocation();
}
getlocation() async {
bool serviceEnabled;
LocationPermission permission;
serviceEnabled = await Geolocator.isLocationServiceEnabled();
if (!serviceEnabled) {
await Geolocator.openLocationSettings();
return Future.error("location service is not enabled");
}
permission = await Geolocator.checkPermission();
if (permission == LocationPermission.denied) {
//do stuff here
permission = await Geolocator.requestPermission();
if (permission == LocationPermission.denied) {
//stuff
return Future.error("location permissions denied");
}
}
if (permission == LocationPermission.deniedForever) {
return Future.error("location permissions permanently denied");
}
Geolocator.getCurrentPosition(desiredAccuracy: LocationAccuracy.high);
//position stream?
}
}
This is the code for the map page:
class MapPage extends StatefulWidget {
const MapPage({super.key});
#override
State<MapPage> createState() => _MapPageState();
}
class _MapPageState extends State<MapPage> {
#override
Widget build(BuildContext context) {
return Scaffold(
body: Stack(
children: [
Container(
child: GoogleMap(
initialCameraPosition: CameraPosition(
target: locationController.getlocation(), zoom: 16),
minMaxZoomPreference: MinMaxZoomPreference(15.5, 19),
zoomGesturesEnabled: true,
cameraTargetBounds: CameraTargetBounds(
LatLngBounds(
northeast: LatLng(43.7970928, -79.3067414),
southwest: LatLng(43.592580, -79.483674),
),
),
),
),
],
),
);
}
}
try this
// create a class for location also handle permission
class PermissionToUser {
static Future permissionForLocation() async {
final request = await [Permission.location].request();
log(request[Permission.location].toString());
final status = await Permission.location.status;
if (status.isDenied) {
request;
return false;
} else if (status.isRestricted) {
request;
return false;
} else if (status.isLimited) {
request;
return false;
} else {
return true;
}
}
static Future<Position>? determinePosition() async {
bool serviceEnabled;
LocationPermission permission;
serviceEnabled = await Geolocator.isLocationServiceEnabled();
if (!serviceEnabled) {
return Future.error('Location services are disabled.');
}
permission = await Geolocator.checkPermission();
if (permission == LocationPermission.denied) {
permission = await Geolocator.requestPermission();
if (permission == LocationPermission.denied) {
return Future.error('Location permissions are denied');
}
}
if (permission == LocationPermission.deniedForever) {
return Future.error(
'Location permissions are permanently denied, we cannot request permissions.');
}
return await Geolocator.getCurrentPosition(
desiredAccuracy: LocationAccuracy.high);
}
}
As per use on the controller
class LocationController extends GetxController {
/// Declare the postion also the lat long just for example
late Position? posinitial;
final lat = 0.0.obs, lng = 0.0.obs;
#override
void onInit() async {
/// Run through here
await PermissionToUser.permissionForLocation().then((value) async {
posinitial = await PermissionToUser.determinePosition();
}).whenComplete(() {
getPositionData();
});
super.onInit();
}
getPositionData() async{
// try to log the data if its not empty
if (posinitial != null) {
log("${posinitial!.latitude}",name:"latitude");
log("${posinitial!.longitude}",name:"longtitude");
/// just pass this to ui to use
lat(posinitial!.latitude);
long(posinitial!.longitude);
}
}
}
as for the googgle map you can call the postion
posinitial != null ?
GoogleMap(
initialCameraPosition: CameraPosition(
/// you can use the lat long that was declared on the controller
/// anyways many ways to do it.
target: LatLng(controller.posinitial!.latitude, controller.posinitial!.longitude), zoom: 16),
minMaxZoomPreference: MinMaxZoomPreference(15.5, 19),
zoomGesturesEnabled: true,
cameraTargetBounds: CameraTargetBounds(
LatLngBounds(
northeast: LatLng(43.7970928, -79.3067414),
southwest: LatLng(43.592580, -79.483674),
),
),
) : const SizedBox.shrink(),
I think you should create a seperate variable like this :
In controller, I created a Position type var myLocation and storing my location in it.
static LocationController instance = Get.find();
late Position myLocation;
#override
void onInit() {
super.onInit();
getlocation();
}
getlocation() async {
bool serviceEnabled;
LocationPermission permission;
serviceEnabled = await Geolocator.isLocationServiceEnabled();
if (!serviceEnabled) {
await Geolocator.openLocationSettings();
return Future.error("location service is not enabled");
}
permission = await Geolocator.checkPermission();
if (permission == LocationPermission.denied) {
//do stuff here
permission = await Geolocator.requestPermission();
if (permission == LocationPermission.denied) {
//stuff
return Future.error("location permissions denied");
}
}
if (permission == LocationPermission.deniedForever) {
return Future.error("location permissions permanently denied");
}
myLocation = await Geolocator.getCurrentPosition(desiredAccuracy: LocationAccuracy.high);
//position stream?
}
and the GoogleMap widget should be like:
GoogleMap(
initialCameraPosition: CameraPosition(
target: LatLng(
locationController.myLocation.latitude,
locationController.myLocation.longitude ),
zoom: 16),
minMaxZoomPreference: MinMaxZoomPreference(15.5, 19),
zoomGesturesEnabled: true,
cameraTargetBounds: CameraTargetBounds(
LatLngBounds(
northeast: LatLng(43.7970928, -79.3067414),
southwest: LatLng(43.592580, -79.483674),
),
),
I'm using geolocator and google_maps_flutter in my app to get user location, passing by getPositionStream.
The Map is the first screen of the app, and when I get user location it work fine, and the camera of the map zoom correctly.
But the user can login to his account, and it's recreated the Map. And my problem is here. When the login is done, my stream with my new location is not listen :/ I need to reload the app for that
My function in my viewModel
final Stream<Position>? stream = await _locationService.getLocation();
if (stream != null) {
stream.listen((location) async {
final newLocation =
CameraPosition(target: LatLng(location.latitude, location.longitude), zoom: 15);
if (controllerCompleter != null) {
final GoogleMapController controller = await controllerCompleter.future;
controller.animateCamera(CameraUpdate.newCameraPosition(newLocation));
}
});
}
In the locationService:
Future<Stream<Position>?> getLocation() async {
bool _serviceEnabled;
LocationPermission _permissionGranted;
_serviceEnabled = await Geolocator.isLocationServiceEnabled();
if (!_serviceEnabled) {
return null; // Use France's GPS coordinates by default
}
_permissionGranted = await Geolocator.checkPermission();
if (_permissionGranted == LocationPermission.denied) {
_permissionGranted = await Geolocator.requestPermission();
if (_permissionGranted == LocationPermission.denied ||
_permissionGranted == LocationPermission.deniedForever) {
return null; // Use France's GPS coordinates by default
} else {
return Geolocator.getPositionStream(locationSettings: locationSettings);
}
} else {
return Geolocator.getPositionStream(locationSettings: locationSettings);
}
}
If anyone have an idea of what I'm doing wrong.
Thanks in advance
I have already got the geolocation with longitude and latitude using the geolocation plugin with getx but now I want to post the same longitude and latitude on API with already present in the backhand the model is yet to be created and even the provider is also yet to be done and I don't know how and the location API post should run in the background once with the application opens up.
API body:-
{
"longitude":"55.5852",
"latitude":"77.6532"
}
Controller code:-
class RootController extends GetxController {
var latitude = 'Getting Latitude..'.obs;
var longitude = 'Getting Longitude..'.obs;
var address = 'Getting Address..'.obs;
final currentIndex = 0.obs;
final notificationsCount = 0.obs;
final customPages = <CustomPage>[].obs;
NotificationRepository _notificationRepository;
CustomPageRepository _customPageRepository;
StreamSubscription<Position> streamSubscription;
RootController() {
_notificationRepository = new NotificationRepository();
_customPageRepository = new CustomPageRepository();
}
#override
void onInit() async {
await getCustomPages();
getNotificationsCount();
if (Get.arguments != null && Get.arguments is int) {
changePageInRoot(Get.arguments as int);
} else {
changePageInRoot(0);
}
super.onInit();
getLocation();
}
#override
void onReady(){
super.onReady();
}
#override
void onClose(){
streamSubscription.cancel();
}
getLocation() async{
bool serviceEnabled;
LocationPermission permission;
serviceEnabled = await Geolocator.isLocationServiceEnabled();
if(!serviceEnabled){
await Geolocator.openLocationSettings();
return Future.error('Location Services are disabled.');
}
permission = await Geolocator.checkPermission();
if(permission == LocationPermission.denied){
permission = await Geolocator.requestPermission();
if(permission == LocationPermission.denied){
return Future.error('Location permissions are denied');
}
}
if (permission == LocationPermission.deniedForever){
return Future.error('Location permissions are permanently denied');
}
streamSubscription = Geolocator.getPositionStream().listen((Position position) {
latitude.value = 'Latitude:${position.latitude}';
longitude.value = 'Longitude:${position.latitude}';
getAddressFromLatLang(position);
print(latitude.value);
print(longitude.value);
});
}
Future<void> getAddressFromLatLang(Position position)async{
List<Placemark> placemark = await
placemarkFromCoordinates(position.latitude,position.longitude);
Placemark place = placemark[0];
address.value = 'address:${place.locality},${place.country}';
}
List<Widget> pages = [
HomeView(),
// EServicesView2(),
ReviewsView(),
MessagesView(),
AccountView(),
];
Widget get currentPage => pages[currentIndex.value];
/**
* change page in route
* */
void changePageInRoot(int _index) {
currentIndex.value = _index;
}
void changePageOutRoot(int _index) {
currentIndex.value = _index;
Get.offNamedUntil(Routes.ROOT, (Route route) {
if (route.settings.name == Routes.ROOT) {
return true;
}
return false;
}, arguments: _index);
}
Future<void> changePage(int _index) async {
if (Get.currentRoute == Routes.ROOT) {
changePageInRoot(_index);
} else {
changePageOutRoot(_index);
}
await refreshPage(_index);
}
Future<void> refreshPage(int _index) async {
switch (_index) {
case 0:
{
await Get.find<HomeController>().refreshHome();
break;
}
case 2:
{
await Get.find<MessagesController>().refreshMessages();
break;
}
}
}
void getNotificationsCount() async {
notificationsCount.value = await _notificationRepository.getCount();
}
Future<void> getCustomPages() async {
customPages.assignAll(await _customPageRepository.all());
}
}
what else should I do?
I am trying getting the location coordinates of user and storing it in variable.
I use the location library from flutter.
But I get this error:
type 'Future' is not a subtype of type 'Future'
This is my code
Future<LocationData> coords;
double lat, long;
coords = getUserLocationCoordinates();
coords.then((value) => {
lat = value.latitude,
long = value.longitude,
});
My getUserLocationCoordinates function
getUserLocationCoordinates() async {
LocationData currentLocation;
String error;
Location location = Location();
try {
currentLocation = await location.getLocation();
} on PlatformException catch (e) {
if (e.code == 'PERMISSION_DENIED') {
error = 'please grant permission';
print(error);
}
if (e.code == 'PERMISSION_DENIED_NEVER_ASK') {
error = 'permission denied- please enable it from app settings';
print(error);
}
currentLocation = null;
}
return currentLocation;
}
Any help is greatly appreciated
Initialize variables
String latitude_data;
String longitude_data;
bool _serviceEnabled;
Current Location Function
Future _getLocation() async {
Location location = new Location();
var _permissionGranted = await location.hasPermission();
_serviceEnabled = await location.serviceEnabled();
if (_permissionGranted != PermissionStatus.granted || !_serviceEnabled) {
_permissionGranted = await location.requestPermission();
_serviceEnabled = await location.requestService();
} else {
///Do something here
}
LocationData _currentPosition = await location.getLocation();
longitude_data=_currentPosition.longitude.toString();
latitude_data=_currentPosition.latitude.toString();
///if you want you can save data to sharedPrefrence
SharedPrefrence().setLatitude(_currentPosition.latitude.toString());
SharedPrefrence().setLongitude(_currentPosition.longitude.toString());
}
Can you call a boolean with Shared Preferences in didChangeDependencies?
I need to use isToolTipTapped as a conditional in my build method but it doesn't seem to be working..
#override
void didChangeDependencies() async {
isToolTipTapped = await checkIfToolTipTapped();
print('$isToolTipTapped');
super.didChangeDependencies();
}
Future<bool> checkIfToolTipTapped() async {
SharedPreferences prefs = await SharedPreferences.getInstance();
return prefs.getBool(SchnapConfigValues.toolTipTapped ?? false);
}
print('$isToolTipTapped'); does return the boolean in didChangeDependencies method but my build method doesn't take the value
I think you should be try this code:
class _DemoPageState extends State<DemoPage> {
static const TAG = 'DemoPage';
bool isToolTipTapped;
Future<bool> checkIfToolTipTapped() async {
SharedPreferences prefs = await SharedPreferences.getInstance();
return prefs.getBool(SchnapConfigValues.toolTipTapped ?? false);
}
#override
void didChangeDependencies() {
super.didChangeDependencies();
checkIfToolTipTapped().then((value) {
setState(() {
isToolTipTapped = value;
});
});
}
#override
Widget build(BuildContext context) {
if (isToolTipTapped == null) {
return Your Loading Widget...
} else {
//Handle logic with isToolTipTapped
}
}
}
class _DemoPageState extends State<DemoPage> {
static const TAG ='DemoPage';
bool isToolTipTapped = false;
Future<SharedPreferences> _prefs = SharedPreferences.getInstance();
Future<bool> checkIfToolTipTapped() async {
SharedPreferences prefs = await _prefs;
return prefs.getBool(SchnapConfigValues.toolTipTapped ?? false);
}
#override
void didChangeDependencies() {
super.didChangeDependencies();
checkIfToolTipTapped().then((value) {
setState(() {
isToolTipTapped = value;
});
});
}
#override Widget build(BuildContext context) {
if (isToolTipTapped) {
return Your Loading Widget...
} else {
//Handle logic with isToolTipTapped
}
}
}