When I tried to change the state from outside the function the state is not changing.
void _showAlertDialog(BuildContext context) {
// flutter defined function
showDialog(
context: context,
builder: (BuildContext context) {
// return object of type Dialog
return AlertDialog(
title: const Text("Diabetes Prediction"),
content: StatefulBuilder(
return _predictedResult == "" ? Column(
mainAxisSize: MainAxisSize.min,
children: [
const CircularProgressIndicator(),
Text(loadingText),
],
) : Text(_predictedResult);
},
),
actions: <Widget>[
// usually buttons at the bottom of the dialog
TextButton(
child: const Text("OK"),
onPressed: () {
Navigator.of(context).pop();
},
),
],
);
},
);
}
Elevated button helps in calling the _showAlertDialog the loadingText is declared inside the class
ElevatedButton(
child: const Text("Predict"),
onPressed: () async {
// Pregnancies, Glucose, Blood Pressure, Insulin, Skin Thickness, Pedigree Function, Weight,
// Height, Age
_predictedResult = "";
loadingText = "";
var data = _formatData();
var result = Serializer().serialize(data);
_showAlertDialog(context);
setState(() {
loadingText = "Sending data to server...";
});
await Future.delayed(const Duration(seconds: 2), (){
});
setState(() {
loadingText = "Analyzing data...";
});
// await Future.delayed(const Duration(seconds: 2), (){
// print("data received");
// });
await _predict(result);
},
),
The output comes as Sending data to server...
String _predictedResult = '';
StreamController<String>? controller;
String loadingText = '';
#override
Widget build(BuildContext context) {
return Scaffold(
backgroundColor: Colors.grey[900],
body: Center(
child: ElevatedButton(
child: const Text("Predict"),
onPressed: () async {
controller = StreamController<String>();
// Pregnancies, Glucose, Blood Pressure, Insulin, Skin Thickness, Pedigree Function, Weight,
// Height, Age
_predictedResult = "";
loadingText = "";
_showAlertDialog(context);
controller!.add("Sending data to server...");
await Future.delayed(const Duration(seconds: 2), () {});
controller!.add("Analyzing data...");
await Future.delayed(const Duration(seconds: 2), () {
print("data received");
});
controller!.add("data received!");
},
),
),
);
}
void _showAlertDialog(BuildContext context) {
// flutter defined function
showDialog(
context: context,
builder: (BuildContext context) {
// return object of type Dialog
return AlertDialog(
title: const Text("Diabetes Prediction"),
content: StreamBuilder(
stream: controller!.stream,
builder: (context, AsyncSnapshot<String> snap) {
return _predictedResult == ""
? Column(
mainAxisSize: MainAxisSize.min,
children: [
const CircularProgressIndicator(),
Text(snap.data ?? "Loading..."),
],
)
: Text(_predictedResult);
},
),
actions: <Widget>[
// usually buttons at the bottom of the dialog
TextButton(
child: const Text("OK"),
onPressed: () {
Navigator.of(context).pop();
},
),
],
);
},
);
}
Use Stream
Flutter Stream Basics for Beginners
Related
Hi in my flutter app have FutureBuilder that return listview, my list listview create some button for update the hive table. when I click the first time on one of buttons everything is run smoothly, but when I click on same button again my hive key turn to null and program show my this error: "type 'Null' is not a subtype of type 'int' "
I write print all over my code but still I do not get it why the key turn null from the second time.
How can I Correct this? please help my.
my Futurebuilder body is:
FutureBuilder<List>(
future: controller.showTaskList(),
builder: (context, snapshot) {
switch (snapshot.connectionState) {
case ConnectionState.waiting:
return SizedBox(
height: Get.height,
child: const Center(
child: CircularProgressIndicator(),
),
);
default:
if (snapshot.hasError) {
return Text('Error: ${snapshot.error}');
} else {
List data = snapshot.data ?? [];
return ListView.separated(
scrollDirection: Axis.vertical,
physics:
const BouncingScrollPhysics(),
shrinkWrap: true,
itemCount: data.length,
itemBuilder: (context, index) {
// controller.taskIconCheckList
// .clear();
for (int i = 0;
i < data.length;
i++) {
if (data[i].status == true) {
controller.taskIconCheckList
.add(true.obs);
} else {
controller.taskIconCheckList
.add(false.obs);
}
}
return ListTile(
leading: Obx(
() => PageTransitionSwitcher(
transitionBuilder: (
child,
primaryAnimation,
secondaryAnimation,
) {
return SharedAxisTransition(
animation:
primaryAnimation,
secondaryAnimation:
secondaryAnimation,
transitionType:
SharedAxisTransitionType
.horizontal,
fillColor:
Colors.transparent,
child: child,
);
},
duration: const Duration(
milliseconds: 800),
child: controller
.taskIconCheckList[
index]
.value
? SizedBox(
child: IconButton(
icon: const Icon(
Icons
.check_circle_rounded,
color: Colors
.lightGreenAccent,
),
onPressed: () {
controller
.functionTaskIconCheckList(
index,
);
print('طول دیتا');
print(data.length.toString());
print('مقدار ایندکس');
print(index.toString());
print('مقدار کلید');
print(data[index].key.toString());
print(data[index].taskText.toString());
controller
.updateStatusTask(
index,
data[index]
.key); // here when i first click // return key currectly, but after that show null and updatestatusetask not run and show error.
},
),
)
: IconButton(
onPressed: () {
controller
.functionTaskIconCheckList(
index,
);
print('طول دیتا');
print(data.length.toString());
print('مقدار ایندکس');
print(index.toString());
print('مقدار کلید');
print(data[index].key.toString());
print(data[index].taskText.toString());
controller
.updateStatusTask(
index,
data[index]
.key); // here when i first click // return key currectly, but after that show null and updatestatusetask not run and show error.
},
icon: const Icon(
Icons
.radio_button_unchecked_outlined,
color: Colors.red,
),
),
),
),
title: Text(data[index].taskText,
style: normalTextForCategory),
subtitle: Text(
data[index]
.date
.toString()
.substring(0, 10),
textDirection:
TextDirection.ltr,
textAlign: TextAlign.right,
style: normalTextForSubtitle,
),
trailing: Row(
mainAxisSize: MainAxisSize.min,
children: [
IconButton(
onPressed: () {
myDefaultDialog(
'هشدار',
'آیا از حذف این گزینه اطمینان دارید؟',
'بله',
'خیر',
() {
Get.back();
mySnakeBar(
'',
'گزینه مورد نظر با موفقیت حذف شد.',
Icons
.warning_amber_rounded,
Colors.yellow);
},
);
},
icon: const Icon(
Icons.delete),
color: Colors.redAccent,
),
IconButton(
onPressed: () {
Get.offNamed(
Routs.editTaskScreen,
arguments: 'edit');
},
icon: const Icon(
Icons.edit_calendar,
color:
Colors.yellowAccent,
),
),
],
),
);
},
separatorBuilder:
(BuildContext context,
int index) {
return const Divider(
height: 2,
color: Colors.white70,
);
},
);
}
}
},
),
this is my functionTaskIconCheckList form controller:
functionTaskIconCheckList(int index) {
taskIconCheckList[index].value = !taskIconCheckList[index].value;}
and this the updatestatusetask function
updateStatusTask(int index,int taskKey) async {
print('در تابع آپدیت ایندکس هست: ${index.toString()}');
print('در تابع آپدیت کی هست: ${taskKey.toString()}');
var taskBox = await Hive.openBox('task');
var filterTask = taskBox.values.where((task) => task.key == taskKey).toList();
Task task = Task(
filterTask[0].taskText,
filterTask[0].date,
taskIconCheckList[index].value,
filterTask[0].deleteStatus,
null,
null,
filterTask[0].taskCatId,
filterTask[0].userId);
await taskBox.put(taskKey, task);}
and this is my showtasklist function:
Future<List> showTaskList() async {
SharedPreferences sharedPreferences = await SharedPreferences.getInstance();
var taskBox = await Hive.openBox('task');
var filterTask = taskBox.values
.where((task) => task.userId == sharedPreferences.getInt('key'))
.toList();
return filterTask;}
this is my model:
#HiveType(typeId: 2)
class Task extends HiveObject{
#HiveField(0)
String taskText;
#HiveField(1)
DateTime date;
#HiveField(2)
bool status;
#HiveField(3)
bool deleteStatus;
#HiveField(4)
int taskCatId;
#HiveField(5)
int userId;
#HiveField(6)
User? user;
#HiveField(7)
TaskCat? taskCat;
Task(this.taskText, this.date, this.status, this.deleteStatus, this.user,
this.taskCat, this.taskCatId, this.userId);
}
One possible solution would be to wait for the Future function to finish and then load the list. If it tries to load the list early before finishing up the Future function, it might presume the value to be null.
Hope this helps.
Still I do not know what is cause this problem, But I found an alternative temporary solution. I create temporary Int list. then just before the return listTile in the futureBuilder body, I write the Loop and save all of the key in that list. finally instead of pass the "data[index].key." I pass my key from that temporary Int list. so everything work fine now
this is my part of code change from before, but still I want know main solution.
return ListView.separated(
scrollDirection: Axis.vertical,
physics:
const BouncingScrollPhysics(),
shrinkWrap: true,
itemCount: data.length,
itemBuilder: (context, index) {
// controller.taskIconCheckList
// .clear();
for (int i = 0;
i < data.length;
i++) {
Get.find<
HomeScreenController>()
.taskKey.add(data[i].key);
if (data[i].status == true) {
Get.find<
HomeScreenController>()
.taskIconCheckList
.add(true.obs);
} else {
Get.find<
HomeScreenController>()
.taskIconCheckList
.add(false.obs);
}
}
return ListTile(
I using qr_code_scanner for scan a qr code & barcodes. Its scanning perfectly. But when i want to use dialog after scan for ask how much product did you scan and after that check it and control it.But when i use textfield inside of dialog and when i tap textfield camera stops working and its stays in black screen. What should i do ? What is wrong ? My codes for scan :
void _onQRViewCreated(QRViewController controller) {
this.controller = controller;
controller.scannedDataStream.listen((scanData) {
controller.pauseCamera();
player.play("scanner_sound.mp3");
inspect(args);
if (args.Barcode == scanData.code) {
showDialog(
context: context,
builder: (context) {
return WillPopScope(
onWillPop: () async {
Navigator.pop(context);
controller.resumeCamera();
return true;
},
child: AlertDialog(
title: const Text('Ürün Giriş'),
content: Column(
children: [
const Text('Bu üründen kaç adet okutuldu ?'),
TextField(
keyboardType: TextInputType.number,
controller: _controller,
),
],
),
actions: <Widget>[
TextButton(
onPressed: () {
bool isTrue = checkScannedCount(int.parse(_controller.text));
if (isTrue) {
var model = args.copyWith(ScannedCount: args.Count);
context.read<ProductCubit>().updateProduct(model);
Navigator.pop(context);
Navigator.pop(context);
} else {
ScaffoldMessenger.of(context).showSnackBar(
const SnackBar(
content: Text("Lütfen sayımı tekrarlayınız."),
),
);
Navigator.pop(context);
controller.resumeCamera(); //Its not starting camera again.
}
},
child: const Text('Tamam')),
],
),
);
});
} else {
showDialog(
context: context,
builder: (context) {
return WillPopScope(
onWillPop: () async {
Navigator.pop(context);
controller.resumeCamera();
return true;
},
child: AlertDialog(
title: const Text('Hatalı Barkod veya Ürün'),
content: const Text('Yanlış ürünü veya barkodu okutuyor olabilirsiniz. Kontrol edip tekrar ediniz.'),
actions: <Widget>[
TextButton(
onPressed: () {
Navigator.pop(context);
controller.resumeCamera();
},
child: const Text('Tamam')),
],
),
);
});
}
});
}
qr_code_scanner no longer supported . Since the underlying frameworks of this package, zxing for android and MTBBarcodescanner for iOS are both not longer maintaned . use mobile_scanner
I'm writing an alertDialog where the user can type a name.
The alertDialog has a "OK" button and a "Annulla" button. I want the "OK" button to be disabled while the textField is empty, and then enabled when the user types something.
I'm using a statefulBuilder as recommended by some answers here on StackOverflow, but clearly my implementation is not working.
// Function to display a dialog to insert a new item to the list
Future<void> _displayItemAddDialog(BuildContext context, provider) async {
String itemName;
// clear the textField and add the item to the list
Future<void> onOKPressed() {
_textFieldController.clear();
Navigator.pop(context);
provider.addItem(itemName);
}
showDialog(
context: context,
builder: (context) {
return StatefulBuilder(
builder: (BuildContext context, StateSetter setState) {
// used to check if to enable the OK button
bool okButtonEnabled = false;
return AlertDialog(
title: Text('Inserisci Nome Oggetto'),
content: TextField(
onChanged: (value) {
itemName = value;
print(value);
// if the TextField is not empty then enable the button
if (value != "") {
// not working :(
setState() => okButtonEnabled = true;
}
},
controller: _textFieldController,
decoration: InputDecoration(hintText: 'Nome'),
),
actions: <Widget>[
TextButton(
onPressed: () {
_textFieldController.clear();
Navigator.pop(context);
},
child: Text('Annulla'),
),
TextButton(
// if button enabled then I change the assigned function
onPressed: okButtonEnabled ? onOKPressed : null,
child: Text('OK')),
],
);
});
});
}
You should move your okButtonEnabled outside StatefulBuilder, so right above it.
showDialog(
context: context,
builder: (context) {
// Move okButtonEnabled here
bool okButtonEnabled = false;
return StatefulBuilder(
builder: (BuildContext context, StateSetter setState) {
return AlertDialog(
title: Text('Inserisci Nome Oggetto'),
content: TextField(
onChanged: (value) {
itemName = value;
print(value);
// if the TextField is not empty then enable the button
if (value != "") {
setState(() => okButtonEnabled = true);
}
},
controller: _textFieldController,
decoration: InputDecoration(hintText: 'Nome'),
),
actions: <Widget>[
TextButton(
onPressed: () {
_textFieldController.clear();
Navigator.pop(context);
},
child: Text('Annulla'),
),
TextButton(
// if button enabled then I change the assigned function
onPressed: okButtonEnabled ? onOKPressed : null,
child: Text('OK')),
],
);
},
);
},
);
I am trying to write a program to check if the time selected by the user already exists in the firebase firestore or not. If it does then I navigate back to the page where they select time again.
But as of now, I am succeeded in sending the date and time to firebase and but not the latter part.
DateTime _eventDate;
bool processing;
String _time;
bool conditionsStatisfied ;
#override
void initState() {
super.initState();
_eventDate = DateTime.now();
processing = false ;
}
inside showDatePicker()
setState(() {
print('inside the setState of listTile');
_eventDate = picked ;
});
inside the button (SAVE):
onPressed: () async {
if (_eventDate != null) {
final QuerySnapshot result = await FirebaseFirestore
.instance
.collection('events')
.where('event_date', isEqualTo: this._eventDate)
.where('selected_time', isEqualTo: this._time)
.get();
final List <DocumentSnapshot> document = result.docs;
if (document.length > 0) {
setState(() {
print('inside the method matching conditions');
showAlertDialogue(context);
});
}else{
final data = {
// "title": _title.text,
'selected_time ': this._time,
"event_date": this._eventDate
};
if (widget.note != null) {
await eventDBS.updateData(widget.note.id, data);
} else {
await eventDBS.create(data);
}
Navigator.pop(context);
setState(() {
processing = false;
});
}
};
some guidance needed on how do I resolve this issue!
Also, because of the else statement now the program won't write the date into firestore.
After Alot of research, I came to realize that if you send the data from calendar in DateTime format then, because of the timestamp at the end of the Date it becomes impossible to match to dates. Hence I formatted the DateTime value into (DD/MM/YYYY).
Here is the rest of the code for reference:
class _AddEventPageState extends State<AddEventPage> {
String _eventDate;
bool processing;
String _time;
#override
void initState() {
super.initState();
// _eventDate = DateTime.now();
processing = false ;
}
#override
Widget build(BuildContext context) {
return Scaffold(
appBar: AppBar(title: Text('Please select a date'),),
body: Column(
children: [
hourMinute30Interval(),
Text('$_time'),
ListView(
scrollDirection: Axis.vertical,
shrinkWrap: true,
children: <Widget>[
ListTile(
title: Text(
'$_eventDate'),
onTap: () async {
DateTime picked = await showDatePicker(context: context,
initialDate: DateTime.now(),
firstDate: DateTime(DateTime.now().year - 1),
lastDate: DateTime(DateTime.now().year + 10),);
if (picked != null) {
setState(() {
print('inside the setState of listTile');
_eventDate = DateFormat('dd/MM/yyyy').format(picked) ;
});
}
},
),
SizedBox(height: 10.0),
ListTile(
title: Center(
child: Text('Select time for appointment!', style: TextStyle(
fontWeight: FontWeight.bold,
fontSize: 20,
),
),
),
),
processing
? Center(child: CircularProgressIndicator())
: Padding(
padding: const EdgeInsets.symmetric(horizontal: 16.0),
child: Material(
elevation: 5.0,
borderRadius: BorderRadius.circular(30.0),
color: Theme
.of(context)
.primaryColor,
child:MaterialButton(
child: Text('SAVE', style: TextStyle(
fontSize: 20,
color: Colors.white,
fontWeight: FontWeight.bold,
)),
onPressed: () async {
if (_eventDate != null) {
AddingEventsUsingRajeshMethod().getAvailableSlots(
_eventDate, _time).then((QuerySnapshot docs) async {
if (docs.docs.length == 1) {
showAlertDialogue(context);
}
else{
final data = {
// "title": _title.text,
'selected_time': this._time,
"event_date": _eventDate,
};
if (widget.note != null) {
await eventDBS.updateData(widget.note.id, data);
} else {
await eventDBS.create(data);
}
Navigator.pop(context);
setState(() {
processing = false;
});
}
});
}
}
),
),
),
],
),
],
),
);
}
showAlertDialogue method :
showAlertDialogue(BuildContext context) {
Widget okButton = FlatButton(onPressed: (){
Timer(Duration(milliseconds: 500), () {
Navigator.push(
context,
MaterialPageRoute(builder: (context) => datePicker()),
);
});
}, child: Text(' OK! '));
AlertDialog alert = AlertDialog(
title: Text('Slot unavailable'),
content: Text('This slot is already booked please select another slot'),
actions: [
okButton,
],
);
showDialog(context: context ,
builder: (BuildContext context){
return alert ;
}
);
}
The hourMinute30Interval() is nothing but a Widget that returns a timePickerSpinner which is a custom Widget. Tap here for that.
The Query that is run after passing the _eventDate and _time is in another class, and it goes as follows :
class AddingEventsUsingRajeshMethod {
getAvailableSlots(String _eventDate , String _time){
return FirebaseFirestore.instance
.collection('events')
.where('event_date', isEqualTo: _eventDate )
.where('selected_time', isEqualTo: _time)
.get();
}
}
You can name it something prettier ;)
I have implemented a function to form submitting.I want to have SnackBar Alert to after submitted. I have tried but it doesn't work.After I added SnackBar routing also doesn't work.
addTicket() async {
if (_formKey.currentState.validate()) {
_formKey.currentState.save();
try{
DocumentReference ref = await db.collection('CostalLineTicketDetails').
document(ticketCato).collection("Tickets").add(
{
'startStation':startStation,
'endStation':endStation,
'price':price,
'ticketType':ticketCato,
'contactNo':contactNo,
'dateTime':dateTime,
});
setState(() => id = ref.documentID);
Navigator.push(context, new MaterialPageRoute(builder: (context) => CostalLine()));
Scaffold.of(context).showSnackBar(SnackBar(content: Text('Ticket Added Sucessfully')));
}catch(e){
print(e);
}
}
}
}
You cannot show showSnackBar on same page after going to another screen.
You can declare _scaffoldKey and pass it to Scaffold like this
final GlobalKey<ScaffoldState> _scaffoldKey = new GlobalKey<ScaffoldState>();
Scaffold(
key: _scaffoldKey,
then open snackbar like this
_scaffoldKey.currentState.showSnackBar(SnackBar(
content: Text(
'Welcome',
),
duration: Duration(seconds: 2),
));
Output:
Edit
You can also use flash where you don't need to pass _scaffoldKey every time.
example:
void _showBasicsFlash({
Duration? duration,
flashStyle = FlashBehavior.floating,
}) {
showFlash(
context: context,
duration: duration,
builder: (context, controller) {
return Flash(
controller: controller,
behavior: flashStyle,
position: FlashPosition.bottom,
boxShadows: kElevationToShadow[4],
horizontalDismissDirection: HorizontalDismissDirection.horizontal,
child: FlashBar(
content: Text('This is a basic flash'),
),
);
},
);
}
try this,
addTicket() async {
if (_formKey.currentState.validate()) {
_formKey.currentState.save();
try{
DocumentReference ref = await
db.collection('CostalLineTicketDetails').
document(ticketCato).collection("Tickets").add(
{
'startStation':startStation,
'endStation':endStation,
'price':price,
'ticketType':ticketCato,
'contactNo':contactNo,
'dateTime':dateTime,
});
setState(() => id = ref.documentID);
// Navigator.push(context, new MaterialPageRoute(builder: (context) => CostalLine()));
Scaffold.of(context).showSnackBar(SnackBar(content:
Text('Ticket Added Sucessfully')));
}catch(e){
print(e);
}
}
}
}
Define this code in any of the generalized dart file, and you can call this function at any place and will display a generic type scaffold.
import 'package:flutter/material.dart';
void showWarningSnackBar(BuildContext context, String message) {
// Find the Scaffold in the widget tree and use it to show a SnackBar.
ScaffoldFeatureController<Widget, dynamic> _scaffold;
// Find the Scaffold in the widget tree and use it to show a SnackBar.
_scaffold = Scaffold.of(context).showSnackBar(SnackBar(
content: InkWell(
onTap: () {
_scaffold.close();
},
child: Row(
mainAxisAlignment: MainAxisAlignment.start,
children: <Widget>[
AppImage.asset(
assetName: YOUR_IMAGE_NAME,
fit: BoxFit.contain,
width: 20,
color: COLOR),
const SizedBox(
width: 10,
),
Text(
'$message',
maxLines: 2,
),
],
),
),
duration: const Duration(seconds: 10),
backgroundColor: COLOR,
));
}