How to update my location after location turned on in flutter - android

I am new to flutter and I am trying something to achieve in this example, I want to update user location after user turns location on, say for suppose user didn't turn on his location first after we give user a pop up saying this application need location on then it should update data but in the below example its not working, please help me out.
Here is the example what I am working on
PS:

Just subscribe to "onLocationChanged" Stream like in the example.
_location.onLocationChanged().listen((Map<String,double> result) {
var latitude = result["latitude"]; //This is called always when the location updates
var longitude = result["longitude"];
});
For showing a popup when the user has no location enabled use this:
try {
currentLocation = await location.getLocation;
} on PlatformException {
await showDialog<dynamic>(
context: context,
builder: (context) {
return AlertDialog(
title: Text("No Location"),
content: Text(
"Please allow this App to use Location or turn on your GPS."),
actions: <Widget>[
FlatButton(
child: Text(
"Ok"
),
onPressed: () {
Navigator.of(context).pop();
},
)
],
);
});
}

Related

How do I fix "Do not use BuildContexts accros async gaps" when using Snack Bar and Navigator in flutter

This is my code
_signinRouter(
userId,
BuildContext context, {
phone = false,
email = false,
googleSignUp = false,
userData,
}) async {
NetworkController network = NetworkController();
setState(() {
_isLoading = true;
});
CallResponse response = await network.fetchUserData(
userId,
phone: phone,
email: email,
);
setState(() {
_isLoading = false;
});
if (response.status == 1) {
debugPrint(response.msg.toString());
//IF USER DATA IS FOUND
showSnackBar('User account exists', context);
} else {
//Since network returns one or zero, 1 for the success of request and 0 for both server error and failure of request
//Response msg will return null if user was not found and it will return an actual server failure msg if it was a server error
if (response.msg == 'null') {
Navigator.push(
context,
MaterialPageRoute(
builder: (context) => (googleSignUp)
? GooglePostSignUp(userData: userData)
: ServerSignUp(phoneNumber: userId, userData: userData),
),
);
} else {
showSnackBar(response.msg, context);
}
}
}
}
I am calling the function within a stateful widget and I defined a function to help in calling the snack bar, my app relies heavily on snack bars and I have this same error all across my files. This is the snack bar function
void showSnackBar(String? value, BuildContext context) {
ScaffoldMessenger.of(context).hideCurrentSnackBar();
ScaffoldMessenger.of(context).showSnackBar(
SnackBar(
content: Text(
value!,
style: p2(
false,
),
),
duration: const Duration(seconds: 2),
action: SnackBarAction(
label: 'Close',
textColor: themeColor,
onPressed: () {
ScaffoldMessenger.of(context).hideCurrentSnackBar();
},
),
),
);
}
I can call the my custom snack bar from anywhere with in my project easily.
I can trick the IDE and lint by removing the Buildcontext type in the function but it not practical, i can check if the widget is mounted before calling the snackbar but i dont think it is very practical ???
I know you are thinking of app performance in mind, Oh! wait! flutter already did that for you :). You don't need to work around it except if you have time and energy. Note that, the context has to be passed every time and so checking the context mount every time is not "i don't think it is very practical" situation
Things like this I call (The warning error). When working with async functions within a context that is likely to be lost due to nesting. You need to handle it with care.
One way to do that is by checking for the widget-mounted state. basically, Don't use context after async if you're not sure your widget is mounted.
To be sure use the following:
if (!mounted) return; // check before calling `Navigator`
Navigator.push(
context,
MaterialPageRoute(
builder: (context) => (googleSignUp)
? GooglePostSignUp(userData: userData)
: ServerSignUp(phoneNumber: userId, userData: userData),
),
);
To make the code short-hand just do the normals!!! :) break the code down in the same file!!
Bye.

Flutter : How to get data from a text field and save it in a map or list for later use?

In this page I wanted to create a text form field to ask the user to enter the name and the price of the item and then when I click on the bottom button I want to save the data in a map so I can access it from another page/widget even when I close the app or maybe to show history of transactions
What's the right way to do it ?
the UI of the widget
c
lass _IncomeState extends State<Income> {
final amountController = TextEditingController();
#override
void dispose() {
amountController.dispose();
super.dispose();
}
and this is the textfield
onPressed: () {
// //this is the part where i add a new income to my list
showDialog(
context: context,
builder: (context) => AlertDialog(
title: Text('Add income'),
content: TextField(
autofocus: true,
decoration: InputDecoration(
hintText: 'entrez la somme ici'),
controller: amountController,
),
));
}),
You can use a TextEditingController to get the value entered in the TextFormField when the button is clicked. Here is an example from the flutter homepage. Just replace the _printLatestValue method from the example with your saving method and call that method when pressing the button.

Using Google fit API in Flutter

