Flutter Send a post request while waiting for gps data - flutter

I'm stuck on my flutter project, I want to send the gps coordinate every time the user open the app to check if its position is on specific place referenced on my base (if yes it send a notification). I have two futures, one of which is dependent on the other (sending needs gps data).
import 'package:http/http.dart' as http;
import 'package:location/location.dart';
import 'dart:convert';
class Islandmenu extends StatelessWidget {
Widget build(BuildContext context) {
......
}
Future<void>getgpscoordinates() async{
final locdata = await Location().getLocation();
List<double> gps= [locdata.latitude,locdata.longitude];
return gps;
}
Future<void>checkUser(gps) async{
const String userurl="*********/input_dbco.php";
final response = await http.post(userurl, body:jsonEncode({
"id": "",
"gps":[gps[0],gps[1]],
"dateco": "",
}));
return response;
}
}//end of class
but it's make my VM crash so i guess i do it in the wrong way ^^.

Related

Listen to changes on a Future object in Flutter

I need to know wether NFC is active or inactive inside the application. I'm using nfc_manager package and riverpod for state management. Here is my providers and ChangeNotifier class:
import 'dart:async';
import 'package:flutter/material.dart';
import 'package:flutter_riverpod/flutter_riverpod.dart';
import 'package:nfc_manager/nfc_manager.dart';
final nfcProvider = ChangeNotifierProvider.autoDispose<NfcService>((ref) {
return NfcService();
});
final nfcIsAvabilableProvider = StreamProvider.autoDispose<bool>((ref) {
ref.maintainState = true;
final stream = ref.watch(nfcProvider).isAvailable.stream;
return stream;
});
class NfcService extends ChangeNotifier {
NfcManager nfcManager = NfcManager.instance;
StreamController<bool> isAvailable = StreamController.broadcast();
NfcService() {
init();
}
init() async {
isAvailable.addStream(nfcManager.isAvailable().asStream());
}
}
When I close the NFC inside the settings, nfcManager.isAvailable() does not return the new state of NFC availability because it is a future not a stream.
So my question is: how to listen to changes on a future object in Flutter?

How should I store a Firestore DocumentReference that I use multiple times?

The database
Hey!
I have a Firestore database with two collections: users and groups.
Each user is linked to a group. So, of course my flutter app is fetching the group's DocumentReference multiple times in the app, so it can use it to fetch other data from the database.
What I have currently
This is how I am currently fetching the data. This screen is the base for many screens in the app, so each screen has one groupDocRef, which isn't very efficient - I would like them to all have the same one.
import 'dart:async';
import 'package:cloud_firestore/cloud_firestore.dart';
import 'package:firebase_auth/firebase_auth.dart';
import 'package:flutter/cupertino.dart';
import 'package:flutter/foundation.dart';
import 'package:shavtzak/data/soldier.dart';
import 'package:shavtzak/widgets/placeholder.dart';
import '../constants.dart';
import '../utils.dart';
/// A base [StatefulWidget] for any screen that wants to display data from Firestore.
abstract class BaseFirestoreState<T extends StatefulWidget> extends State<T> {
/// The current [FirebaseAuth] user.
User? _user;
StreamSubscription<User?>? _authStateChangeListener;
DocumentReference<Map<String, dynamic>>? _nullableGroupDoc;
/// A [DocumentReference] to the user's group doc.
late DocumentReference<Map<String, dynamic>> groupDocRef;
#override
#nonVirtual
Widget build(BuildContext context) {
// Begin to listen to any user change event.
if (_authStateChangeListener == null) {
_authStateChangeListener = FirebaseAuth.instance.authStateChanges().listen((User? user) {
if (user != null) {
_user = user;
Utils.getGroupDoc(_user!).then((value) => {setState(() => _nullableGroupDoc = value)});
}
});
}
// If the group doc is null, show empty screen.
if (_nullableGroupDoc == null)
return NoDataPlaceholder();
// Else return the child.
else
groupDocRef = _nullableGroupDoc!;
return buildWithDoc(context);
}
/// The child's widget.
///
/// Replaces the default [build] method.
Widget buildWithDoc(BuildContext context);
/// Returns a [Stream] of lists of [Soldier]s.
Stream<QuerySnapshot<Map<String, dynamic>>> getSoldiersStream() {
return groupDocRef.collection(Constants.dbColSoldiers).snapshots();
}
/// Extracts and returns a list of soldiers from a Firestore [QuerySnapshot].
List<Soldier> soldierListFromSnapshot(QuerySnapshot<Map<String, dynamic>> snapshot) {
return snapshot.docs.map((DocumentSnapshot<Map<String, dynamic>> doc) {
Soldier? sol;
// If there is no data, return null.
if (doc.data() == null) {
sol = null;
}
// Else, return the extracted soldier.
else {
sol = Soldier.fromMap(doc.data()!, doc.id);
}
return sol!;
}).toList();
}
#override
void dispose() {
if (_authStateChangeListener != null) {
_authStateChangeListener!.cancel();
}
super.dispose();
}
}
The Question
Since reading the same DocumentReference a lot of times in a single app session isn't a good idea, I would like to know how should I create a global reference so that I call the database only once.
Typically, one uses static for sharing a variable between all instances of a class:
static late DocumentReference<Map<String, dynamic>> groupDocRef;
Access with:
YOUR_CLASS.groupDocRef = ...
var bla = YOUR_CLASS.groupDocRef;

Flutter: Non-nullable instance field 'currentLocation' must be initialised

