flutter : disable button after fetch data - flutter

I am trying to implement a flutter app to fetch data from an API end point. I've already implemented the fetch function on button press.
Although, I want the button (Enregistrer) to get disabled (to avoid multiple clicks) while the request is being fetched or after success editing (name, adress ...) !
I implemented it using the dart http package.
Here's my code for the same:
Container(
margin: EdgeInsets.symmetric(
vertical: 10),
width: size.width * 0.4,
child: ElevatedButton(
onPressed: () {
if (_nameController.text ==
"" &&
_emailController.text ==
"" &&
_adressController
.text ==
"") {
setState(() =>
isButtonDisabled =
true);
} else {
editUserProfile();
}
},
child: Text('Enregistrer'),
void editUserProfile() async {
setState(() {});
// if (_formKey.currentState.validate()) {
String name = _nameController.text;
String email = _emailController.text;
String adress = _adressController.text;
userApi.editUserProfile(name, email, adress).then((data) {
if (data != null) {
}
setState(() {
enableup = false;
enableadress = false;
enableemail = false;
});
ScaffoldMessenger.of(context).showSnackBar(SnackBar(content: Text(data)));
// ScaffoldMessenger.of(context).showSnackBar(snackBar3);
}).catchError((error) {
ScaffoldMessenger.of(context)
.showSnackBar(SnackBar(content: Text(error.toString())));
});
setState(() {});
}

if you set null onPressed you actualy disable the click
onPressed: isButtonDisabled ? null : () {
if (_nameController.text == "" &&
_emailController.text == "" &&
_adressController.text == "") {
setState(() =>
isButtonDisabled = true);
} else {
editUserProfile();
}
}

Related

How to call button tap functionality outside of button in Flutter

I want to call the onTap functionality outside of my button. As soon as I receive my OTP, I want to call the onTap of my manually created widget. I have a custom widget called as LoginCTA and I want to call it's onTap after I receive my OTP in initSmsListener method which I called in initState.
My code -
String _comingSms = 'Unknown';
Future<void> initSmsListener() async {
String comingSms;
try {
comingSms = await AltSmsAutofill().listenForSms??"";
} on PlatformException {
comingSms = 'Failed to get Sms.';
}
if(!mounted)
return;
setState(() {
_comingSms=comingSms;
print("\n \n \n Coming SMS - $_comingSms");
otpController.text = _comingSms[23] + _comingSms[24] + _comingSms[25] + _comingSms[26]
+ _comingSms[27] + _comingSms[28];
});
//Apply here -
}
#override
void initState() {
initSmsListener();
super.initState();
}
isOTP
? LoginCTA(
//After input otp
onPressed: () async {
print(Provider.of<APIData>(context, listen: false)
.loggedIN);
if (emailEntered &&
otpController.text.length == 6) {
bool res;
try {
res = await widget.signInWithOTP(
contactController.text, otpController.text);
} catch (e) {
res = false;
print(e);
}
if (res) {
Fluttertoast.showToast(
msg: "Verifying OTP...",
toastLength: Toast.LENGTH_SHORT,
gravity: ToastGravity.BOTTOM,
textColor: cardColor,
backgroundColor: primaryTextColor,
fontSize: 16.0,
);
Timer(Duration(seconds: 2), () {
print(Provider.of<APIData>(context,
listen: false)
.loggedIN);
if (Provider.of<APIData>(context,
listen: false)
.loggedIN ==
1) {
Navigator.pop(context);
}
});
}
}
},
btnText: otpButtonText,
isDisabled: isDisabled,
)
: LoginCTA(
//After input mobile number
onPressed: () async {
if (emailEntered &&
contactController.text.length == 10) {
widget.sendOTP(contactController.text);
setState(() {
isOTP = true;
isDisabled = true;
});
} else {
print('kuch na kuch glti');
}
},
btnText: buttonText,
isDisabled: isDisabled,
hasIcon: hasIcon,
),
Just extract the functionality out into its own function. Then you can assign the function to onTap and also call it whenever you like.

Flutter Future<bool>, RX<bool>, and regular bool confusion and how to get the value of one from the other

I'm new to flutter and just learned about GetX so I'm trying to incorporate it into my app as much as possible. In this example I'm trying to get permissions for storage and have a widget reactive if it is or isnt granted to change text and color and such.
My function for calling storage permissions gives back a future like so...
Future<bool> requestStoragePermissions() async {
final storagePermissionStatus = await Permission.storage.request();
if (storagePermissionStatus == PermissionStatus.granted) {
debugPrint('Notification Permission Granted');
return true;
} else if (storagePermissionStatus == PermissionStatus.denied) {
debugPrint('Notification Permission Denied');
} else if (storagePermissionStatus == PermissionStatus.permanentlyDenied) {
debugPrint('Notification Permission Permanently Denied');
await openAppSettings();
}
if (storagePermissionStatus == PermissionStatus.granted) {
return true;
} else {
return false;
}
}
in my permissions screen I have a method to choose which permissions I want depending on the argument sent into the class...
Future<bool> checkPermissions() async {
print('Permission Type: ' + permissionType.toString());
bool statusGranted = false;
if (permissionType == Permission.camera) {
statusGranted = await _permissionController.requestCameraPermission();
} else if (permissionType == Permission.location) {
statusGranted = await _permissionController.requestLocationPermissions();
} else if (permissionType == Permission.notification) {
statusGranted = await _permissionController.requestNotificationPermissions();
} else if (permissionType == Permission.storage) {
statusGranted = await _permissionController.requestStoragePermissions();
}
return Future<bool>.value(statusGranted);
}
I change the return to future but I did have it as just statusGranted as I'm playing around with it. How do I use the value Future in a conditional statement? I keep getting error that I cant compare Future to a bool.
Here I am trying to conditionally set the button icon to be different depending on if permission is granted or not.
SizedBox(
width: 100,
child: _permissionGranted.value == false
? const Icon(
Icons.no_photography,
size: 40,
color: Colors.red,
)
: const Icon(
Icons.camera_alt,
size: 40,
color: Colors.green,
),
),
The _permissionsGranted.value I put in there cause I had checkPermission() == falsa there at first. Now I'm just trying random things and falling further from where I need to be which is why I've come here for help.
On a side note as the Title says. Now we have 3 different Bools to work with. Is there a proper way to use these interchangably?
EDIT:
The checkPermission is getting checked everytime this button gets pressed...
Obx(
() => ElevatedButton(
child: _permissionGranted.value == false ? const Text('Click Me') : const Text('Done'),
onPressed: _permissionGranted.value == false
? () async {
await checkPermissions();
}
: null,
I basically was creating this button inside my screen widget and decided to extract it into its own widget so I could use more of the same button to check different permission checks on the same page.
If you're confused about Futures then I suggest reading up on async programming in Dart as its an important concept to understand. It's a Future because it has to await the process checking the permission before the value of the bool is set.
A Future of any type just means that the value won't be returned until some other process occurs ie...requesting data from some external API or checking permissions etc...
RxBool vs bool is a stream of a boolean vs a regular boolean. Using Obx requires a stream inside of it because its job is to listen to the stream and rebuild when the value of the stream updates. And as you know to access the actual primitive bool you use .value.
In your case, you have a bunch of logic in your screen and that could all live in the GetX class and clean up your UI code. All the UI should care about is the value of controller.permissionGranted
Your Future<bool> checkPermissions() doesn't need to return a bool it just needs to update the value of permissionGranted. All the other functions can be private because the UI doesn't need to know about what checkPermissions() does.
// all of this lives in the GetX class
Future<void> checkPermissions() async {
if (permissionType == Permission.camera) {
permissionGranted.value = await _requestCameraPermission();
} else if (permissionType == Permission.location) {
permissionGranted.value = await _requestLocationPermissions();
} // continue with others...
}
And here's an example of how that could look in the UI
class TestPage extends StatelessWidget {
final controller = Get.find<PermissionController>();
#override
Widget build(BuildContext context) {
return Scaffold(
body: Center(
child: Obx(
() => ElevatedButton(
child: !controller.permissionGranted
.value // note the ! saves from having to write "== false"
? const Text('Click Me')
: const Text('Done'),
onPressed: !controller.permissionGranted.value
? () async {
await controller.checkPermissions();
}
: null),
),
),
);
}
}
After a few more hours beating my head against the wall trying to figure this out I came across a forum that educated me in the fact the I could use async in an onPressed: property. So I created an RX in my permissionsController to change for each permission check I did and used that as the ternary condition to change the widgets behavior. So I had to add this method which takes in the bool as the method finishes successfully
void permissionGranted() {
if (permissionType == Permission.camera) {
_permissionGranted.value = _permissionController.mediaGranted.value;
} else if (permissionType == Permission.location) {
_permissionGranted.value = _permissionController.locationGranted.value;
} else if (permissionType == Permission.notification) {
_permissionGranted.value = _permissionController.notificationsGranted.value;
} else if (permissionType == Permission.storage) {
_permissionGranted.value = _permissionController.storageGranted.value;
}
}
And as I showed in my post edit I now used the checkPermission method inside the ternary statement rather than trying to use is AS the ternary statement.
Obx(
() => ElevatedButton(
child: _permissionGranted.value == false ? const Text('Click Me') : const Text('Done'),
onPressed: _permissionGranted.value == false
? () async {
await checkPermissions();
}
: null,
and here is my updated checkPermission method...
bool statusGranted = false;
Future<bool> checkPermissions() async {
//print('Permission Type: ' + permissionType.toString());
if (permissionType == Permission.camera) {
statusGranted = await _permissionController.requestCameraPermission();
permissionGranted();
} else if (permissionType == Permission.location) {
statusGranted = await _permissionController.requestLocationPermissions();
permissionGranted();
} else if (permissionType == Permission.notification) {
statusGranted = await _permissionController.requestNotificationPermissions();
permissionGranted();
} else if (permissionType == Permission.storage) {
statusGranted = await _permissionController.requestStoragePermissions();
permissionGranted();
}
return statusGranted;
}
Still very much confused about the interchangeability of having 3 different Boolean types to mix and use though. the Future, the RX and the regular bool.

flutter how to terminate all ongoing actions when the back button is pressed?

I want to terminate any currently executing function task when the back button is clicked.How can I do it?(I want to terminate the below function if I press back button)
void getData(String locale, String searchKey, List<String> contentType,
int categoryID, int start, int limit) async {
print('get data');
temp = (await context.read(knowledgeBaseViewModelProvider).getCategoryData(
locale, searchKey, contentType, categoryID, start, limit))!;
_isLoding = false;
if(mounted){
setState(() {
if (temp.length == 0 ) {
isEnd = true;
momAlertBox(
context,
"Alert",
"No More Data.Try Another Category!",
"Oky.",
() => Navigator.pop(context, 'OK'),
);
} else {
isEnd = false;
}
isLodingState = false;
items.addAll(temp);
});
}
}
The back button
BackButton(
onPress: () => {
Navigator.pop(context)},
svgAssetsPath: "assets/icons/icon_back.svg",
height: SizeConfig.devicePixelRatio * 8,
width: SizeConfig.devicePixelRatio * 8,
),

How to toggle on or off SwichTileList based on some condition in Flutter?

I was working with switchTileList in flutter what I exactly want is to ask a user multiple permissions when toggling the switchTileList button and if all permission's granted I want to toggle on the button but if not all permission's granted i want the button to toggle off.
Below is My code but not working properly as i want
void _askPermission() async {
Map<Permission, PermissionStatus> statuses = await [
Permission.camera,
Permission.sms,
Permission.contacts,
Permission.locationAlways,
Permission.microphone,
Permission.storage,
Permission.photos,
].request();
if (statuses[Permission.location]!.isDenied &&
statuses[Permission.camera]!.isDenied &&
statuses[Permission.sms]!.isDenied &&
statuses[Permission.contacts]!.isDenied &&
statuses[Permission.storage]!.isDenied &&
statuses[Permission.photos]!.isDenied) {
print("ALL permission is denied.");
} else if (statuses[Permission.location]!.isGranted &&
statuses[Permission.camera]!.isGranted &&
statuses[Permission.sms]!.isGranted &&
statuses[Permission.contacts]!.isGranted &&
statuses[Permission.storage]!.isGranted &&
statuses[Permission.photos]!.isGranted) {
_isAllPermissionGranted = true;
print("ALL permission is Granted.");
} else {
print("Something Happend");
}
}
SwitchListTile(
// contentPadding: EdgeInsets.all(30),
title: Text(
'Activate All Permission',
),
activeColor: Colors.lightBlue,
activeTrackColor: Colors.blue,
inactiveTrackColor: Colors.blueGrey,
subtitle: Text('Activate the permissions necessary for proper functioning of the application'),
onChanged: (bool value) {
_askPermission();
if(_isAllPermissionGranted){
setState(() => _darkMode = value);
}else if(!_isAllPermissionGranted){
value = false;
setState(() => _darkMode = value);
}
}, value: _darkMode,
You should make your onChanged(bool value) async and await the execution of the _askPermissions() method
Like so
onChanged: (bool value) async { // Make this async
await _askPermission(); // Wait for this to complete and only
//then execute the further code
if(_isAllPermissionGranted){
setState(() => _darkMode = value);
}else if(!_isAllPermissionGranted){
value = false;
setState(() => _darkMode = value);
}
},

How can I leave a function? Dart/Flutter

Hey I have an ElevatedButton with an onPressed. Inside the onPressed are some if-statements that ensure that everything is correct and afterwards I want to push these information to firebase. How can I leave the onPressed function if a condition is not fulfilled? I tried return and return null, return 0 but my App is just freezing.
ElevatedButton(
onPressed: () async {
if (date != null) {
print(date);
} else {
dialog.showAlertDialog(context, 'Oops', 'You didn\'t choose a date!');
return;
}
if (time != null) {
print(time);
} else {
dialog.showAlertDialog(context, 'Oops', 'You didn\'t choose a time!');
return 0;
}
if(combinedDateAndTime.isBefore(DateTime.now())) {
dialog.showAlertDialog(context, 'Oops', 'Your date and time is in the past');
return null;
}
_firestore.collection('foo').add({
'dateTime': combinedDateAndTime,
});
},
style: raisedButtonStyle,
),
),
I just couldn't figure out how to leave the function. I would appreciate any help.
one way is that define a boolean variable and check if it is true then firestore.collection called, somthing like this :
bool var = true;
if (date != null) {
print(date);
} else {
dialog.showAlertDialog(context, 'Oops', 'You didn\'t choose a date!');
var = false;
}
if (time != null) {
print(time);
} else {
dialog.showAlertDialog(context, 'Oops', 'You didn\'t choose a time!');
var = false;
}
if(combinedDateAndTime.isBefore(DateTime.now())) {
dialog.showAlertDialog(context, 'Oops', 'Your date and time is in the past');
var = false;
}
if (var == true){
_firestore.collection('foo').add({
'dateTime': combinedDateAndTime,
});
}