I have a Future function "_doSearch" which fetch data from server and it is working fine.
But when I add a another function inside it to display progress dialog while fetching data from the server the progress dialog is displayed but the Future function stop fetching data!!!
Any body can help ?
Future<List<Property>> _doSearch () async{
showDialog(
context: context,
barrierDismissible: false,
builder: (BuildContext context){
return MyProgressDialog("Please wait...");
}
);
Response response = await get("https://www.example.com/services/?action=search");
if(response.statusCode == 200){
Navigator.pop(context);
var jsonData = json.decode(response.body);
var res = jsonData["results"];
List<Property> results = [];
for (var p in res){
Property unit = Property(p["property_title"], p["property_image"]);
results.add(unit);
}
print(results.length);
return results;
}else{
Navigator.pop(context);
}
}
Use this method
static progressDialog(bool isLoading, BuildContext context) {
AlertDialog dialog = new AlertDialog(
content: new Container(
height: 40.0,
child: new Center(
child: new Row(
crossAxisAlignment: CrossAxisAlignment.center,
children: <Widget>[
new CircularProgressIndicator(),
Padding(padding: EdgeInsets.only(left: 15.0)),
new Text("Please wait")
],
),
)),
contentPadding: EdgeInsets.fromLTRB(15.0, 15.0, 15.0, 15.0),
);
if (!isLoading) {
Navigator.of(context, rootNavigator: true).pop();
} else {
showDialog(
barrierDismissible: false,
context: context,
builder: (BuildContext context) {
return WillPopScope(onWillPop: () {}, child: dialog);
},
useRootNavigator: true,
);
}
}
example:
Constants.progressDialog(true, context);
Response response = await get("https://www.example.com/services/?action=search");
Constants.progressDialog(false, context);
if(response.statusCode == 200){
var jsonData = json.decode(response.body);
var res = jsonData["results"];
List<Property> results = [];
for (var p in res){
Property unit = Property(p["property_title"], p["property_image"]);
results.add(unit);
}
print(results.length);
return results;
}
You are killing the function using return MyProgressDialog("Please wait...");
Modify the code like this
Future<List<Property>> _doSearch () async{
pr = ProgressDialog(context,type: ProgressDialogType.Normal, isDismissible: false);
pr.style(
message: 'Please wait...',
borderRadius: 10.0,
backgroundColor: Colors.white,
progressWidget: CircularProgressIndicator(valueColor: new AlwaysStoppedAnimation<Color>(Colors.orange),),
elevation: 10.0,
insetAnimCurve: Curves.easeInOut,
progressTextStyle: TextStyle(
color: Colors.black, fontSize: 13.0, fontWeight: FontWeight.w400),
messageTextStyle: TextStyle(
color: Colors.black, fontSize: 19.0, fontWeight: FontWeight.w600)
);
await pr.show();
Response response = await get("https://www.example.com/services/?action=search");
if(response.statusCode == 200){
Navigator.pop(context);
var jsonData = json.decode(response.body);
var res = jsonData["results"];
List<Property> results = [];
for (var p in res){
Property unit = Property(p["property_title"], p["property_image"]);
results.add(unit);
}
print(results.length);
pr.hide();
return results;
}else{
pr = ProgressDialog(context,type: ProgressDialogType.Normal, isDismissible: false);
pr.style(
message: 'Please wait...',
borderRadius: 10.0,
backgroundColor: Colors.white,
progressWidget: CircularProgressIndicator(valueColor: new AlwaysStoppedAnimation<Color>(Colors.orange),),
elevation: 10.0,
insetAnimCurve: Curves.easeInOut,
progressTextStyle: TextStyle(
color: Colors.black, fontSize: 13.0, fontWeight: FontWeight.w400),
messageTextStyle: TextStyle(
color: Colors.black, fontSize: 19.0, fontWeight: FontWeight.w600)
);
await pr.show();
Navigator.pop(context);
}
}
Do remember to add and import progress_dialog
Related
I have an elevated button, to which i want to disable it after user hits the button, api gets called here. i have tried to setState but itseems not working. what else can i do to disable button.
hint: my concept i am working is that once ther users clicks the button, again the user should not be able to click again the same button.
Here is my code:
bool isEnable = false;
ElevatedButton.icon(
style: ButtonStyle(
backgroundColor: MaterialStateProperty.all(
const Color.fromARGB(255, 53, 121, 87)),
padding:
MaterialStateProperty.all(const EdgeInsets.all(20)),
textStyle: MaterialStateProperty.all(const TextStyle(
fontSize: 14, color: Colors.black))),
onPressed: qrdata.code != 9 && !isEnable
? () async {
setState(() {
isEnable = true;
});
var url = Uri.parse(
'${ApiConstants.baseUrl}${ApiConstants.updateEndpoint}');
var responseData = await http.put(url,
headers: ApiConstants.headers);
if (responseData.statusCode == 202) {
print(jsonDecode(responseData.body).toString());
// ignore: use_build_context_synchronously
Navigator.push(
context,
MaterialPageRoute(
builder: (context) => Dashboard(
data: widget.data,
)),
);
}
//FocusManager.instance.primaryFocus!.unfocus();
// });
// setState(() {
// isEnable = false;
// });
}
:null,
// : () {},
icon: const Icon(
Icons.home_filled,
),
label: const Text('Entry',
style: TextStyle(
color: Colors.white,
)),
),
Please make sure variable qrdata.code and isEnable are initialized outside the build method. Every time when setState is called one or both the variables are getting reset.
The problem is whenever setState is pressed it is not rebuilding the button state. so to change the button state wrap your button with StatefulBuilder.
and please call your API in try catch.
class DisableButton extends StatefulWidget {
const DisableButton({Key? key}) : super(key: key);
#override
State<DisableButton> createState() => _DisableButtonState();
}
class _DisableButtonState extends State<DisableButton> {
bool isEnable = false;
int qrdata = 1;
#override
Widget build(BuildContext context) {
return Scaffold(
body: Center(
child: StatefulBuilder(
builder:
(BuildContext context, void Function(void Function()) setState) {
return ElevatedButton.icon(
style: ButtonStyle(
backgroundColor: MaterialStateProperty.all(
const Color.fromARGB(255, 53, 121, 87)),
padding: MaterialStateProperty.all(const EdgeInsets.all(20)),
textStyle: MaterialStateProperty.all(
const TextStyle(fontSize: 14, color: Colors.black))),
onPressed: qrdata != 9 && !isEnable
? () async {
setState(() {
isEnable = true;
});
print(">>>> Button is disabled");
try {
final data = await http.get(
Uri.parse(
'https://jsonplaceholder.typicode.com/albums/1'),
);
if (!mounted) return;
Navigator.push(
context,
MaterialPageRoute(
builder: (context) => NextPage(
data: data.body.toString(),
),
),
);
print("Api Data >>>> $data.body");
} catch (e) {
print("Error While fetching data");
}
setState(() {
isEnable = false;
});
print(">>>> Button is enabled");
}
: null,
// : () {},
icon: const Icon(
Icons.home_filled,
),
label: Text(isEnable ? "Disabled" : "Enabled",
style: const TextStyle(
color: Colors.white,
)),
);
},
),
),
);
}
}
class NextPage extends StatelessWidget {
const NextPage({Key? key, required this.data}) : super(key: key);
final String data;
#override
Widget build(BuildContext context) {
return Scaffold(
appBar: AppBar(),
body: Center(child: Text("Data : $data")),
);
}
}
The problem in your code is setting isEnable to true but not resting to false.
ElevatedButton.icon(
style: ButtonStyle(
backgroundColor: MaterialStateProperty.all(
const Color.fromARGB(255, 53, 121, 87)),
padding:
MaterialStateProperty.all(const EdgeInsets.all(20)),
textStyle: MaterialStateProperty.all(const TextStyle(
fontSize: 14, color: Colors.black))),
onPressed: qrdata.code != 9 && !isEnable
? () async {
setState(() {
isEnable = true;
});
var url = Uri.parse(
'${ApiConstants.baseUrl}${ApiConstants.updateEndpoint}');
var responseData = await http.put(url,
headers: ApiConstants.headers);
if (responseData.statusCode == 202) {
print(jsonDecode(responseData.body).toString());
// ignore: use_build_context_synchronously
Navigator.push(
context,
MaterialPageRoute(
builder: (context) => Dashboard(
data: widget.data,
)),
);
}
//FocusManager.instance.primaryFocus!.unfocus();
// });
// setState(() { <---- Uncomment this code.
// isEnable = false;
// });
}
:null,
// : () {},
icon: const Icon(
Icons.home_filled,
),
label: const Text('Entry',
style: TextStyle(
color: Colors.white,
)),
),
Apply this code bellow:
You got error on double equal.
bool variable:
bool isDisabled = false;
Widget
ElevatedButton.icon(
style: ButtonStyle(
backgroundColor: MaterialStateProperty.all(
const Color.fromARGB(255, 53, 121, 87)),
padding:
MaterialStateProperty.all(const EdgeInsets.all(20)),
textStyle: MaterialStateProperty.all(const TextStyle(
fontSize: 14, color: Colors.black))),
onPressed: qrdata.code != 9 && !isDisabled
? () async {
setState(() {
isDisabled = true;
});
var url = Uri.parse(
'${ApiConstants.baseUrl}${ApiConstants.updateEndpoint}');
var responseData = await http.put(url,
headers: ApiConstants.headers);
if (responseData.statusCode == 202) {
print(jsonDecode(responseData.body).toString());
// ignore: use_build_context_synchronously
Navigator.push(
context,
MaterialPageRoute(
builder: (context) => Dashboard(
data: widget.data,
)),
);
}
});
setState(() {
isDisabled = false;
});
}
:null,
I've got an error while i tried to add value to value from firestore.
I want to sum value from kcal variable with firestore "progress" value
progressAdd = nutr + kcal2;
Error screenshot
Future addMeal() async {
var nutr;
await FirebaseFirestore.instance
.collection('usersData')
.doc(FirebaseAuth.instance.currentUser!.uid)
.get()
.then((doc) => {nutr = doc.data()});
print('test');
if (nutr != null) {
this.progress = nutr['progress'];
setState(() {
progressAdd = nutr + kcal2;
FirebaseFirestore.instance
.collection('usersData')
.doc(FirebaseAuth.instance.currentUser!.uid)
.update({'progress': progressAdd});
});
} else {
print('test2');
return showDialog(
context: context,
builder: (context) {
return AlertDialog(
backgroundColor: mainFontColor().tsubColor,
title: Text(
':/',
textAlign: TextAlign.center,
style: GoogleFonts.lato(
fontWeight: FontWeight.w600, color: Colors.white),
),
content: Container(
height: 120,
width: 250,
child: Column(children: [
Text(
'Something went wrong!',
style: GoogleFonts.dosis(color: Colors.white),
),
SizedBox(
height: 5,
),
Text(
'Go back and try again!',
style: GoogleFonts.dosis(color: Colors.white),
),
SizedBox(
height: 20,
),
Container(
height: 40,
width: 180,
child: ElevatedButton(
child: Text('OK'),
style: ElevatedButton.styleFrom(
backgroundColor: mainFontColor().tsubColor2),
onPressed: (() => Navigator.pop(context))),
)
]),
),
);
});
}
}
This line:
.then((doc) => {nutr = doc.data()});
will assign the doc.data() which have a type of Map<String, dynamic> to the nutr variable.
so, this:
progressAdd = nutr + kcal2;
is actually not valid, because you want to make an addition over objects that can't be summed, nutr have a type of Map<String, dynamic> and kcal2 is double.
from the code I read, I assume that you want to get the existing progress on the Firestore document and update it with the sum of it + kcal2, so try the following:
instead of:
progressAdd = nutr + kcal2;
replace with this:
progressAdd = this.progress + kcal2;
this now should be valid that you want to sum to numbers the update in Firestore.
I recently made a button, and I'm wondering how to include a message that says "success" after the button is pressed and data is stored in the firebase.
The button functions as intended and all data is stored in Firebase, as can be seen in the code, but I would want to have a message inside the button or on the screen informing the user that the data has been uploaded successfully.
code -
Container(
height: 60,
width: 290,
padding: EdgeInsets.all(10),
child: ElevatedButton(
style: ElevatedButton.styleFrom(
textStyle: TextStyle(fontSize: 24),
minimumSize: Size.fromHeight(24),
shape: StadiumBorder()),
child: isLoading
? Row(
mainAxisAlignment: MainAxisAlignment.center,
children: const [
CircularProgressIndicator(
color: Colors.white),
SizedBox(width: 10),
Text('Please wait'),
])
: Text(
'Submit',
style: TextStyle(fontSize: 21),
),
onPressed: () async {
Map<String, dynamic> data = {
'Other medication':
_othermedicationController.text,
'Preventer inhaler': _preventController.text,
'Reliever inhaler': _relieverController.text,
'Triggers': _triggersController.text +
(', ') +
_triggersController2.text
};
if (isLoading) return;
FirebaseFirestore.instance
.collection('user')
.doc()
.collection('Medication')
.add(data);
setState(() => isLoading = true);
await Future.delayed(Duration(seconds: 2));
setState(() => isLoading = false);
},
),
),
thank you
you have to make a seperate bool function with a try catch then return true if success else false and reflect the ui accordingly to return value ... some thing like as following : -
Container(
height: 60,
width: 290,
padding: EdgeInsets.all(10),
child: ElevatedButton(
style: ElevatedButton.styleFrom(
textStyle: TextStyle(fontSize: 24),
minimumSize: Size.fromHeight(24),
shape: StadiumBorder()),
child: isLoading
? Row(
mainAxisAlignment: MainAxisAlignment.center,
children: const [
CircularProgressIndicator(
color: Colors.white),
SizedBox(width: 10),
Text('Please wait'),
])
: Text(
'Submit',
style: TextStyle(fontSize: 21),
),
onPressed: () async {
Map<String, dynamic> data = {
'Other medication':
_othermedicationController.text,
'Preventer inhaler': _preventController.text,
'Reliever inhaler': _relieverController.text,
'Triggers': _triggersController.text +
(', ') +
_triggersController2.text
};
if (isLoading) return;
final success = await getData();
if(success) {print('success');}
//show toast or something
},
),
),
Future<bool>getData()async{
bool success = false;
try {
await FirebaseFirestore.instance
.collection('user')
.doc()
.collection('Medication')
.add(data);
setState(() => isLoading = true);
success = true;
}catch(e){
success = false ;
setState(() => isLoading = false;
print(e);
}
return success;
}
I am working on a project and ended up having an error rendering the image from firestore and still do not understand what is exactly the problem. I am very new to Flutter.
Here is how I am uploading it
RoundedButton(
buttonName: 'Add Event',
onPressed: () async{
if(kIsWeb){
await uploadFileWeb().then((value) => showToast(
message: "Events Added Successfully",
color: Colors.green,
));
Navigator.pop(context);
}
else{
await uploadFile().then((value) => showToast(
message: "Events Added Successfully",
color: Colors.green,
));
Navigator.pop(context);
}
},
color: Colors.green,
),
and the functions
Future selectFile() async{
final result = await FilePicker.platform.pickFiles(
type: FileType.custom,
allowMultiple: false,
allowedExtensions: ['jpg']
);
if(result == null) return;
final path = result.files.single.path!;
setState(() {
file = File(path);
});
}
Future uploadFile() async{
if(file == null) return;
final fileName = basename(file!.path);
final destination = 'events/$fileName';
task = await FirebaseApi.uploadFile(destination, file!)!.then((_) async{
DateTime time = DateTime.now();
await FirebaseFirestore.instance.collection('activities').doc().set({
'Name' : name,
'Location': location,
'Description' : description,
'Price' : price,
'Date' : date,
'PhotoUrl': destination,
'Type' : selectedType,
'ts' : time,
});
});
}
void selectWebImage(){
res.FileUploadInputElement uploadInput = res.FileUploadInputElement()..accept = 'image/*';
uploadInput.click();
uploadInput.onChange.listen((event) {
webFile = uploadInput.files!.first;
final reader = res.FileReader();
reader.readAsDataUrl(webFile!);
reader.onLoadEnd.listen((event) {
});
});
}
Future<void> uploadFileWeb()async {
final dateTime = DateTime.now();
final path = 'events/$dateTime';
await FirebaseStorage.instance.refFromURL('gs://tembea-4d3c6.appspot.com')
.child(path)
.putBlob(webFile).then((_) async{
DateTime time = DateTime.now();
await FirebaseFirestore.instance.collection('activities').doc().set({
'Name' : name,
'Location': location,
'Description' : description,
'Price' : price,
'Date' : date,
'PhotoUrl': path,
'Type' : selectedType,
'ts' : time,
});
});
}
}
This is how I am trying to retrieve data
final Stream<QuerySnapshot> activities = FirebaseFirestore
.instance.collection('activities').orderBy('ts', descending: true).snapshots();
StreamBuilder<QuerySnapshot>(
stream: activities,
builder: (BuildContext context, AsyncSnapshot<QuerySnapshot> snapshot){
if(snapshot.connectionState == ConnectionState.waiting){
return const Center(
child: CircularProgressIndicator(),
);
}
final data = snapshot.requireData;
return ListView.builder(
scrollDirection: Axis.vertical,
shrinkWrap: true,
itemCount: data.size,
itemBuilder: (context, index){
if(data.docs[index]['Type'] == 'Event'){
return Column(
children: [
Row(
mainAxisAlignment: MainAxisAlignment.spaceBetween,
children: [
CircleAvatar(
backgroundColor: Colors.transparent,
radius: 40,
backgroundImage: NetworkImage(data.docs[index]['PhotoUrl']),
),
Text( data.docs[index]['Name'], style:const TextStyle(
color: Colors.white,
fontSize: 20,
fontWeight: FontWeight.bold),
),
Responsive.isWeb(context) ? ButtonBlue(
addLabel: 'Edit Event',
color: Colors.green,
onPressed: (){},
icon: const Icon(IconData(61161, fontFamily: 'MaterialIcons')),
) : InkWell(
onTap: (){},
child: const Icon(IconData(61161, fontFamily: 'MaterialIcons')),
),
Responsive.isWeb(context) ? ButtonBlue(
addLabel: 'Delete Event',
color: Colors.red,
onPressed: (){},
icon: const Icon(Icons.delete_outline,),
): InkWell(
onTap: (){},
child: const Icon(Icons.delete_outline,),
),
],
),
const Divider(
color: Colors.white70,
height:40.0,
),
],
);
}
return Container();
});
},
)
It keeps bringing me this error and I don't know what to do
Invalid argument(s): No host specified in URI file:///events/2021-11-16%2002:59:15.764
I have been on this the entire day and seem not to understand. Can anyone help me on this?
On Firestore you are saving document with final path = 'events/$dateTime'; as PhotoUrl, when retrieving it you are reading the string events/$dateTime and trying to use it as a URI for a NetworkImage.
NetworkImage is then trying to create a URI from that string which results in a local file uri and fails to download it from the network.
Basically, from what I see, you're not actually uploading a picture, but it's difficult to say without the complete code flow.
I am trying to show an CircularProgressIndicator whenever user presses on register button, here is my code:
onPressed: () async{
if (_email.isNotEmpty && _password.isNotEmpty) {
startProgressIndicator();
FirebaseAuth mAuth = FirebaseAuth.instance;
UserCredential credential = await mAuth.createUserWithEmailAndPassword(email: _email, password: _password);
print(credential.user!.email);
//stopProgressIndicator();
} else {
ScaffoldMessenger.of(context).showSnackBar(SnackBar(
content: Text(
"Please enter all information!",
style: TextStyle(
color: Colors.white,
fontSize: 15,
fontWeight: FontWeight.bold
),
),
backgroundColor: Colors.black,
elevation: 5,
duration: Duration(
seconds: 3
),
action: SnackBarAction(
label: "close",
onPressed: (){
ScaffoldMessenger.of(context).hideCurrentSnackBar();
},
),
));
}
startProgressIndicator():
CircularProgressIndicator startProgressIndicator() {
return CircularProgressIndicator(
valueColor: AlwaysStoppedAnimation<Color>(Colors.orange),
backgroundColor: Colors.black,
strokeWidth: 5,
);
}
stopProgressIndicator():
CircularProgressIndicator stopProgressIndicator() {
return CircularProgressIndicator(
value: 0,
);
}
The loading icon doesn't appear at all.
All colors are correct(i.e. background color and progress bar color are different)
What is the issue here?
EDIT: I added the following code but it still isn't working:
Column(
children: [
<Other widgets>
Visibility(
visible: _isProgressVisible,
child: CircularProgressIndicator(),
)
]
)
and I set _isProgressVisible to true and false:
if (_email.isNotEmpty && _password.isNotEmpty) {
setState(() {
_isProgressVisible = true;
});
FirebaseAuth mAuth = FirebaseAuth.instance;
UserCredential credential = await mAuth.createUserWithEmailAndPassword(email: _email, password: _password);
print(credential.user!.email);
setState(() {
_isProgressVisible = false;
});
}
You are not showing the returned widget anywhere, startProgressIndicator() returns the widget but you're just calling not rendering it,
Either use like this
showCupertinoDialog(
useRootNavigator: true,
barrierDismissible: false,
context: context,
builder: (context) {
return startProgressIndicator();
},
);
If you want to show that somewhere else you can do that like this
Container(
margin: const EdgeInsets.all(16),
child: Column(children: [
Visibility(
visible: showIndicator,
child: startProgressIndicator()),
const SizedBox(height: 10),
RaisedButton(
child: const Text('Here'),
onPressed: () => setState(() => showIndicator = !showIndicator),
)
]),
);
return startProgressIndicator();
That's just simple mistake
You have to return widget;