I need my app to read step count from Google Fit. I'm using health 3.05 package. For now I copied the example code to see if it works and unfortunately it's not. Of course I did every step from this packge readme. I set up OAuth2 Client ID, I changed gradle.properties as they shown and in AndroidManifest.xml I put <uses-permission android:name="android.permission.ACTIVITY_RECOGNITION"/> . However after running app I don't get any permission window and when I click the button to get data I got an error "Authorization not granted" in console. What should I do? Thanks
Here is my code that I copied form package example:
import 'dart:async';
import 'package:flutter/material.dart';
import 'package:health/health.dart';
class DailyStepsScreen extends StatefulWidget {
#override
_DailyStepsScreenState createState() => _DailyStepsScreenState();
}
enum AppState {
DATA_NOT_FETCHED,
FETCHING_DATA,
DATA_READY,
NO_DATA,
AUTH_NOT_GRANTED
}
class _DailyStepsScreenState extends State<DailyStepsScreen> {
List<HealthDataPoint> _healthDataList = [];
AppState _state = AppState.DATA_NOT_FETCHED;
#override
void initState() {
super.initState();
}
Future<void> fetchData() async {
/// Get everything from midnight until now
DateTime startDate = DateTime(2020, 11, 07, 0, 0, 0);
DateTime endDate = DateTime(2025, 11, 07, 23, 59, 59);
HealthFactory health = HealthFactory();
/// Define the types to get.
List<HealthDataType> types = [
HealthDataType.STEPS,
HealthDataType.WEIGHT,
HealthDataType.HEIGHT,
HealthDataType.BLOOD_GLUCOSE,
HealthDataType.DISTANCE_WALKING_RUNNING,
];
setState(() => _state = AppState.FETCHING_DATA);
/// You MUST request access to the data types before reading them
bool accessWasGranted = await health.requestAuthorization(types);
int steps = 0;
if (accessWasGranted) {
try {
/// Fetch new data
List<HealthDataPoint> healthData =
await health.getHealthDataFromTypes(startDate, endDate, types);
/// Save all the new data points
_healthDataList.addAll(healthData);
} catch (e) {
print("Caught exception in getHealthDataFromTypes: $e");
}
/// Filter out duplicates
_healthDataList = HealthFactory.removeDuplicates(_healthDataList);
/// Print the results
_healthDataList.forEach((x) {
print("Data point: $x");
steps += x.value.round();
});
print("Steps: $steps");
/// Update the UI to display the results
setState(() {
_state =
_healthDataList.isEmpty ? AppState.NO_DATA : AppState.DATA_READY;
});
} else {
print("Authorization not granted");
setState(() => _state = AppState.DATA_NOT_FETCHED);
}
}
Widget _contentFetchingData() {
return Column(
mainAxisAlignment: MainAxisAlignment.center,
children: <Widget>[
Container(
padding: EdgeInsets.all(20),
child: CircularProgressIndicator(
strokeWidth: 10,
)),
Text('Fetching data...')
],
);
}
Widget _contentDataReady() {
return ListView.builder(
itemCount: _healthDataList.length,
itemBuilder: (_, index) {
HealthDataPoint p = _healthDataList[index];
return ListTile(
title: Text("${p.typeString}: ${p.value}"),
trailing: Text('${p.unitString}'),
subtitle: Text('${p.dateFrom} - ${p.dateTo}'),
);
});
}
Widget _contentNoData() {
return Text('No Data to show');
}
Widget _contentNotFetched() {
return Text('Press the download button to fetch data');
}
Widget _authorizationNotGranted() {
return Text('''Authorization not given.
For Android please check your OAUTH2 client ID is correct in Google Developer Console.
For iOS check your permissions in Apple Health.''');
}
Widget _content() {
if (_state == AppState.DATA_READY)
return _contentDataReady();
else if (_state == AppState.NO_DATA)
return _contentNoData();
else if (_state == AppState.FETCHING_DATA)
return _contentFetchingData();
else if (_state == AppState.AUTH_NOT_GRANTED)
return _authorizationNotGranted();
return _contentNotFetched();
}
#override
Widget build(BuildContext context) {
return Scaffold(
appBar: AppBar(
title: const Text('Plugin example app'),
actions: <Widget>[
IconButton(
icon: Icon(Icons.file_download),
onPressed: () {
fetchData();
},
)
],
),
body: Center(
child: _content(),
)
);
}
}
Step 1 use health: 3.0.4
Step 2 do proper set up for OAuth2 Client ID, download new google-service.json
Step 3 From Android 10. you have to add ACTIVITY_RECOGNITION for getting STEP Count permission in AndroidManifest.xml.
<uses-permission android:name="android.permission.ACTIVITY_RECOGNITION" />
Step 4 And then using permission_handler ask for permission.
if (Platform.isAndroid) {
final permissionStatus = Permission.activityRecognition.request();
if (await permissionStatus.isDenied ||
await permissionStatus.isPermanentlyDenied) {
showToast(
'activityRecognition permission required to fetch your steps count');
return;
}
}
FINALLY GOT THIS ISSUE SOLVED!!
So the problem doesn't lie in the version I am using 3.4.0 but still got the problem solved
Authorization not granted. And stuck in loading screen
Stuck in authorization request screen
When you create your OAuth 2.0 consent screen try to add at least 2 email addresses to the TEST USER section and make sure to login from that emails.
Add 2 email addresses in Test User
After that make sure to verify your application from Google, it will work until you test your app once you release the application, it will not work
Verify Your Application from Google
Final Result
Step 1 use health: 3.0.4
Step 2 Add permission function
Step 3 Start your function inside of initstate

