Disable Button While processing Flutter - flutter

How can I disable a a button while in processing? I have made a like button, but it takes some delay to register the like on db. How can I prevent the button press while processing is done. ??
onPressed: () {
setState(() {
_color = Colors.green;
_icon = Icon(Icons.favorite);
final like = LikeData(
campaingID: donation.campaignID,
dateTime: Timestamp.now(),
userName: FirebaseAuth.instance.currentUser.displayName,
userId: user.uid,
);
likeService.newLike(donation, like);
how can i prevent double tap on this button event??

try this
bool isProcessing = false; // in your class before build method
onPressed: !isProcessing ? () {
setState(() {
isProcessing = true;
_color = Colors.green;
_icon = Icon(Icons.favorite);
final like = LikeData(
campaingID: donation.campaignID,
dateTime: Timestamp.now(),
userName: FirebaseAuth.instance.currentUser.displayName,
userId: user.uid,
);
likeService.newLike(donation, like).then((val) {
setState() {
isProcessing = false;
}
});
});
} : null,

Think of it as three different states, e.g. "initial", "pressedConfirmationPending" and "pressedAndConfirmed". The button can then be enabled depending on this status, e.g.:
String buttonStatus = 'initial';
...
MyButton(
...
enabled: buttonStatus == 'initial' || buttonStatus == 'pressedAndConfirmed',
...
);
Set the status to 'pressedConfirmationPending' just before you start the input processing, and then to 'pressedAndConfirmed' after your receive confirmation that processing is finished.
Also, the button's design and child widget will most likely be different, and possibly also it's onPressed functionality.

You can do adding a variable between processing.
I think that 'newLike' is synchronous method.
So you set checking variable true and processing 'newLike'.
After that set checking variable false to enable button.
bool isProcessing = false;
...
onPressed: isProcessing ? null : () async {
setState(() {
isProcessing = true;
final like = LikeData(
campaingID: donation.campaignID,
dateTime: Timestamp.now(),
userName: FirebaseAuth.instance.currentUser.displayName,
userId: user.uid,
);
await likeService.newLike(donation, like);
});
setState(() {
_color = Colors.green;
_icon = Icon(Icons.favorite);
isProcessing = false;
});

firstly you need to create bool variable like this
'
bool _isworking=false;
onPressed:(){
if(_isworking==false){
setState(() {
_isworking=true;
});
{{ here your function }}
setState(() {
_isworking=false;
});
}
else
{
print('the Function is working now please wait ');
//you can edit this and show the user a dialog that the process is going on and he need to wait
}
}

Related

Unhandled Exception: Null check operator used on a null value Uint8List

Unhandled Exception: Null check operator used on a null value
Friends, I have indicated the place where the error is below and I tried a few things, but I still could not get rid of this error. Does anyone know the solution?
When I remove ! from _image!, I still get an error.
Uint8List? _image;
signUpUser() async {
// set loading to true
setState(() {
_isLoading = true;
});
String res = await AuthMethods().signUpUser(
email: _emailController.text,
password: _passwordController.text,
username: _usernameController.text,
bio: _bioController.text,
gender: _genderController.text,
file: _image! //--> error);
if (res == "success") {
setState(() {
_isLoading = false;
});
Navigator.push(context, MaterialPageRoute(builder: (context) => HomePage()));
} else {
setState(() {
_isLoading = false;
});
// show the error
showSnackBar(context, res);
}
}
selectImage() async {
Uint8List im = await pickImage(ImageSource.gallery);
setState(() {
_image = im;
});
}
The _image is null. I don't see where you call the selectImage() function, and other than that function _image is never defined. Even if selectImage() was called, when the picker appears the user may not actually pick an image and cancel it or another error can happen. The AuthMethods().signUpUser() method seems to not allow the file parameter to be null, that's why when you remove the ! it doesn't work.

An alert dialog is not displayed at the widget load, why?

In my application I am reading a qr code with the flutter_barcode_scanner package, and when reading a valid code it is supposed to show me an alert dialog saying that it is correct, otherwise, well, no.
To implement this package, an example tells us that based on an action (such as pressing a button) start the scanning method, and save what is read in a variable. Thus:
Future<void> scanQr() async {
try {
final qrCode = await FlutterBarcodeScanner.scanBarcode(
'#ffffff', 'Cancel', true, ScanMode.QR);
if (!mounted) {
return;
}
setState(() {
this.qrCode = qrCode.isEmpty
? 'EMPTY'
: qrCode == '-1'
? 'INVALID'
: qrCode;
});
} on PlatformException {
qrCode = 'fail';
}
}
We can see what the set state occupies in order to update the value. This in a variable that, as you can see, is called qrCode. Which in the example puts it in a text widget and it works fine. when reading something, it is updated.
So, what I want to do is a simple validation, and based on said validation, show an alertdialog saying if what was read in the qr is right or wrong.
I have my validation in the same setstate, I ask if a certain part of the read string looks like what I want. Likewise, I have an int variable, which when updated in the set state, draws an alertdialog.
Future<void> scanQr() async {
try {
final qrCode = await FlutterBarcodeScanner.scanBarcode(
'#ffffff', 'Cancel', true, ScanMode.QR);
if (!mounted) {
return;
}
setState(() {
this.qrCode = qrCode.isEmpty
? 'EMPTY'
: qrCode == '-1'
? 'INVALID'
: qrCode;
});
if (qrCode.substring(0, 2) == 'somepattern') {
setState(() {
value = 1;
});
} else {
setState(() {
value = 2;
});
}
//saveContact(qrCode);
} on PlatformException {
qrCode = 'fail';
}
}
In the build method I have:
String qrCode = '';
int value = 0;
#override
Widget build(BuildContext context) {
//Future(() async {
(value == 1)
? alerta('Yeah', "This code are right!")
: (value == 2)
? alerta(
'Oh no!', 'An invalid qr code')
: null;
//});
return Scaffold(...
As you can see, I even try it with a future to give it time to draw, but it doesn't show any alertDialog. The text widget with the each is displayed. Even, i print the value, and its right, prints 2 and 1 respectively; but the alert dialog is never showed
Why doesn't it draw my alert dialog? What am I doing wrong?
Instead of writing the alert dialog logic inside build method, you should have it in scanQR method
Future<void> scanQr() async {
try {
final qrCode = await FlutterBarcodeScanner.scanBarcode(
'#ffffff', 'Cancel', true, ScanMode.QR);
if (!mounted) {
return;
}
setState(() {
this.qrCode = qrCode.isEmpty
? 'EMPTY'
: qrCode == '-1'
? 'INVALID'
: qrCode;
});
if (qrCode.substring(0, 2) == 'somepattern') {
setState(() {
value = 1;
alerta('Yeah', "This code are right!");
});
} else {
setState(() {
value = 2;
alerta(
'Oh no!', 'An invalid qr code');
});
}
//saveContact(qrCode);
} on PlatformException {
qrCode = 'fail';
}
}
Try this and let me know.

How do i create a rounded search bar in flutter that also shows the recent searches from the search bar?

I have been wanting to find a solution to create a rounded search bar in flutter which also shows the list of recent searches underneath it. How is it possible to create the previous widget?
Using the package below, you can save the information you want to the device memory and then withdraw it from there (username, password, search history, etc.). The sample code is in the document.
https://pub.dev/packages/shared_preferences
like this:
void handleRememberMe(bool? value) {
_isChecked = value!;
SharedPreferences.getInstance().then(
(prefs) {
prefs.setBool("remember_me", value);
prefs.setString('userName', userNameController.text);
prefs.setString('password', passwordController.text);
},
);
setState(() {
_isChecked = value;
});
}
void loadUserEmailPassword() async {
try {
SharedPreferences _prefs = await SharedPreferences.getInstance();
var _email = _prefs.getString("userName") ?? "";
var password = _prefs.getString("password") ?? "";
var _remeberMe = _prefs.getBool("remember_me") ?? false;
if (_remeberMe) {
setState(() {
_isChecked = true;
});
userNameController.text = _email;
passwordController.text = password;
} else {
userNameController.text = "";
passwordController.text = "";
setState(() {
_isChecked = false;
});
}
} catch (e) {
debugPrint(e.toString());
}
}

Flutter Multiple setState in Async Function

I'm trying to create a Login Page for my app. I want it to say 'Logging In' then update if there's an issue.
When run, the app doesn't appear to do anything for the timeout duration. I'm guessing the 'Logging In' status is appearing microseconds before the AlertDialog shows as both the status and AlertDialog seem to appear at the same time. Once I click OK, the status updates to 'Retry Login'.
What I want is the 'Logging In' to appear as the text for my status box as soon as the button is pressed.
Button onPressed
ElevatedButton(
onPressed: () async {
setState((){
statusText = 'Logging In';
});
LoginNow();
TimeOutCheck();
},
child: Text('Log In'),
),
TimeOutCheck()
Future<void> TimeOutCheck() async{
hasTimedOut = false;
Duration timeoutDuration = GLOBAL_CONFIG.DEFAULT_TIMEOUT;
final endTime = DateTime.now().add(timeoutDuration);
while (!isComplete && DateTime.now().isBefore(endTime)){
sleep(Duration(milliseconds: 500));
print('Waiting ${DateTime.now()}');
}
hasTimedOut = !isComplete;
if (hasTimedOut){
await _showAlert('Timeout', 'Login Attempt Timed Out.\n\nPlease try again.');
setState(() {
_StatusText = 'Retry Login';
});
}
}
LoginNow()
Future<void> LoginNow(BuildContext context) async {
final String funcName = 'LoginNow';
bool doLogin = false;
_LoginForm.currentState!.validate();
setState(() {
if (LoginInfo['username'] == null || LoginInfo['username'] == ''){
_StatusText = 'Please Enter your User Name';
isComplete = true;
}
else if (LoginInfo['password'] == null || LoginInfo['password'] == '') {
_StatusText = 'Please Enter your Password';
isComplete = true;
}
else {
logger.wtf('[${className}.${funcName}]\t Setting Status to:\t "Logging In"\n');
//_StatusText = 'Logging In';
doLogin = true;
}
});
if (doLogin){
logger.d('[$className.$funcName\t Do Login: $doLogin');
logger.d('[$className.$funcName\t _StatusText Value: $_StatusText');
String URL = GetLoginRequest();
Uri uri = Uri.parse(URL);
var response = await http.get(uri);
isComplete = true;
// Do the rest of login stuff
}
I think what you need is to simply await the functions.
...
await LoginNow();
await TimeOutCheck();
// Make sure to update the status text at the end.
setState(() {
statusText = "Finished";
}
The problem is in the TimeOutCheck(). During the while, I'm using Sleep. Sleep is a synchronous function. Sleep is holding up all changes that may be completed by other async processes.
while (!isComplete && DateTime.now().isBefore(endTime)){
sleep(Duration(milliseconds: 500));
}
Instead of Sleep, I should've used Future.delayed(). Future.delayed() allows other threads to run while the thread it's called in waits for the delay.
while (!isComplete && DateTime.now().isBefore(endTime)){
await Future.delayed(Duration(milliseconds: 500));
}
The working code looks like:
Future<void> TimeOutCheck() async{
this.hasTimedOut = false;
Duration timeoutDuration = GLOBAL_CONFIG.DEFAULT_TIMEOUT;
final endTime = DateTime.now().add(timeoutDuration);
while (!(this.isComplete) && DateTime.now().isBefore(endTime)){
await Future.delayed(Duration(milliseconds: 500));
print('Waiting ${DateTime.now()}\n\t isComplete\t ${this.isComplete}');
}
this.hasTimedOut = !this.isComplete;
if (this.hasTimedOut && !this.isComplete){
await _showAlert('Timeout', 'Login Attempt Timed Out.\n\nPlease try again.');
setState(() {
this._StatusText = 'Retry Login';
});
}
}

How to fix GPS location call currentloaction null error in an API call?

I am calling an Openweather API using current GPS location. But I get an exception showing that currentlocation is called on null.
I can show it on the screen using text widget. But I get null exception when I am calling for the API.
Text('${currentPosition.latitude.toStringAsFixed(2)} ${currentPosition.longitude}'),
void initState() {
getCurrentLocation().then((position) {
currentPosition = position;
});
super.initState();
loadWeather();
}
This the API call function:
Future loadWeather() async {
setState(() {
isLoading = true;
});
final lat = currentPosition.latitude.toStringAsFixed(2);
final lon = currentPosition.longitude.toStringAsFixed(2);
// This part is showing null
final openUviToken = 'API';
final openWeatherToken = 'API';
final weatherResponse = await http.get(
'https://api.openweathermap.org/data/2.5/weather?APPID=${openWeatherToken}&lat=${lat.toString()}&lon=${lon.toString()}');
if (weatherResponse.statusCode == 200) {
return setState(() {
weatherData = new WeatherData.fromJson(
jsonDecode(weatherResponse.body),
);
isLoading = false;
});
}
setState(() {
isLoading = false;
});
}
I tried Hemanth Raj's code already. The app get stuck in a loading state but when I click the button for the loadWeather function, it works. So problem persist only when the app is launched.
This is the load weather button. I just call this function in a column.
IconButton refreshButton() {
return IconButton(
icon: new Icon(Icons.refresh),
tooltip: 'Refresh',
onPressed: loadWeather,
color: Colors.white,
);
}
Seems your are calling loadWeather before the future of getCurrentLocation is complete.
Change your initState like:
void initState() {
getCurrentLocation().then((position) {
currentPosition = position;
loadWeather();
});
super.initState();
}
Hope that helps!