How to implement async | await to receive distance with geoLocation package? - flutter

I am implementing a ListView that will show a Card with the distance between the user and each card location, the location of the card is obtained from Firestore. Im using the geoLocator package but i have an issue to receive the distance, i got null when i call the method and i know that i have to use async-wait in order to wait for the value of the distance but i do not know where to implement it.
This is the class that i call to the get the distance:
class Distance {
double distance;
void getDistance(double startLatitude, double startLongitude, double endLatitude,
double endLongitude) async {
try {
distance = await Geolocator().distanceBetween(
startLatitude, startLongitude, endLatitude, endLongitude);
} catch (e) {
print('SE DISPARO EL ERROR DE DISTANCE = $e');
}
}
This is the Widget that i return:
Widget cardList(double userLatitude, double userLongitude) {
double result;
// Method to get the distance
dynamic getDistance(double cardLatitude, double cardLongitude) async {
Distance distancia = Distance();
await distancia.getDistance(
userLatitude, userLongitude, cardLatitude, cardLongitude);
result = distancia.distance;
return result;
}
return StreamBuilder<QuerySnapshot>(
stream: _firestore.collection('salonesInfantiles').snapshots(),
builder: (context, snapshot) {
if (!snapshot.hasData) {
return Center(
child: CircularProgressIndicator(
backgroundColor: Colors.pink,
),
);
}
final rooms = snapshot.data.documents.reversed;
List<SalonesFeed> listaDeSalones = [];
// List<SalonesFeed> listaDeSalonesDistancia = [];
for (var room in rooms) {
final nombreSalonText = room.data['nombre'];
final salonLatitude = room.data['latitude'];
final salonLongitude = room.data['longitude'];
// This is the method that i dont know how to implement the wait in order to receive the value before the ListView is showed
double distance = getDistance(salonLatitude, salonLongitude);
print('result 2 = $result');
final salonCard = SalonesFeed(
nombreSalon: nombreSalonText,
distanciaSalon: distance,
);
listaDeSalones.add(salonCard);
}
return Expanded(
child: ListView(
children: listaDeSalones,
),
);
},
);
}
I got this result:
type 'Future<dynamic>' is not a subtype of type 'double'
I also try to make it Future but still have the same issue of null
type 'Future<double>' is not a subtype of type 'double'

The return type of getDistance should be Future and you should await the response
double distance = await getDistance(salonLatitude, salonLongitude);

Related

total price doesn't display the value

List cart =[];
double totalPrice = 0.0;
//here is i retrieve cart item from database to calculate
Future getData() async {
final CollectionReference reference = FirebaseFirestore.instance.collection('cart');
reference.doc(FirebaseAuth.instance.currentUser!.email).collection('items').get().then((ds) {
ds.docs.forEach((data) {
/*var temp = {
'image': data['image'],
'name': data['name'],
'category': data['category'],
'price': data['price'],
};*/
setState(() {
cart.add(data['price']);
double e = double.parse(data['price']);
totalPrice = totalPrice + e;
});
print(totalPrice.toStringAsFixed(2));
});
});
}
double getTotalPrice() { // calculate of my total price
double totPrice = 0.00;
for(int i=0; i<cart.length; i++){
String price = cart[i];
double p = double.parse(price);
totPrice = totPrice + p;
}
return totPrice;
}
#override
void initState() {
// TODO: implement initState
super.initState();
getData();
getTotalPrice();
}
Future<void> initPayment({required String email, required double amount, required BuildContext context}) async {
double newAmount = amount * 100;
try {
// create a payment intent on the server
final response = await http.post(
Uri.parse('https://us-central1-market-3387e.cloudfunctions.net/stripePaymentIntentRequest'),
body: {
'email': email,
'amount': newAmount.toString(),
'payment_method_types[]': "card",
});
double roundDouble(double value, int places){
num mod = pow(10.0, places);
return ((value * mod).round().toDouble() / mod);
}
#override
Widget build(BuildContext context) {
bottomNavigationBar: Container(
child: ElevatedButton(
child: Text('Payment', style: GoogleFonts.hammersmithOne(
// i can't display total price value here at amount:
onPressed: () async {
double h = roundDouble(totalPrice, 2);
await initPayment(amount: h, context: context, email: 'test#gmail.com');
},
),
),
I do not know why but i already calculate the total price at getTotalPrice() function, but when i declare var h at the amount, it doesn't display the value cause i think i already did true. can someone show me how it supposed to be the calculation because i already declare in the stripe function.
var h is where i declare my calculation of total price but i doesn't display the value it doesn't working. When i route from shopping cart to payment page , the total price doesn't retrieve and display the value. I already retrieve data from my database from "cart" collection

Null check operator used on a null value in my Future to get List object

I would like to retrieve the distance between two positions.
I can get the name but not the distance. I have an error
The following _CastError was thrown building:
Null check operator used on a null value
when I do
print(jsonData);
I get
I/flutter ( 8181): [{nom: CLINIQUE CENTRE, latitude: 37.7586968, longitude: -122.3053474, distance: 0}, {nom: CLINIQUE CHATEAU, latitude: 37.8711583, longitude: -122.336457, distance: 0}, {nom: CLINIQUE ARAFAT, latitude: 37.5206515, longitude: -122.064364, distance: 0}]
this is my model
class Destination {
double lat;
double lng;
String name;
double? distance;
Destination(this.lat, this.lng, this.name, {this.distance});
}
here is what i tried
import 'package:flutter/material.dart';
import 'package:geolocator/geolocator.dart';
import 'package:flutter_sorting_location/Utils.dart';
import 'package:http/http.dart' as http;
import 'dart:convert';
import 'dart:async';
import 'Destinations.dart';
class Home extends StatefulWidget {
#override
_HomeState createState() => _HomeState();
}
class _HomeState extends State<Home> {
double? distance;
List<Destination> destinations = [];
Position? _currentPosition;
Future<List<Destination>> getData() async {
var url = 'http://xxxx/flutter/getlocation.php';
var res = await http.get(Uri.parse(url));
var jsonData = json.decode(res.body);
print(jsonData);
for (var destinationval in jsonData) {
// print(destinationval['nom']);
Destination dests = Destination(
double.parse(destinationval['latitude']),
double.parse(destinationval['longitude']),
destinationval['nom'],
);
destinations.add(dests);
}
// print(destinations);
return destinations;
}
#override
void initState() {
_getCurrentLocation();
super.initState();
}
#override
Widget build(BuildContext context) {
return Scaffold(
appBar: AppBar(
title: const Text("Location sorting from current location"),
),
body: FutureBuilder(
future: getData(),
builder: (context, snapshot) {
if (snapshot.hasData) {
final audioList = snapshot.data as List<Destination>;
return ListView.builder(
itemCount: audioList.length,
itemBuilder: (context, index) {
return Card(
margin: EdgeInsets.all(5),
elevation: 5,
child: Padding(
padding: EdgeInsets.all(5),
child: Container(
height: 40,
color: Colors.white,
child: Column(
children: [
Text(audioList[index].name.toString()),
Text(
"${audioList[index].distance!.toStringAsFixed(2)} km"),
],
),
),
),
);
});
} else if (snapshot.hasError) {
// handle error here
return Text('${snapshot.error}');
} else {
return CircularProgressIndicator(); // displays while loading data
}
}),
);
}
// get Current Location
_getCurrentLocation() {
Geolocator.getCurrentPosition(
desiredAccuracy: LocationAccuracy.best,
forceAndroidLocationManager: true)
.then((Position position) {
distanceCalculation(position);
setState(() {
_currentPosition = position;
});
}).catchError((e) {
print(e);
});
}
distanceCalculation(Position position) {
for (var d in destinations) {
print(d);
var km = getDistanceFromLatLonInKm(
position.latitude, position.longitude, d.lat, d.lng);
// var m = Geolocator.distanceBetween(position.latitude,position.longitude, d.lat,d.lng);
// d.distance = m/1000;
d.distance = km;
destinations.add(d);
// print(getDistanceFromLatLonInKm(position.latitude,position.longitude, d.lat,d.lng));
}
setState(() {
destinations.sort((a, b) {
// print("a : ${a.distance} b : ${b.distance}");
return a.distance!.compareTo(b.distance!);
});
});
}
}
While you are creating instance, it is missing optional distance field here.
for (var destinationval in jsonData) {
Destination dests = Destination(
double.parse(destinationval['latitude']),
double.parse(destinationval['longitude']),
destinationval['nom'],
distance: double.tryParse(destinationval["distance"])
);
audioList[index].distance is getting null, while distance is nullable, it is risky to use ! without null check.
Safer way is checking null 1st and then use ! or provide default value on null case. For string on Text, it can print null
Text("${audioList[index].distance?.toStringAsFixed(2)} km"),
Or just ignore the text build like
if(audioList[index].distance!=null) Text("${audioList[index].distance?.toStringAsFixed(2)} km"),
with
for (var destinationval in jsonData) {
Destination dests = Destination(
double.parse(destinationval['latitude']),
double.parse(destinationval['longitude']),
destinationval['nom'],
distance: double.tryParse(destinationval["distance"])
)
and
if(audioList[index].distance!=null) Text("${audioList[index].distance?.toStringAsFixed(2)} km"),
the screen now displays
type 'Null' is not a subtype of type 'String'
I think the problem lies here since I have to calculate the distance and display it
distanceCalculation(Position position) {
for (var d in destinations) {
var km = getDistanceFromLatLonInKm(
position.latitude, position.longitude, d.lat, d.lng);
d.distance = km;
destinations.add(d);
// print(getDistanceFromLatLonInKm(position.latitude,position.longitude, d.lat,d.lng));
}
setState(() {
destinations.sort((a, b) {
// print("a : ${a.distance} b : ${b.distance}");
return a.distance!.compareTo(b.distance!);
});
});
}
I just corrected
Text("${audioList[index].distance?.toStringAsFixed(2)} km"),
but i can't get distance . it's show me null

Future builder returns null although my list is not empty

I have this future builder which loads a list of movies in my provider class. Whenever I reload my screen, the movies do not get returned. Below is the future builder
FutureBuilder(
future: movieData.getTrendingMovies(),
builder: (context, snapshot) {
if (snapshot.connectionState == ConnectionState.waiting) {
return const Center(
child: CircularProgressIndicator(),
);
} else if (snapshot.hasData) {
return Swiper(
itemBuilder: (BuildContext context, i) {
return ChangeNotifierProvider(
create: (context) => Movie(),
child: MovieContainer(
imageUrl: movieData.movies[i].imageUrl,
id: movieData.movies[i].id,
rate: movieData.movies[i].rate,
title: movieData.movies[i].title,
),
);
},
itemCount: movieData.movies.length,
viewportFraction: 0.25,
scale: 0.4,
);
} else {
return Text(snapshot.error.toString()); // it returns null on the screen
}
}),
Also in my homescreen where I display my movies, after the build method, I create a listener(moviesData) to listen to all changes in the movies provider.
final movieData = Provider.of<Movies>(context, listen: false);
Below is also the methos which fetches the movies from a restfulAPI using http get request
Future<void> getTrendingMovies() async {
List<String> movieTitles = [];
List<String> movieImageUrls = [];
List<String> movieDescriptions = [];
List<String> movieReleaseDates = [];
List<String> movieRates = [];
List<String> movieIds = [];
const _apiKey = '******************************';
const url =
'https://api.themoviedb.org/3/trending/all/week?api_key=$_apiKey';
try {
final response = await http.get(Uri.parse(url));
if (response.statusCode >= 400) {
print(response.statusCode);
return;
}
final extractedData = json.decode(response.body);
List moviesList = extractedData['results'] as List;
List<Movie> loadedMovies = [];
for (int i = 0; i < moviesList.length; i++) {
String movieTitle = moviesList[i]['original_title'] ?? '';
String? movieImage =
'https://image.tmdb.org/t/p/w400${moviesList[i]['poster_path']}'; //results[0].poster_path
String movieDescription =
moviesList[i]['overview'] ?? ''; //results[0].overview
String movieReleaseDate = moviesList[i]['release_date'] ?? '';
String? movieRate = moviesList[i]['vote_average'].toString();
String? movieId = moviesList[i]['id'].toString();
movieTitles.add(movieTitle);
movieImageUrls.add(movieImage);
movieDescriptions.add(movieDescription);
movieReleaseDates.add(movieReleaseDate);
movieRates.add(movieRate);
movieIds.add(movieId);
loadedMovies.add(
Movie(
id: movieIds[i],
title: movieTitles[i],
imageUrl: movieImageUrls[i],
description: movieDescriptions[i],
rate: double.parse(movieRates[i]),
releaseDate: movieReleaseDates[i],
),
);
}
_movies = loadedMovies;
notifyListeners();
//print(_movies.last.title); //This prints the name of the last movie perfectly....This gets called unlimited times whenever I set the listen of the **moviesData** to true
} catch (error) {
print(error);
}
}
There's a couple of things to unpack here.
Instead of a ChangeNotifierProvider, I believe you should use a Consumer widget that listens to your Movies provided service when you call the notifyListeners call, so make it Consumer<Movie>.
You can still call it using the Provider.of above for the sake of making the async call via the FutureBuilder, but I believe because you're not returning anything out of the getTrendingMovies and is just a Future<void> and you're querying the snapshot.hasData, well there is no data coming through the snapshot. Maybe instead you should call snapshot.connectionState == ConnectionState.done as opposed to querying for whether it has data.
Make sure that the response.body is truly returning a JSON value, but I believe your issue is in one of the points above.

getting future string and saving state in flutter

I am trying to get the string value of a future, and saving state in flutter. user chooses the endTime and it should display on the UI untill it ends. however, I am getting the following error:
type 'String' is not a subtype of type 'Future<String>' in type cast
the method:
final Future<SharedPreferences> _prefs =
SharedPreferences.getInstance();
Future<String> _textLine = '' as Future<String>;
Future<String> fastTrue() async {
final SharedPreferences prefs = await _prefs;
String formattedDate = DateFormat('yyyy-MM-dd,
hh:mma').format(endTime);
final textLine = (prefs.getString('formattedDate') ??
Languages.of(context)!.setYourFastTime) as Future<String>;
setState(() {
_textLine = prefs.setString('formattedDate',
Languages.of(context)!.endTimeIs
+'\n$formattedDate').then((bool success) {
return textLine;
});
});
return textLine;
}
in initState():
#override
void initState() {
super.initState();
_textLine = _prefs.then((SharedPreferences prefs) {
return prefs.getString('formattedDate') ??
Languages.of(context)!.setEndTime +'\n'+DateFormat('yyyy-MM-dd,
hh:mma').format(DateTime.now());
});
then in my widget build():
Padding(padding: const EdgeInsets.only(top: 170),
child: FutureBuilder<String>(
future: _textLine,
builder: (BuildContext context,
AsyncSnapshot<String> snapshot) {
switch (snapshot.connectionState) {
case ConnectionState.waiting:
return const CircularProgressIndicator();
default:
if (snapshot.hasError) {
return Text('Error: ${snapshot.error}');
} else {
return Text(
Languages.of(context)!.endTimeIs +
"\n${snapshot.data}"
);
}
}
})),
help me, pls, tried using hive, but was not able to get to save the state of the widget. Thanks!
This code throws the error because you try to cast a String to a Future<String>>, although it is a String.
Future<String> _textLine = '' as Future<String>;
If you want to declare a Future with a value, you can use the value method.
Future<String> _textLine = Future.value('');

'Future<GeoFirePoint>' is not a subtype of type 'GeoFirePoint' in type cast

I have a function that gets coordinates latitude and longitude:
Future <GeoFirePoint> getCenter() async {
var center = await geolocatorService.getInitialLocation()
.then ( (position) {
return GeoFirePoint( position.latitude, position.longitude);
}, onError: throw Exception('Intentional exception')
);}
When I try to assign it:
late GeoFirePoint center = getCenter() as GeoFirePoint;
I get the above error. Tried peppering the function with async /awaits, but I seem to be missing something. More problems arise if I remove the cast.
The problem is, that your getCenter() function returns a Future of GeoFirePoint.
late GeoFirePoint center;
Future <GeoFirePoint> getCenter() async {
final position = await geolocatorService.getInitialLocation();
center = GeoFirePoint(position.latitude, position.longitude);
}
This assigns the correct value to your variable. To catch exceptions you can wrap the line containing the await keyword in a try/catch block.
Instead of assigning getCenter() value to variable center use FutureBuilder to get value from getCenter() like this
FutureBuilder<GeoFirePoint>(
future: getCenter(),
builder: (context, snapshot) {
if (!snapshot.hasData) {
return Text('Loading...');
}
return Text('${snapshot.data}'); /// snapshot.data is the type of GeoFirePoint
},
);