How to show a message before 'Usage data access' opens for user to grant permission in flutter

I am using the package "app_usage" to get user data in my app. It however directly opens the usage page without any context. This is as written in the package
as can be seen in the photo.
Now how do I go about showing a screen where I ask the user to grant this permission? it is a protected permission so the user needs to explicitly consent but I would like the user to see something on my app before being taken to settings. Any help would be much appreciated!
You can display a dialog box that alerts the user:
void _showConfirmation() {
showDialog(
context: context,
builder: (_) => new AlertDialog(
title: new Text("App usage"),
content: new Text("We're getting information about your app usage. If you didn't grant the permission yet, you'll be redirected to the settings page"),
actions: <Widget>[
FlatButton(
child: Text('Ok'),
onPressed: () {
_showConfirmation();
Navigator.of(context).pop();
},
)
],
));
}
void getUsageStats() async {
try {
DateTime startDate = DateTime(2018, 01, 01);
DateTime endDate = new DateTime.now();
List<AppUsageInfo> infos = await AppUsage.getAppUsage(startDate, endDate);
setState(() {
_infos = infos;
});
} on AppUsageException catch (exception) {
print(exception);
}
}
You can execute the _showConfirmation() function immediately after the layout has been loaded:
#override
void initState() {
WidgetsBinding.instance
.addPostFrameCallback((_) => _showConfirmation());
}

Flutter validator only trigger on double tap

i stored phone numbers in a firebase document(table). What i want is to detect if the number already existed by using validators and display a message under a textbox that the phone number is already exists i had no problem with this , my problem is a have to double tap the button to execute to complete the task.
var _formKey = GlobalKey<FormState>();
var validate;
String validateNumber(String value){
if (value.isEmpty) {
return 'Please enter number';
}if(validate == true){
return "Phone number already exists";
}
return null;
}
addPhoneNumber(phoneNumber) async{
var exist = await db.checkPhoneNumber(phoneNumber); //my query to firestore so far i have no problem with this.
if(exist == true){
validate = true;
print(validate);
}
if(exist == false){
validate = false;
Navigator.of(context).push(_verifyPhone(_phoneNumber.text));
await db.addPhoneNumber(phoneNumber);
}
} //my function to detect if the number exists
#override
Widget build(BuildContext context) {
_get1();
return WillPopScope(
onWillPop: () async {
Navigator.pop(context);
return true;
},
child: Scaffold(
body: Column(
crossAxisAlignment: CrossAxisAlignment.start,
children: <Widget>[
Form(
key:_formKey,
child:Expanded(
child:Scrollbar(
child: ListView(
padding: EdgeInsets.zero,
children: <Widget>[
TextFormField(
controller: _phoneNumber,
validator: validateNumber, //my validator
),
],
),
),
),
),
FlatButton(
onTap: (){
if(_formKey.currentState.validate()){
addPhoneNumber(phoneNumber)
}
},
)
],
),
),
);
}
}
You need to call the validate() method on your form state. Look here for API reference.
This is not invoked automatically by the framework for you. You need to invoke it inside the onTap() method of your button. Add there a line _formKey.currentState.validate().
When this method is invoked then the form calls the validator for each form field.
---------------------------UPDATE---------------------------------------
Ok, #ppdy, you are one step closer now. It doesn't work yet because your validator only checks if the value is not empty. Just look carefully at what happens when you push the button. It runs the validateNumber and if the value is empty the framework will render your validate message. Then if the value is not empty you run the addPhoneNumber method, but you run it yourself. This is important, notice that it is not get run as part of the text form field validator property function. So you need to handle the output of the await db.checkPhoneNumber(phoneNumber); yourself and render the validation red message in the text form field if the check is false.
For this please note first that the TextFormField class has the decoration property. Type of this property is the InputDecoration. Please read the documentation of this class here. So by setting the errorText property of the decoration you will be able to add the red validation message to the form field manually.
Try to think it all over, play with it, stick this all together and you will have what you want :)

Categories

Resources