I'm getting an error with the new flutter changes on null safety. Am not sure whether I am supposed to add final/late/! in this code.
I have a code to connect to Google Maps and now I want to be able to store the data collected.
Right now I facing an error at the Application Bloc: Non-nullable field 'currentLocation' must be initialized.
import 'package:flutter/material.dart';
import 'package:hawkepedia/services/geolocator_Services.dart';
import 'package:geolocator/geolocator.dart';
class ApplicationBloc with ChangeNotifier {
final geoLocatorService = GeolocatorService();
//Variables
Position currentLocation;
//fire function when the app starts
ApplicationBloc(){
setCurrentLocation();
}
//gets current location
setCurrentLocation() async {
currentLocation = await geoLocatorService.getCurrentLocation();
notifyListeners();
}
}
As it is state in the error, the field causing the issue is currentLocation.
You can:
set it as late meaning you will initilize it during initState for example.
set it a nullable, not sure it is possible in this case, Position? currentLocation. (But it is for primary types)
Initialize it with a neutral value that you know is not initialized yet
Edit:
import 'package:flutter/material.dart';
import 'package:hawkepedia/services/geolocator_Services.dart';
import 'package:geolocator/geolocator.dart';
class ApplicationBloc with ChangeNotifier {
final geoLocatorService = GeolocatorService();
//Variables
late Position currentLocation;
//fire function when the app starts
ApplicationBloc(){
setCurrentLocation();
}
//gets current location
setCurrentLocation() async {
currentLocation = await geoLocatorService.getCurrentLocation();
notifyListeners();
}
}

Error in Http package and JsonPlaceholder while running

I am getting this error many times in Flutter when I want to use the JsonPlaceholder API, and I downloaded a package named HTTP package in pub.dev/flutter , used in pubspec.yaml , but I can't get the data it gives the same error every time I run the application,
([ERROR:flutter/lib/ui/ui_dart_state.cc(157)] Unhandled Exception: SocketException: Failed host lookup: 'jsonplaceholder.typicode.com' (OS Error: No address associated with hostname, errno = 7)) ,
Here is the code I used inside my stateful Widget class
import 'package:flutter/material.dart';
import 'package:http/http.dart';
class Loading extends StatefulWidget {
#override
_LoadingState createState() => _LoadingState();
}
class _LoadingState extends State<Loading> {
void getData() async{
Response response = await get('https://jsonplaceholder.typicode.com/todos/1');
print(response.body);
}
#override
initState() {
super.initState();
getData();
}
#override
Widget build(BuildContext context) {
return Scaffold(
body: Center(
child: Text('Loading Screen'),
),
);
}
}
The problem is in various stages.
Did not import the package right
Did not perform the operation right in the method
We will sort this out one by one. Refer to the http documentation, by selecting the link give. Now let us jump into the code
1. Importing the package right
// refer documentation as well
import 'package:http/http.dart' as http;
2. Using the method right
void getData() async{
// see the difference, it is http.get()
Response response = await http.get('https://jsonplaceholder.typicode.com/todos/1');
print('Response body: ${response.body}');
}
Now that you call your method in your initState(), you will get the data in your console.
Also, it is a good practice to take a look at the response code, if it is 200, it is OK, else return an error message.
void getData() async{
// see the difference, it is http.get()
Response response = await http.get('https://jsonplaceholder.typicode.com/todos/1');
if(response.statusCode == 200) print('Response body: ${response.body}');
else print('Some error happened, here is the status code: ${response.statusCode}')
}

how to add remove and show in widget when data is added to websocket?

i use laravel_echo and flutter_pusher_client packages for custom websocket. i can successfully fetch data in real time when backend sends. My data is number and message. and i send that coming number data as message to that number using sms_maintained package. My problem is how to show alltime data(past,present,future) that is coming when backend sends. It can be in anytime. should i use StreamBuilder or Animated list??. and little example would be appreciated. Here is websocket part code:
import 'package:dio/dio.dart';
import 'package:flutter/material.dart';
import 'package:flutter_pusher_client/flutter_pusher.dart';
import 'package:laravel_echo/laravel_echo.dart';
import 'package:pursat_otp/provider.dart';
import 'package:sms_maintained/sms.dart';
import 'model/data_model.dart';
import 'model/pusher_model.dart';
class PusherSide extends StatefulWidget {
#override
_PusherSideState createState() => _PusherSideState();
}
class _PusherSideState extends State<PusherSide> {
FlutterPusher pusherClient;
Echo echo;
dynamic channel;
Data data;
// fetch declarations
#override
void initState() {
fetchConf();
super.initState();
}
Future<void> fetchConf() async {
try {
var response = await Provider.dio.get('/conf/pusher');
Conf conf = Conf.fromJson(response.data['conf']);
debugPrint('${conf.pusherAppKey}');
//websocket part
FlutterPusher getPusherClient() {
PusherOptions options = PusherOptions(
host: conf.host,
port: conf.port,
cluster: conf.pusherAppCluster,
encrypted: conf.encrypted);
return FlutterPusher(conf.pusherAppKey, options, lazyConnect: false);
}
pusherClient = getPusherClient();
echo = new Echo({
'broadcaster': 'pusher',
'client': pusherClient,
});
channel = echo.channel(conf.channel);
channel.listen(conf.event, (e) {
setState(() {
data = Data.fromJson(e);
debugPrint('$e');
});
});
} on DioError catch (e) {
debugPrint('${e.message}');
}
}
#override
Widget build(BuildContext context) {
// how to show that e data here using StreamBuilder or AnimatedList or any Widget. e data comes as json at anytime during a day
}
}
anyway i solved above problem using AnimatedList widget. Let me know if who needs source code.