0

I'm building a flutter app to show the nearby ATMs to a user. So I collect it position and comapre it to the ATMs positons whicha are stored in cloud firestore.

This is what I did... When I compiled I get an error at the line which contains the code List<DocumentSnapshot<Map<String, dynamic>>> documentList = querySnapshot().docs;

How should I solve the problem please??

import 'package:cloud_firestore_platform_interface/cloud_firestore_platform_interface.dart';
import 'package:firebase_core/firebase_core.dart';
import 'package:flutter/material.dart';
import 'package:gab/pages/functions.dart';
import 'package:geocoding/geocoding.dart';
import 'package:geolocator/geolocator.dart';
import 'package:permission_handler/permission_handler.dart';
import 'package:geoflutterfire/geoflutterfire.dart';
import 'package:cloud_firestore/cloud_firestore.dart';
import 'dart:math' show asin, cos, pi, pow, sin, sqrt;


final geo = Geoflutterfire();
final _firestore = FirebaseFirestore.instance;



class Principal extends StatefulWidget {
  const Principal({Key? key}) : super(key: key);

  @override
  State<Principal> createState() => _PrincipalState();
}

class _PrincipalState extends State<Principal> {

  //To obatin positon
  Position? position1;

  getCurrentLocation() async {
    Position position = await determinePosition();
    setState(() {
      position1 = position;
    });
  }

  Future<Position> determinePosition() async {
    LocationPermission permission;
    permission = await Geolocator.checkPermission();
    if (permission == LocationPermission.denied) {
      permission = await Geolocator.requestPermission();
      if (permission == LocationPermission.denied) {
        return Future.error("Location permissions are denied");
      }
    }
    return await Geolocator.getCurrentPosition();
  }


 @override
  Widget build(BuildContext context){
    // TODO: implement build
   double _toRadians(double degree) {
     return degree * pi / 180;
   }

   //To calculate the Harvesine distance
   double calculateDistance(double lat1, double lon1, double lat2, double lon2) {
     const double earthRadius = 6371;
     double dLat = _toRadians(lat2 - lat1);
     double dLon = _toRadians(lon2 - lon1);
     double a = pow(sin(dLat / 2), 2) + cos(_toRadians(lat1)) * cos(_toRadians(lat2)) * pow(sin(dLon / 2), 2);
     double c = 2 * asin(sqrt(a));
     return earthRadius * c;
   }


   getCurrentLocation();
   if (position1 != null) {
     GeoPoint userLocation = GeoPoint(
         position1!.latitude, position1!.longitude);
     double radius = 10;
     Future<QuerySnapshot<Map<String, dynamic>>> querySnapshot() async {
       return await _firestore.collection('atms').where("isFunctioning", isEqualTo: true).where('position.geopoint.latitude',
           isGreaterThan: userLocation.latitude - (radius / 111)).where(
           'position.geopoint.latitude',
           isLessThan: userLocation.latitude + (radius / 111)).get();
     }
     //Calculating the distance to each atm
     List<DocumentSnapshot<Map<String, dynamic>>> documentList = querySnapshot().docs;//This is where I'm getting the error
     List<ATM> atmList = [];
     for (DocumentSnapshot<Map<String, dynamic>> document in documentList) {
       GeoPoint atmLocation = document.get('position.geopoint');
       double distance = calculateDistance(userLocation.latitude, userLocation.longitude, atmLocation.latitude, atmLocation.longitude);
       if (distance <= radius) {
         ATM atm = ATM(
           name: document.get('name'),
           isFunctioning: document.get('isFunctioning'),
           position: GeoPoint(atmLocation.latitude, atmLocation.longitude),
           distance : distance,
         );
         atmList.add(atm);
       }
     }
     atmList.sort((a, b) => a.distance.compareTo(b.distance));
     return Scaffold(
       appBar: AppBar(
         title: Text('ATMs'),
       ),
       body: ListView.builder(
         itemCount: atmList.length,
         itemBuilder: (BuildContext context, int index) {
           return ListTile(
             title: Text(atmList[index].name),
             subtitle: Text('${atmList[index].distance.toStringAsFixed(2)} km'),
           );
         },
       ),
     );
   }
   else{
     return Scaffold(
       appBar: AppBar(
         title: Text('ATMs'),
       ),
       body: Center(
         child: CircularProgressIndicator(color: Color(0xFFee7b64),),
       ),
     );
   }

  }
}
class ATM {
  String name;
  bool isFunctioning;
  GeoPoint position;
  double distance;

  ATM({required this.name, required this.isFunctioning, required this.position, required this.distance});
}

Im getting the error at the line which contains List<DocumentSnapshot<Map<String, dynamic>>> documentList = querySnapshot().docs;

Abdel
  • 23
  • 7

1 Answers1

1

Your querySnapshot function returns a Future<QuerySnapshot<Map<String, dynamic>>>. The Future in there means that the QuerySnapshot is asynchronously loaded, and you need to handle that asynchronous behavior when you call it. Your code currently doesn't do that.

List<DocumentSnapshot<Map<String, dynamic>>> documentList = querySnapshot().docs;

The two options are to either use then or use await.


With then it'll look like this:

querySnapshot().then((List<DocumentSnapshot<Map<String, dynamic>>> documentList) {
  ... all code that accesses documentList has to be in here
});

With await it'll look like this:

List<DocumentSnapshot<Map<String, dynamic>>> documentList = (await querySnapshot()).docs;

Or a bit more readable:

var querySnapshot = await querySnapshot();
List<DocumentSnapshot<Map<String, dynamic>>> documentList = querySnapshot.docs;

In both of these latter examples, you'll need to mark the block where you use await as async.


To learn more about all of this, see:

Frank van Puffelen
  • 565,676
  • 79
  • 828
  • 807
  • I tried this but there's another problem please. It is saying ''The await expression can only be used in an async function.'' and it suggests me to add the 'async' modifier to the build function. But when i do that it says that the build function is not correctly implemented – Abdel May 02 '23 at 23:56
  • That is correct. You'll want to either use `then` and `setState` or use a `FutureBuilder` to display the asynchronously loaded value. Also see: https://stackoverflow.com/questions/63017280/what-is-a-future-and-how-do-i-use-it – Frank van Puffelen May 03 '23 at 01:07