Error : Failed to detect image file format using the file header. File header was [0x3c 0x68 0x74 0x6d 0x6c 0x3e 0x0a 0x20 0x20 0x20] - flutter

I'm trying to display an image from Firestore in to my UI. But it returns the error above, and the file format also changes when I run it on Edge (not on physical device or Emulator). I can't figure out how. Here's my code.
class ViewPola extends StatefulWidget {
const ViewPola({Key? key}) : super(key: key);
static String id = 'view_pola';
#override
State<ViewPola> createState() => _ViewPolaState();
}
class _ViewPolaState extends State<ViewPola> {
Function getSnaps = () async {
final polaMap = {
'Kode Pola': '',
'Bagian Pola': '',
'image_url': '',
};
FirebaseFirestore.instance
.collection('PolaWillyJKT')
.limit(1)
.get()
.then((snapshot) {
if (snapshot.size == 0) {
FirebaseFirestore.instance.collection('PolaWillyJKT').add(polaMap);
FirebaseFirestore.instance.collection('PolaWillyJKT');
print('add');
} else {
print('disini nge get');
var a = FirebaseFirestore.instance.collection('PolaWillyJKT').get();
Map<String, dynamic> data = a as Map<String, dynamic>;
print(data);
}
});
};
var _selectedItem;
var _showList = false;
#override
void initState() {
getSnaps();
super.initState();
}
final Stream<QuerySnapshot> _polaWilly =
FirebaseFirestore.instance.collection('PolaWillyJKT').snapshots();
#override
Widget build(BuildContext context) {
final screenHeight = ScreenInfo.screenHeight(context);
final screenWidth = ScreenInfo.screenWidth(context);
return StreamBuilder<QuerySnapshot>(
stream: _polaWilly,
builder: (BuildContext context, AsyncSnapshot<QuerySnapshot> snapshot) {
if (snapshot.hasError) {
return Text('Something went wrong');
}
if (snapshot.connectionState == ConnectionState.waiting) {
return Text("Loading");
}
return SafeArea(
child: Scaffold(
body: Padding(
padding: EdgeInsets.all(25),
child: Column(
mainAxisSize: MainAxisSize.min,
crossAxisAlignment: CrossAxisAlignment.center,
children: [
const Text(
'Pilih Bagian Pola',
style: TextStyle(fontSize: 25),
),
const SizedBox(
height: 20,
),
DropdownButton(
isExpanded: true,
value: _selectedItem,
items: snapshot.data?.docs
.map(
(value) => DropdownMenuItem(
value: value.get("Bagian Pola"),
child: Text('${value.get("Bagian Pola")}'),
),
)
.toList(),
onChanged: (newValue) {
setState(() {
_selectedItem = newValue.toString();
_showList = true;
});
}),
Padding(
padding: const EdgeInsets.all(25),
child: Visibility(
visible: _showList,
child: Container(
height: screenHeight * 0.4,
child: ListView(
children: snapshot.data!.docs
.where(
(e) => e.get("Bagian Pola") == _selectedItem)
.map((DocumentSnapshot document) {
Map<String, dynamic> data =
document.data()! as Map<String, dynamic>;
return Center(
child: Column(
children: [
Text(
'Bagian Pola: ${data["Bagian Pola"]}',
style: TextStyle(fontSize: 15),
),
const SizedBox(
height: 15,
),
Text(
'Kode Pola : ${data["Kode Pola"]}',
style: TextStyle(fontSize: 15),
),
const SizedBox(
height: 15,
),
Image(
image:
NetworkImage(document.get("Foto Pola")),
height: 200,
width: 200,
), // this is the Image widget where I tried to put the image from firestore
Text(document.get('Foto Pola').toString()),
],
),
);
}).toList(),
),
),
),
),
],
),
),
),
);
},
);
}
}
and here's the class that uploads the image to Firestore
class Input_Pola extends StatefulWidget {
const Input_Pola({Key? key}) : super(key: key);
static String id = 'input_pola';
#override
State<Input_Pola> createState() => _Input_PolaState();
}
class _Input_PolaState extends State<Input_Pola> {
final GlobalKey<ScaffoldState> _scaffoldKey = GlobalKey<ScaffoldState>();
void _checkDuplicate() {
if (options.contains(_textfieldValue.text)) {
// Display bottom sheet that says item already exists
_scaffoldKey.currentState?.showBottomSheet((context) => Container(
height: 300,
child: Column(
children: [
const Text('Item already exists'),
TextButton(
onPressed: () {
Navigator.pop(context);
},
child: Text('Dismiss'))
],
),
));
} else {
// Add item to options list
setState(() {
options.add(_textfieldValue.text);
});
}
}
XFile? image;
final ImagePicker picker = ImagePicker();
String _image_url = '';
void _addToFirebase(String dropdownValue, String _kodePolaController) {
var imageFile = File(image!.path);
String fileName = pth.basename(imageFile.path);
FirebaseStorage storage = FirebaseStorage.instance;
Reference ref = storage.ref().child("WillyJKT/polaWillyJKT");
UploadTask uploadTask = ref.putFile(imageFile);
uploadTask.whenComplete(() async {
var url = await ref.getDownloadURL();
_image_url = url.toString();
});
FirebaseFirestore.instance
.collection('PolaWillyJKT')
.doc(_selectedOption)
.set({
'Bagian Pola': _selectedOption,
'Kode Pola': _kodePolaController,
'Foto Pola': _image_url
});
}
String _dropdownValue = 'kg';
String _property1 = '';
String _property2 = '';
String _property3 = '';
bool _isOptionSelected = false;
final TextEditingController _kodePolaController = TextEditingController();
var _selectedOption;
final TextEditingController _textfieldValue = TextEditingController();
final List<String> options = [];
#override
void initState() {
super.initState();
_selectedOption = options.isNotEmpty ? options[0] : null;
}
//we can upload image from camera or from gallery based on parameter
Future getImage(ImageSource media) async {
var img = await picker.pickImage(source: media);
setState(() {
image = img;
});
}
void myAlert() {
showDialog(
context: context,
builder: (BuildContext context) {
return AlertDialog(
shape:
RoundedRectangleBorder(borderRadius: BorderRadius.circular(8)),
title: Text('Please choose media to select'),
content: Container(
height: MediaQuery.of(context).size.height / 6,
child: Column(
children: [
ElevatedButton(
//if user click this button, user can upload image from gallery
onPressed: () {
Navigator.pop(context);
getImage(ImageSource.gallery);
},
child: Row(
children: [
Icon(Icons.image),
Text('From Gallery'),
],
),
),
ElevatedButton(
//if user click this button. user can upload image from camera
onPressed: () {
Navigator.pop(context);
getImage(ImageSource.camera);
},
child: Row(
children: [
Icon(Icons.camera),
Text('From Camera'),
],
),
),
],
),
),
);
});
}
#override
Widget build(BuildContext context) {
final screenHeight = ScreenInfo.screenHeight(context);
final screenWidth = ScreenInfo.screenWidth(context);
return SafeArea(
child: Scaffold(
key: _scaffoldKey,
floatingActionButton: FloatingActionButton(
child: const Icon(Icons.add),
onPressed: () {
_addToFirebase(_dropdownValue, _kodePolaController.text);
},
),
body: SingleChildScrollView(
child: Padding(
padding: const EdgeInsets.all(25),
child: Container(
height: screenHeight,
child: Column(
mainAxisAlignment: MainAxisAlignment.start,
crossAxisAlignment: CrossAxisAlignment.center,
children: [
TextFormField(
decoration: const InputDecoration(
hintText: 'Input Pola',
border: UnderlineInputBorder(),
),
onChanged: (value) {
setState(() {
_textfieldValue.text = value;
});
},
),
DropdownButton<String>(
value: _selectedOption,
onChanged: (value) {
setState(() {
_selectedOption = value!;
_isOptionSelected = true;
_kodePolaController.clear();
});
},
hint: const Text('Input from Text Field Above'),
items: options.map((option) {
return DropdownMenuItem<String>(
value: option,
child: Text(option),
);
}).toList(),
),
TextButton(
onPressed: _checkDuplicate,
child: const Text("Add Option"),
),
Visibility(
visible: _isOptionSelected,
child: Expanded(
child: Column(
mainAxisAlignment: MainAxisAlignment.start,
crossAxisAlignment: CrossAxisAlignment.center,
children: <Widget>[
TextField(
controller: _kodePolaController,
decoration: const InputDecoration(
labelText: "Kode Pola"),
onChanged: (value) {
setState(() {
_property1 = value;
});
},
),
const SizedBox(height: 20,),
ElevatedButton(
onPressed: () {
myAlert();
},
child: Text('Upload Photo'),
),
SizedBox(
height: 10,
),
//if image not null show the image
//if image null show text
image != null
? Padding(
padding:
const EdgeInsets.symmetric(horizontal: 20),
child: ClipRRect(
borderRadius: BorderRadius.circular(8),
child: Image.file(
//to show image, you type like this.
File(image!.path),
fit: BoxFit.cover,
width: MediaQuery.of(context).size.width,
height: 300,
),
),
)
: const Text(
"No Image",
style: TextStyle(fontSize: 20),
),
],
),
),
)
],
),
),
),
),
),
);
}
}
It also displays the error on Edge, but when I build the apk and run it on my physical device, it just shows nothing on the screen except for the data that's got above it. Any idea on how I can fix this?

var a = FirebaseFirestore.instance.collection('PolaWillyJKT').get();
This returns a promise but not the actual data. In fact it could still be fetching the data when you attempt to convert it to a map.
You can await
var a = await FirebaseFirestore.instance.collection('PolaWillyJKT').get();
myDoc = a.docs.first();
Or use a callback that will run once the collection fetch completes:
FirebaseFirestore.instance.collection('PolaWillyJKT').get().then((response) => {
print(response);
});

Related

flutter firestore - How to retrieve the new document id after adding to firestore

I want to retrieve the new created document id and display the document data in a new page. How can i get the document id? When onPressed() the elevated button, I want to retrieve the document data based on its id.
How can I bring the document id from addDiagnose(_type, _symptomsResult) so that I can navigate it to another page.
Navigator.push(
context,
MaterialPageRoute(
builder: (context) => DiagnosisPage(documentId: documentId),
)
);
This is my current code.
import 'package:cloud_firestore/cloud_firestore.dart';
import 'package:firebase_auth/firebase_auth.dart';
import 'package:flutter/material.dart';
import 'package:multiselect_formfield/multiselect_formfield.dart';
import 'package:petbuddies/user/diagnosis/diagnose_history.dart';
import 'package:petbuddies/user/diagnosis/diagnosis.dart';
class CheckerPage extends StatefulWidget {
const CheckerPage({Key? key}) : super(key: key);
#override
_CheckerPageState createState() => _CheckerPageState();
}
class _CheckerPageState extends State<CheckerPage> {
//retrieve options
final _formKey = GlobalKey<FormState>();
void _petTypeDropDownItemSelected(String newValueSelected) {
setState(() {
petType = newValueSelected;
});
}
clearText(){
_symptoms?.clear();
}
#override
void initState(){
super.initState();
_symptoms = [];
_symptomsResult = [];
}
List? _symptoms;
late List<dynamic> _symptomsResult;
var petType;
var _type;
final Stream<QuerySnapshot> petTypeStream = FirebaseFirestore.instance.collection('pet type').orderBy('name').snapshots();
final Stream<QuerySnapshot> symptomsStream = FirebaseFirestore.instance.collection('symptoms').orderBy('name').snapshots();
DocumentReference diagnosis = FirebaseFirestore.instance.collection('diagnosis').doc();
//store the diagnosis result
User? user = FirebaseAuth.instance.currentUser;
Future<void> addDiagnose(_type, _symptomsResult) async {
String petChosen = this._type;
List symptomsChosen = this._symptomsResult.toList();
QuerySnapshot<Map<String, dynamic>> snapshot =
await FirebaseFirestore.instance.collection("disease")
.where('petType',isEqualTo: petChosen)
.where('symptoms',arrayContainsAny: symptomsChosen)
.get();
List<String> diseaseRef = snapshot.docs.map((e) => e.id).toList();
String createdby = user!.uid;
Timestamp date = Timestamp.now();
List possibleDisease = diseaseRef.toList();
final data = {
'created by': createdby,
'date': date,
'pet chosen': petChosen,
'symptoms chosen': symptomsChosen,
'possible disease': possibleDisease,
};
//set document data
return diagnosis
.set(data)
.then((value) => print('Diagnose Report Added'))
.catchError((error)=>print("Failed to add: $error")
);
}
#override
Widget build(BuildContext context) {
return Scaffold(
appBar: AppBar(
backgroundColor: Colors.blue[900],
title: const Text("Pet Symptoms Checker",
style: TextStyle(color: Colors.white),
),
),
body: Form(
key: _formKey,
child: Padding(
padding: const EdgeInsets.symmetric(vertical: 20, horizontal: 30),
child: ListView(
children: [
Align(
alignment: Alignment.bottomRight,
child: TextButton(
child: const Text(
'History',
style: TextStyle(fontSize: 18),
),
onPressed: (){
Navigator.push(context, MaterialPageRoute(builder: (context) => const DiagnoseHistoryPage(),));
},
),
),
Container(
padding: const EdgeInsets.all(12.0),
decoration: BoxDecoration(
border: Border.all(width: 3, color: Colors.indigo,),
borderRadius: const BorderRadius.all(Radius.circular(30)),
),
child: Column(
children: [
StreamBuilder<QuerySnapshot>(
stream: petTypeStream,
builder: (context, snapshot) {
if (!snapshot.hasData) {
return const Center(
child: CircularProgressIndicator(),
);
}
return Container(
padding: const EdgeInsets.only(bottom: 16.0),
child: Row(
children: <Widget>[
Expanded(
flex: 2,
child: Container(
padding: const EdgeInsets.fromLTRB(12.0, 10.0, 10.0, 10.0),
child: const Text(
"Pet Type",
style: TextStyle(fontSize: 20),
),
),
),
Expanded(
flex: 3,
child: Row(
children: [
const SizedBox(width: 30,),
DropdownButton(
value: petType,
onChanged: (valueSelectedByUser) {
_petTypeDropDownItemSelected(valueSelectedByUser.toString());
},
hint: const Text('Choose Pet Type',),
underline: Container(),
items: snapshot.data!.docs.map((DocumentSnapshot document) {
return DropdownMenuItem<String>(
value: document.get('name'),
child: Text(document.get('name')),
);
}).toList(),
),
],
),
),
],
),
);
}),
StreamBuilder(
stream: symptomsStream,
builder: (BuildContext context, AsyncSnapshot<QuerySnapshot> snapshot){
if(snapshot.hasError){
print('Something went wrong');
}
if(snapshot.connectionState == ConnectionState.waiting){
return const Center(
child: CircularProgressIndicator(),
);
}
final List symptomsList = [];
snapshot.data!.docs.map((DocumentSnapshot document){
Map a = document.data() as Map<String, dynamic>;
symptomsList.add(a['name']);
a['id'] = document.id;
}).toList();
return MultiSelectFormField(
autovalidate: AutovalidateMode.disabled,
chipBackGroundColor: Colors.blue[900],
chipLabelStyle: const TextStyle(fontWeight: FontWeight.bold, color: Colors.white),
dialogTextStyle: const TextStyle(fontWeight: FontWeight.bold),
checkBoxActiveColor: Colors.blue[900],
checkBoxCheckColor: Colors.white,
dialogShapeBorder: const RoundedRectangleBorder(
borderRadius: BorderRadius.all(Radius.circular(12.0))),
title: const Text(
"Symptoms",
style: TextStyle(fontSize:20),
),
validator: (value) {
if (value == null || value.length == 0) {
return 'Please select one or more symptoms';
}
return null;
},
dataSource: [
for (String i in symptomsList) {'value' : i}
],
textField: 'value',
valueField: 'value',
okButtonLabel: 'OK',
cancelButtonLabel: 'CANCEL',
hintWidget: const Text('Please choose one or more symptoms'),
initialValue: _symptoms,
onSaved: (value) {
if (value == null) return;
setState(() {
_symptoms = value;
}
);
},
);
}
),
const SizedBox(height:50,),
Row(
mainAxisAlignment: MainAxisAlignment.spaceAround,
children: [
ElevatedButton(
onPressed: () async{
if(_formKey.currentState!.validate()){
setState(() {
_type = petType.toString();
_symptomsResult = _symptoms!.toList();
addDiagnose(_type,_symptomsResult);
final documentId = diagnosis.id;
Navigator.push(
context,
MaterialPageRoute(
builder: (context) => DiagnosisPage(documentId: documentId),
)
);
clearText();
}
);
}
},
child: const Text(
'Diagnose',
style: TextStyle(fontSize: 18),
),
style: ElevatedButton.styleFrom(primary: Colors.blue[900]),
),
],
),
],
),
)
],
),
),
),
);
}
}

How to provide filled places in Flutter

First I want to introduce the pages.
Form Page
This is where I fill a form. When I click save as draft it will save the form data to the SQLite database. For now, I haven't implemented SQLite yet. Anyway, But I have a list that buffers the form input. When you click on Save as draft, I create a FormData object and add that data to a list and provide that list with Provider.
Form Page Code
class FormPage extends StatefulWidget {
FormData? formData = FormData();
FormPage({Key? key, this.formData}) : super(key: key);
#override
State<FormPage> createState() => _HomePageState();
}
class _HomePageState extends State<FormPage> {
String? isEmpty(String val) {
String? text;
setState(() {
if (val.isEmpty) {
text = 'Boş bırakılamaz';
}
});
return text;
}
#override
Widget build(BuildContext context) {
return Scaffold(
backgroundColor: const Color(0xffffe0b2),
appBar: AppBar(
// backgroundColor: Colors.teal.shade400,
title: const Text('Hasta Etkileşim Kaydı'),
centerTitle: true,
backgroundColor: const Color(0xffffb74d),
elevation: 0,
),
body: SafeArea(
child: FutureBuilder(
future: readJsonData(),
builder: (context, snapshot) {
if (snapshot.hasError) {
return Text(snapshot.error.toString());
} else if (snapshot.hasData) {
var items = snapshot.data as List<dynamic>;
var listStajTuru = items[0].stajTuruItems;
var listCinsiyet = items[0].cinsiyetItems;
var listEtkilesim = items[0].etkilesimTuruItems;
var listKapsam = items[0].kapsamItems;
var listOrtam = items[0].ortamItems;
var listDoktor = items[0].doktorItems;
return Form(
key: _formKey,
child: ListView(
shrinkWrap: true,
children: [
myDropDownContainer(_valueStajTuru, listStajTuru,
hintTextStajTuru, onChangedStajTuru),
myDropDownContainer(_valueDoktor, listDoktor,
hintTextDoktor, onChangedDoktor),
myDropDownContainer(_valueCinsiyet, listCinsiyet,
hintTextCinsiyet, onChangedCinsiyet),
myDropDownContainer(_valueEtkilesim, listEtkilesim,
hintTextEtkilesim, onChangedEtkilesim),
myDropDownContainer(_valueKapsam, listKapsam,
hintTextKapsam, onChangedKapsam),
myDropDownContainer(_valueOrtam, listOrtam,
hintTextOrtam, onChangedOrtam),
myTextFieldRow(20, "Kayıt No: ", 10,
_formData.setKayitNo, isEmpty),
myTextFieldRow(
20, "Hastanın Yaşı:", 3, _formData.setYas, isEmpty),
myTextFieldRow(
20, "Şikayet:", 10, _formData.setSikayet, isEmpty),
myTextFieldRow(50, "Ayırıcı Tanı:", 50,
_formData.setAyiriciTani, isEmpty),
myTextFieldRow(50, "Kesin Tanı:", 50,
_formData.setKesinTani, isEmpty),
myTextFieldRow(50, "Tedavi Yöntemi:", 100,
_formData.setTedaviYontemi, isEmpty),
const SizedBox(
height: 20,
),
Row(
mainAxisAlignment: MainAxisAlignment.spaceBetween,
children: [
submitButton(context, "Sava as Draft"),
submitButton(context, "GÖNDER"),
],
),
],
),
);
} else {
return const Center(
child: CircularProgressIndicator(),
);
}
})),
);
}
//Kullanıcı kaydet butonuna basarsa local olarak kaydedecek
Container submitButton(BuildContext context, String title) {
return Container(
width: 120,
height: 50,
margin: const EdgeInsets.all(12),
child: TextButton(
onPressed: () {
setState(() {
if (_formKey.currentState!.validate()) {
Provider.of<FormAdd>(context, listen: false)
.addNewFormToList(_formData);
alertDialog(context).then((_) =>_formKey.currentState!.reset());
}
});
},
child: Text(
title,
style: kTextStyle.copyWith(
fontSize: 14, color: Colors.white, fontWeight: FontWeight.bold),
),
style: ButtonStyle(
backgroundColor: MaterialStateProperty.all<Color>(
const Color(0xffffa726),
),
),
),
);
}
//DropDownWidget
Container myDropDownContainer(String initialVal, List<String> listItems,
String text, Function myFunc) {
return Container(
margin: const EdgeInsets.all(8),
child: Row(
mainAxisSize: MainAxisSize.min,
mainAxisAlignment: MainAxisAlignment.start,
children: [
SizedBox(
width: 120,
child: Text(
text,
style: kTextStyle,
),
),
const SizedBox(
width: 20,
),
Expanded(
child: Container(
height: 50,
decoration: BoxDecoration(
color: Colors.orangeAccent,
borderRadius: BorderRadius.circular(5)),
child: DropdownButtonFormField<String>(
// autovalidateMode: AutovalidateMode.always,
//menuMaxHeight: 300,
validator: (value) {
if (value!.isEmpty) {
return "485s4a8sd4as85";
}
},
decoration: const InputDecoration(border: InputBorder.none),
isExpanded: true,
//onTap: () => myFunc,
//borderRadius: BorderRadius.circular(5),
value: initialVal,
icon: const Icon(
Icons.arrow_downward,
color: Colors.black38,
),
iconSize: 24,
elevation: 16,
dropdownColor: Colors.deepOrange,
style: kTextStyle.copyWith(color: Colors.black),
onChanged: (val) => myFunc(val),
items: listItems.map<DropdownMenuItem<String>>((String? val) {
return DropdownMenuItem(
//TODO: Set default values
value: val == null ? val = initialVal : val = val,
child: Text(
val,
style: kTextStyle.copyWith(color: Colors.black),
),
);
}).toList(),
),
),
)
],
),
);
}
//TextFieldWidget
Row myTextFieldRow(double height, String text, int? maxLength,
Function function, Function regexFunction) {
return Row(
mainAxisSize: MainAxisSize.min,
children: [
SizedBox(
width: 80,
height: height,
child: Text(
text,
style: kTextStyle.copyWith(color: Colors.black54),
),
),
const SizedBox(
width: 10,
),
Expanded(
child: TextFormField(
validator: (value) => regexFunction(value),
// focusNode: FocusNode(),
onChanged: (input) {
function(input);
},
autofocus: false,
textAlignVertical: TextAlignVertical.bottom,
style: kTextStyle.copyWith(fontSize: 16),
maxLength: maxLength,
maxLines: null, //TODO:Arrange maxlines for the inputs
decoration: InputDecoration(
isDense: true,
contentPadding: EdgeInsets.fromLTRB(0, 0, 0, height),
border: const OutlineInputBorder(
borderSide: BorderSide(color: Colors.green),
borderRadius: BorderRadius.all(Radius.circular(3))),
// labelStyle:kTextStyle.copyWith(fontSize: 16, color: Colors.white54),
),
),
),
],
);
}
Future<List<FormContent>> readJsonData() async {
final jsonData =
await rootBundle.rootBundle.loadString('assets/json/formdata.json');
return [
for (final e in json.decode(jsonData)) FormContent.fromJson(e),
];
}
final _formKey = GlobalKey<FormState>();
final FormData _formData = FormData();
String _valueEtkilesim = "Gözlem";
String _valueKapsam = "Öykü";
String _valueOrtam = "Poliklinik";
String _valueDoktor = "Diğer";
String _valueStajTuru = "Ortopedi";
String _valueCinsiyet = "Erkek"; // initial value
final String hintTextCinsiyet = "Cinsiyet:";
final String hintTextStajTuru = "Staj Türü:";
final String hintTextEtkilesim = "Etkileşim Türü:";
final String hintTextKapsam = "Kapsam:";
final String hintTextOrtam = "Gerçekleştiği Ortam:";
final String hintTextDoktor = "Klinik Eğitici:";
void onChangedCinsiyet(String? newVal) {
setState(() {
_valueCinsiyet = newVal!;
_formData.setCinsiyet(_valueCinsiyet);
});
}
void onChangedStajTuru(String newVal) {
setState(() {
_valueStajTuru = newVal;
_formData.setStajTuru(newVal);
});
}
void onChangedEtkilesim(String newVal) {
setState(() {
_valueEtkilesim = newVal;
_formData.setEtkilesimTuru(newVal);
});
}
void onChangedKapsam(String newVal) {
setState(() {
_valueKapsam = newVal;
_formData.setKapsam(newVal);
});
}
void onChangedOrtam(String newVal) {
setState(() {
_valueOrtam = newVal;
_formData.setOrtam(newVal);
});
}
void onChangedDoktor(String newVal) {
setState(() {
_valueDoktor = newVal;
_formData.setDoktor(newVal);
});
}
}
Assume, we saved the form as a draft. Now, It is in the DraftsPage.
Drafts Page
Everything is alright up to now. I have a list of the saved in draft forms. When I click on any list item I could get the form information (3rd picture).
Here is the question.
When I click on the Edit button. I want to renavigate to the Form Page.However this time I want to fill the places with the relevant data. For instance, this time Kayıt No: TextField shouldn't be empty it must be filled with 555, because it was saved to draft. And unfilled places must be blank. I know I need to provide an object of the form(formData) but, I couldn't manage it. When I click on the Edit button. I should provide that object and use it in the Form Page to fill those forms. But, how?
Draft Code
class Drafts extends StatelessWidget {
#override
Widget build(BuildContext context) {
void pushToFormPage(FormData formData) {
Navigator.push(
context,
MaterialPageRoute(
builder: (context) => FormView(
formData: formData,
)));
}
List<FormData> _forms = Provider.of<FormAdd>(context).getForms();
return Scaffold(
backgroundColor: Colors.grey,
appBar: AppBar(
title: const Text("Taslaklar"),
centerTitle: true,
),
body: ListView.separated(
separatorBuilder: (BuildContext context, int index) => const Divider(
height: 5,
color: Colors.blueAccent,
),
itemCount: _forms.length,
itemBuilder: (BuildContext context, int index) {
return studentListViewInstanceContainer(
const Color.fromARGB(200, 200, 130, 240),
pushToFormPage,
_forms[index], context);
},
),
);
}
}
GestureDetector studentListViewInstanceContainer(
Color color, Function function, FormData formData,BuildContext context) {
return GestureDetector(
onTap: () => function(formData),
child: Container(
height: 100,
color: color,
child: Column(
crossAxisAlignment: CrossAxisAlignment.start,
mainAxisAlignment: MainAxisAlignment.spaceBetween,
children: [
Row(
mainAxisAlignment: MainAxisAlignment.spaceBetween,
children: [
Text(
'Kayıt No: ${formData.getKayitNo()}',
style: kTextStyle,
),
Text(
'Tarih: ${formData.getKayitNo()}',
style: kTextStyle.copyWith(fontSize: 15),
) //TODO: implement DateT
],
),
Row(
mainAxisAlignment: MainAxisAlignment.end,
children: [
ElevatedButton(onPressed: (){
// taslağa kaydedilmiş bilgiler tekrar yüklenecek.
FormData data= Provider.of<FormData>(context,listen: false);
Navigator.push(context, MaterialPageRoute(builder: (context)=>FormPage(formData: data,)));
},
child:const Text('Edit'),
),
const SizedBox(width: 5,),
ElevatedButton(onPressed: (){
},
child: const Text('Delete'),
),
],
),
],
),
),
);
}
This is my FormData model class.
class FormData with ChangeNotifier{
String? _kayitNo;
String? _stajTuru;
String? _doktor; //TODO: Convert string to AttendingPhysician type object
// late AttendingPhysician klinikEgitici;
String? _yas; // TODO: Convert to string later
String? _cinsiyet;
String? _sikayet;
String? _ayiriciTani;
String? _kesinTani;
String? _tedaviYontemi;
String? _etkilesimTuru;
String? _kapsam;
String? _gerceklestigiOrtam;
//DateTime tarih;
String getKayitNo()=>_kayitNo!;
String getStajTuru()=>_stajTuru!;
String getDoktor()=>_doktor!;
String getYas()=>_yas!;
String getCinsiyet()=>_cinsiyet!;
String getSikayet()=>_sikayet!;
String getAyiriciTani()=>_ayiriciTani!;
String getKesinTani()=>_kesinTani!;
String getTedaviYontemi()=>_tedaviYontemi!;
String getEtkilesimTuru()=>_etkilesimTuru!;
String getKapsam()=>_kapsam!;
String getOrtam()=>_gerceklestigiOrtam!;
void setStajTuru(String stajTuru) {
_stajTuru = stajTuru;
notifyListeners();
}
void setCinsiyet(String cinsiyet) {
_cinsiyet = cinsiyet;
notifyListeners();
}
void setEtkilesimTuru(String etkilesim) {
_etkilesimTuru = etkilesim;
notifyListeners();
}
void setKapsam(String kapsam) {
_kapsam = kapsam;
notifyListeners();
}
void setOrtam(String ortam) {
_gerceklestigiOrtam = ortam;
notifyListeners();
}
void setKayitNo(String kayitNo) {
_kayitNo = kayitNo;
notifyListeners();
}
void setYas(String yas) {
_yas = yas;
notifyListeners();
}
void setSikayet(String sikayet) {
_sikayet = sikayet;
notifyListeners();
}
void setAyiriciTani(String ayiriciTani) {
_ayiriciTani = ayiriciTani;
notifyListeners();
}
void setKesinTani(String kesinTani) {
_kesinTani = kesinTani;
notifyListeners();
}
void setTedaviYontemi(String tedaviYontemi) {
_tedaviYontemi = tedaviYontemi;
notifyListeners();
}
void setDoktor(String doktor){
_doktor=doktor;
notifyListeners();
}
}
To make it easier to understand the question. This process is the same as saving mail as a draft. When you want to edit the mail, the unfinished mail will show up not an empty mail.

I dont want to display all the records of table in listview but I want to display records of only particular customer in flutter

I have a screen which shows list of customers using listview. Next when I click on a customer I want to show the notes(records) only of that particular customer(customerId) in next screen in listview. I know how to display all the records of table. but how to display only certain records?? Neither there is any error nor the listview is being displayed. I dont know where am I going wrong.
List<CustomerNote> cnoteList;
int count = 0;
if (cnoteList == null) {
cnoteList = List<CustomerNote>();
updateCustomerNotes();
}
db_service.dart
Future<List<CustomerNote>> getCustomerNotes(int customer) async {
await DB.init();
var res = await DB.rawQuery("noteDetails WHERE custId = '$customer'");
int count = res.length;
List<CustomerNote> cnotelist = List<CustomerNote>();
for (int i = 0; i < count; i++) {
cnotelist.add(CustomerNote.fromMap(res[i]));
}
return cnotelist;
}
People_List.dart //this is the file which displays list of customers
import 'package:customer/models/Note.dart';
import 'package:customer/models/addCustomer.dart';
import 'package:customer/screens/New_Note.dart';
import 'package:customer/screens/Note_info.dart';
import 'package:customer/screens/User_Settings.dart';
import 'package:customer/screens/add_person.dart';
import 'package:customer/services/db_service.dart';
import 'package:customer/utils/database_helper.dart';
import 'package:flutter/material.dart';
import 'dart:io';
import 'package:sqflite/sqflite.dart';
class People_List extends StatefulWidget{
#override
State<StatefulWidget> createState() {
return People_ListState();
}
}
class People_ListState extends State<People_List> with SingleTickerProviderStateMixin{
DBService dbService = DBService();
List<AddCustomer> customerList;
int count = 0;
static final GlobalKey<ScaffoldState> scaffoldKey = new GlobalKey<ScaffoldState>();
var _isSelectedItemIndex;
TextEditingController _searchQuery;
bool _isSearching = false;
String searchQuery = "Search query";
#override
void initState() {
super.initState();
_searchQuery = new TextEditingController();
}
void _startSearch() {
print("open search box");
ModalRoute
.of(context)
.addLocalHistoryEntry(new LocalHistoryEntry(onRemove: _stopSearching));
setState(() {
_isSearching = true;
});
}
void _stopSearching() {
_clearSearchQuery();
setState(() {
_isSearching = false;
});
}
void _clearSearchQuery() {
print("close search box");
setState(() {
_searchQuery.clear();
updateSearchQuery("Search query");
});
}
Widget _buildTitle(BuildContext context) {
var horizontalTitleAlignment =
Platform.isIOS ? CrossAxisAlignment.center : CrossAxisAlignment.start;
return new InkWell(
onTap: () => scaffoldKey.currentState.openDrawer(),
child: new Padding(
padding: const EdgeInsets.symmetric(horizontal: 12.0),
child: new Column(
mainAxisAlignment: MainAxisAlignment.center,
crossAxisAlignment: horizontalTitleAlignment,
children: <Widget>[
const Text(''),
],
),
),
);
}
Widget _buildSearchField() {
return new TextField(
controller: _searchQuery,
autofocus: true,
decoration: const InputDecoration(
hintText: 'Search...',
border: InputBorder.none,
hintStyle: const TextStyle(color: Colors.white30),
),
style: const TextStyle(color: Colors.white, fontSize: 16.0),
onChanged: updateSearchQuery,
);
}
void updateSearchQuery(String newQuery) {
setState(() {
searchQuery = newQuery;
});
print("search query " + newQuery);
}
List<Widget> _buildActions() {
if (_isSearching) {
return <Widget>[
new IconButton(
icon: const Icon(Icons.clear),
onPressed: () {
if (_searchQuery == null || _searchQuery.text.isEmpty) {
Navigator.pop(context);
return;
}
_clearSearchQuery();
},
),
];
}
return <Widget>[
new IconButton(
icon: const Icon(Icons.search),
onPressed: _startSearch,
),
];
}
#override
Widget build(BuildContext context) {
var height = MediaQuery.of(context).size.height;
var width = MediaQuery.of(context).size.width;
if (customerList == null) {
customerList = List<AddCustomer>();
updateListView();
}
return Scaffold(
appBar: new AppBar(
leading: _isSearching ? const BackButton() : null,
title: _isSearching ? _buildSearchField() : _buildTitle(context),
actions: _buildActions(),
),
body:getCustomerListView(),
floatingActionButton: FloatingActionButton(
onPressed: () {
navigateToCustomer(AddCustomer(), 'Add Person');
},
child: const Icon(Icons.add),
),
bottomNavigationBar:Row (
children: <Widget>[
buildNavBarItem(Icons.home,0,"Home"),
buildNavBarItem(Icons.fiber_new_rounded,1,"Upcoming"),
buildNavBarItem(Icons.history,2,"History"),
buildNavBarItem(Icons.account_circle,3,"Account"),
],
),
);
}
ListView getCustomerListView() {
TextStyle titleStyle = Theme.of(context).textTheme.subhead;
return ListView.builder(
itemCount: count,
itemBuilder: (BuildContext context, int position) {
return Card(
color: Colors.white,
elevation: 2.0,
child: ListTile(
/*trailing: CircleAvatar(
backgroundColor: getPriorityColor(this.noteList[position].priority),
child: getPriorityIcon(this.noteList[position].priority),
),*/
title: Text(this.customerList[position].custName, style: titleStyle,),
//subtitle: Text(this.customerList[position].date),
onTap: () {
},
),
);
},
);
}
void navigateToCustomer(AddCustomer customer, String title) async {
bool result = await Navigator.push(context, MaterialPageRoute(builder: (context) {
return AddPerson(customer, title);
}));
if (result == true) {
updateListView();
}
}
void updateListView() {
final Future<Database> dbFuture = DB.init();
dbFuture.then((database) {
Future<List<AddCustomer>> customerListFuture = dbService.getCustomerList();
customerListFuture.then((customerList) {
setState(() {
this.customerList = customerList;
this.count = customerList.length;
});
});
});
}
Widget buildNavBarItem(IconData icon,int index,title) {
var height = MediaQuery.of(context).size.height;
var width = MediaQuery.of(context).size.width;
return GestureDetector(
onTap: () {
setState(() {
_isSelectedItemIndex=index;
if(_isSelectedItemIndex==3) {
Navigator.of(context).push(MaterialPageRoute(
builder: (BuildContext context) => User_Settings()));
}
});
},
child: Container(
height: height * 0.09,
width: width / 4,
decoration: index==_isSelectedItemIndex?BoxDecoration(
border: Border(
bottom: BorderSide(width: 4,color: Theme.of(context).primaryColor),
),
gradient: LinearGradient(colors: [
Theme.of(context).primaryColor.withOpacity(0.3),
Theme.of(context).primaryColor.withOpacity(0.015),
],begin: Alignment.bottomCenter,end: Alignment.topCenter)
):BoxDecoration(),
child: Column(
children: <Widget>[
InkWell(
child: Icon(icon,
color: index==_isSelectedItemIndex? Theme.of(context).primaryColor:Colors.black54,
),
),
Text(title)
],)),
);
}
}
Note_Info.dart
class Note_Info extends StatefulWidget{
final String appBarTitle;
final AddCustomer customer;
Note_Info(this. customer, this.appBarTitle);
#override
State<StatefulWidget> createState() {
return Note_InfoState(this.customer,this.appBarTitle);
}
}
class Note_InfoState extends State<Note_Info> {
CustomerNote note=CustomerNote();
DBService dbService = DBService();
List<CustomerNote> cnoteList;
int count = 0;
String appBarTitle;
AddCustomer customer;
Note_InfoState(this.customer, this.appBarTitle);
PickedFile _imageFile;
final ImagePicker _picker = ImagePicker();
bool rememberMe = false;
DateTime _date = DateTime.now();
TextEditingController custNameController = TextEditingController();
void getImage(ImageSource source) async {
final pickedFile = await _picker.getImage(
source: source);
setState(() {
_imageFile = pickedFile;
});
}
#override
Widget build(BuildContext context) {
if (noteList == null) {
noteList = List<CustomerNote>();
updateCustomerNotes();
}
var height = MediaQuery.of(context).size.height;
custNameController.text = customer.custName;
return DefaultTabController(
length: 4,
child: Scaffold(
appBar: AppBar(
actions: [
IconButton(
icon: Icon(
Icons.add,
),
onPressed: () {
Navigator.of(context).push(MaterialPageRoute(
builder: (BuildContext context) => NewNote()));
},
)
],
),
body: Container(
child: Column(
children: <Widget>[
TextField(controller: custNameController,
style: TextStyle(
fontSize: 20.0, fontWeight: FontWeight.bold),
textAlign: TextAlign.center),
Padding(
padding: const EdgeInsets.all(15.0),
child: Row(children: [
ImageProfile(),
Padding(
padding: const EdgeInsets.only(left: 30.0),
child: IconButton(
icon: Icon(
Icons.call,
color: Colors.green,
size: 45,
),
onPressed: () {
},
),
),
],),
),
SizedBox(
height: 50,
child: AppBar(
bottom: TabBar(
tabs: [
Tab(
text: "All",
),
Tab(
text: "Pending",
),
Tab(
text: "Cancelled",
),
Tab(
text: "Completed",
),
],
),
),
),
// create widgets for each tab bar here
Expanded(
child: TabBarView(
children: [
// first tab bar view widget
Container(
child: getNoteListView(),
),
// second tab bar view widget
Container(
child: Center(
child: Text(
'Pending Items',
),
),
),
Container(
child: Center(
child: Text(
'Cancelled',
),
),
),
Container(
child: Center(
child: Text(
'Completed',
),
),
),
],
),
),
Padding(
padding: const EdgeInsets.all(8.0),
child: Container(
height: 55.0,
width: 200,
child: RaisedButton(
elevation: 2,
shape: RoundedRectangleBorder(
borderRadius: BorderRadius.circular(20)),
color: Theme
.of(context)
.primaryColorDark,
textColor: Colors.white,
child: Text('Save', textScaleFactor: 1.5,),
onPressed: () {
setState(() {
//_reset();
});
},
),
),
),
]
),
)
));
}
void updateCustomerNotes() {
final Future<Database> dbFuture = DB.init();
dbFuture.then((database) {
int customerId=customer.custId;
Future<List<CustomerNote>> noteListFuture = dbService.getCustomerNotes(customerId);
noteListFuture.then((cnoteList) {
setState(() {
this.cnoteList = cnoteList;
//this.count = cnoteList.length;
});
});
});
}
ListView getNoteListView() {
TextStyle titleStyle = Theme.of(context).textTheme.subhead;
return ListView.builder(
itemCount: count,
itemBuilder: (BuildContext context, int position) {
return Card(
color: Colors.white,
elevation: 2.0,
child: ListTile(
title: Text(this.cnoteList[position].note, style: titleStyle,),
subtitle: Text(this.cnoteList[position].date),
trailing: GestureDetector(
child: Icon(Icons.delete, color: Colors.grey,),
onTap: () {
},
),
onTap: () {
},
),
);
},
);
}
void _showSnackBar(BuildContext context, String message) {
final snackBar = SnackBar(content: Text(message));
Scaffold.of(context).showSnackBar(snackBar);
}
Widget ImageProfile() {
return Center(
child: CircleAvatar(
radius: 80.0,
backgroundImage: AssetImage('images/person_icon.jpg')
),
);
}
}
If u want to get some specific data from the server then you need to provide (where: ) in your query such as
List<Map> result = await db.query(
DatabaseHelper.table,
columns: columnsToSelect,
where: whereString,
whereArgs: whereArguments);
// print the results
result.forEach((row) => print(row));
// {_id: 1, name: Bob, age: 23}
}
Note your query can be different from the above one.
and if you want to get the same specific data from already fetched data then also you need to use the where clause such as
final outData = responseData.where((i) => i.userId == customerId).toList();
and then pass the outData to next page through params.

Updating state in flutter

I have a dialog box that sorts a list on my home screen. When I press update the list will sort properly.
What I need to do is run setState for the entire home screen so that the other widgets will reflect the change for the sort order.
Specifically, I have two widgets that I need to rebuild when the update button is pressed.
I have tried to pass a function from the button to the home screen in the constructor and created a function to setState but that didn't work.
Please let me know if I'm being clear enough. Thanks
Home:
#override
Widget build(BuildContext context) {
return Scaffold(
appBar: AppBar(
title: Text('Home'),
),
body: SingleChildScrollView(
child: Center(
child: Column(
mainAxisAlignment: MainAxisAlignment.center,
children: <Widget>[
SizedBox(
height: 30,
),
HpHeader(),
SizedBox(height: 30),
QuoteBox(),
SizedBox(height: 30),
//parent
MainDebtDebt(),
SizedBox(height: 30),
AdCard(),
//child
AllDebtsCard(),
All debts card (where the button is):
import 'package:debt_zero_2/classes/min_debt_class.dart';
//import 'package:debt_zero_2/classes/icon_class.dart';
import 'package:debt_zero_2/widgets/provider_widget.dart';
import 'package:flutter/material.dart';
import 'package:intl/intl.dart';
import 'package:shared_preferences/shared_preferences.dart';
class AllDebtsCard extends StatefulWidget {
#override
_AllDebtsCardState createState() => _AllDebtsCardState();
}
class _AllDebtsCardState extends State<AllDebtsCard> {
int debtValue = 1;
int group;
void setValues() async {
SharedPreferences sharedPrefs = await SharedPreferences.getInstance();
final uid = await Provider.of(context).auth.getUidPref();
final db = Firestore.instance;
setState(() {
sharedPrefs.setInt('sortBySnowOrAva', debtValue);
SetMainDebt().setMainDebt();
});
db
.collection('userPreferences')
.document(uid)
.updateData({'sortBySnowOrAva': debtValue});
}
getValues() async {
SharedPreferences sharedPrefs = await SharedPreferences.getInstance();
int intValue = sharedPrefs.getInt('sortBySnowOrAva');
return intValue;
}
restore() async {
final SharedPreferences sharedPrefs = await SharedPreferences.getInstance();
setState(() {
group = (sharedPrefs.getInt('sortBySnowOrAva') ?? false);
});
}
final dbPath = Firestore.instance.collection('userDebts');
Stream<QuerySnapshot> dbStream(BuildContext context) async* {
final uid = await Provider.of(context).auth.getUidPref();
final intValues = await getValues();
yield* intValues == 1
? dbPath
.document(uid)
.collection('debts')
.orderBy('balance')
.snapshots()
: dbPath
.document(uid)
.collection('debts')
.orderBy('interest', descending: true)
.snapshots();
}
#override
void initState() {
super.initState();
restore();
}
#override
Widget build(BuildContext context) {
return Column(
children: <Widget>[
RaisedButton(
child: Text('SORT'),
onPressed: () {
showDialog(
barrierDismissible: false,
context: context,
builder: (BuildContext context) {
return StatefulBuilder(
builder: (context, setState) {
return AlertDialog(
title: Text('Sort Debts By:'),
content: Column(
mainAxisSize: MainAxisSize.min,
children: <Widget>[
RadioListTile(
value: 1,
secondary: IconButton(
onPressed: () {
showDialog(
context: context,
builder: (BuildContext context) {
return AlertDialog(
title: Text('Debt Snowball:'),
content: Text(
'This is an explanation of debt snowball'),
actions: <Widget>[
FlatButton(
child: Text('OK'),
onPressed: () {
Navigator.pop(context);
},
)
],
);
});
},
icon: Icon(Icons.help_outline),
),
title: Text('Snowball'),
groupValue: group,
onChanged: (T) {
setState(() {
group = T;
debtValue = 1;
});
},
),
RadioListTile(
value: 2,
title: Text('Avalanche'),
secondary: IconButton(
onPressed: () {},
icon: Icon(Icons.help_outline),
),
groupValue: group,
onChanged: (T) {
setState(() {
group = T;
debtValue = 2;
});
},
)
],
),
actions: <Widget>[
FlatButton(
onPressed: () async {
setState(() {
setValues();
});
Navigator.pop(context);
},
child: Text('UPDATE'),
),
FlatButton(
child: Text(
'CANCEL',
style: TextStyle(color: Colors.red),
),
onPressed: () {
Navigator.pop(context);
},
),
],
);
},
);
}).then((value) => setState(() {}));
},
),
StreamBuilder<QuerySnapshot>(
stream: dbStream(context),
builder: (context, snapshot) {
if (snapshot.hasData) {
final debts = snapshot.data.documents;
List<Widget> debtWidgets = [];
for (var debt in debts) {
final debtName = debt.data['name'];
final debtType = debt.data['type'];
final debtBalance = debt.data['balance'];
final debtDue = debt.data['due'].toDate();
final debtWidget = Card(
child: Row(
mainAxisAlignment: MainAxisAlignment.spaceBetween,
children: <Widget>[
Text('$debtType'),
Text('$debtName'),
Text(DateFormat.MMMd().format(debtDue)),
Text('$debtBalance'),
FlatButton(
child: Text(
'DELETE',
style: TextStyle(color: Colors.red),
),
onPressed: () {
//When I delete a debt I need to update the 'debtMinimum' field in prefs and firestore
},
)
],
),
);
debtWidgets.add(debtWidget);
}
return Column(children: debtWidgets);
}
return Container();
}),
],
);
}
}
One of the two widgets that I need updated:
import 'dart:async';
//import 'package:cloud_firestore/cloud_firestore.dart';
import 'package:debt_zero_2/classes/icon_class.dart';
import 'package:flutter/material.dart';
import 'package:shared_preferences/shared_preferences.dart';
class MainDebtDebt extends StatefulWidget {
#override
_MainDebtDebtState createState() => _MainDebtDebtState();
}
class _MainDebtDebtState extends State<MainDebtDebt> {
bool thenum = true;
static DebtModel debtIcons = DebtModel();
bool getGoalType = true;
double balance = 0.0;
String name = '';
String type = '';
int numOfDebts = 0;
double safetyBalance = 0.0;
double mainSnowballOpeningBalance = 0.0;
Future<void> getGoalTypeFlag() async {
final SharedPreferences preferences = await SharedPreferences.getInstance();
final sortBy = preferences.getInt('sortBySnowOrAva');
setState(() {
if (sortBy == 1){
balance = preferences.getDouble('mainDebtFieldSnowball');
type = preferences.getString('mainDebtFieldSnowballType');
name = preferences.getString('mainDebtFieldSnowballName');}
if (sortBy == 2){
balance = preferences.getDouble('mainAvalancheBalance');
type = preferences.getString('mainAvalancheBalanceType');
name = preferences.getString('mainAvalancheBalanceName');
}
mainSnowballOpeningBalance = preferences.getDouble('openingBalance');
safetyBalance = preferences.getDouble('safetyBalance');
getGoalType = preferences.getBool('mainGoalIsDebts');
numOfDebts = preferences.getInt('numberOfDebts');
});
}
#override
void initState() {
super.initState();
getGoalTypeFlag();
}
#override
Widget build(BuildContext context) {
return Container(
width: double.infinity,
decoration: BoxDecoration(border: Border.all()),
child: Column(
children: <Widget>[
Text(getGoalType
? 'I\'m Knocking Out This Payment:'
: 'I\'m Building My Safety Fund'),
SizedBox(
height: 15,
),
Row(
mainAxisAlignment: MainAxisAlignment.center,
children: <Widget>[
Text(
getGoalType
? debtIcons.getDebtIcon(type)
: '🧯',
style: TextStyle(fontSize: 30),
),
SizedBox(
width: 20,
),
Text(getGoalType ? name : 'Safety Fund'),
],
),
SizedBox(
height: 15,
),
Row(
mainAxisAlignment: MainAxisAlignment.center,
children: <Widget>[
Text(getGoalType ? 'Remaining Balance:' : 'Saved:'),
SizedBox(
width: 15,
),
Text(getGoalType
? '\$' + balance.toStringAsFixed(0)
: safetyBalance.toStringAsFixed(0))
],
),
SizedBox(
height: 15,
),
Column(
children: <Widget>[
Text('Current Progress:'),
SizedBox(
height: 10,
),
Container(
decoration: BoxDecoration(border: Border.all()),
height: 22,
width: 202,
child: Column(
crossAxisAlignment: CrossAxisAlignment.start,
children: <Widget>[
Flexible(
child: FractionallySizedBox(
widthFactor: .75,
//fix this
// 1 - mainSnowballBalance / mainSnowballOpeningBalance,
child: Container(
color: Colors.green,
),
),
)
],
),
),
SizedBox(
height: 15,
),
RaisedButton(
child: Text(getGoalType ? 'MAKE A PAYMENT' : 'MAKE A DEPOSIT'),
onPressed: () {
Navigator.of(context).pushNamed('/makePayment');
},
),
SizedBox(
height: 30,
),
RaisedButton(
child: Text('GET DATA'),
onPressed: ()async {
SharedPreferences pref = await SharedPreferences.getInstance();
String thenum = pref.getString('mainAvalancheBalanceType1');
//pref.setBool('isInOb', null);
print(thenum);
},
),
],
)
],
),
);
}
}

How to implement a network data fetch and then display in checkbox in alert inside showDialog with setState

I couldn't find a way to fetch data from network API inside showDialog > StatefulBuilder > AlertDialog. After fetching, this data should display in checkboxes and then finally on click ok, the selected checkboxes data is returned to the parent widget. There are more states other than these checkbox states in the alert. But the Navigator.of(context).pop() can return only single value.
Is there a way to rebuild the StatefulBuilder with setState on parent widget. Or some easy hack to rebuild the StatefulBuilder from an outside function like fetchOrderStatus() in the below code. (might be possible with a key on StatefulBuilder, but don't know how).
Below is my code
import 'package:flutter/material.dart';
import 'package:flutter/services.dart';
import 'package:flutter_spinkit/flutter_spinkit.dart';
import 'package:http/http.dart' as http;
import 'package:intl/intl.dart';
import 'dart:convert';
import 'package:recase/recase.dart';
import 'package:woocommerceadmin/src/orders/widgets/OrderDetailsPage.dart';
import 'package:barcode_scan/barcode_scan.dart';
class OrdersListPage extends StatefulWidget {
final String baseurl;
final String username;
final String password;
OrdersListPage({
Key key,
#required this.baseurl,
#required this.username,
#required this.password,
}) : super(key: key);
#override
_OrdersListPageState createState() => _OrdersListPageState();
}
class _OrdersListPageState extends State<OrdersListPage> {
String baseurl;
String username;
String password;
List ordersListData = List();
int page = 1;
bool hasMoreToLoad = true;
bool isListLoading = false;
bool isSearching = false;
String searchValue = "";
String sortOrderByValue = "date";
String sortOrderValue = "desc";
bool isOrderStatusOptionsReady = false;
bool isOrderStatusOptionsError = false;
String orderStatusOptionsError;
Map<String, bool> orderStatusOptions = {};
final scaffoldKey = new GlobalKey<ScaffoldState>();
final GlobalKey<RefreshIndicatorState> _refreshIndicatorKey =
new GlobalKey<RefreshIndicatorState>();
#override
void initState() {
super.initState();
baseurl = widget.baseurl;
username = widget.username;
password = widget.password;
fetchOrdersList();
}
#override
Widget build(BuildContext context) {
return Scaffold(
key: scaffoldKey,
appBar: _myAppBar(),
body: RefreshIndicator(
key: _refreshIndicatorKey,
onRefresh: handleRefresh,
child: Column(
children: <Widget>[
Expanded(
child: NotificationListener<ScrollNotification>(
onNotification: (ScrollNotification scrollInfo) {
if (hasMoreToLoad &&
!isListLoading &&
scrollInfo.metrics.pixels ==
scrollInfo.metrics.maxScrollExtent) {
handleLoadMore();
}
},
child: ListView.builder(
itemCount: ordersListData.length,
itemBuilder: (BuildContext context, int index) {
return Card(
child: InkWell(
onTap: () {
Navigator.push(
context,
MaterialPageRoute(
builder: (context) => OrderDetailsPage(
id: ordersListData[index]["id"],
),
),
);
},
child: Row(
mainAxisAlignment: MainAxisAlignment.start,
mainAxisSize: MainAxisSize.max,
crossAxisAlignment: CrossAxisAlignment.center,
children: <Widget>[
Expanded(
child: Padding(
padding: const EdgeInsets.all(10.0),
child: Column(
mainAxisAlignment:
MainAxisAlignment.start,
mainAxisSize: MainAxisSize.min,
crossAxisAlignment:
CrossAxisAlignment.start,
children: <Widget>[
_orderDate(ordersListData[index]),
_orderIdAndBillingName(
ordersListData[index]),
_orderStatus(ordersListData[index]),
_orderTotal(ordersListData[index])
]),
),
)
]),
),
);
}),
),
),
if (isListLoading)
Container(
height: 60.0,
color: Colors.white,
child: Center(
child: SpinKitFadingCube(
color: Colors.purple,
size: 30.0,
)),
),
],
),
),
);
}
Future<void> fetchOrderStatus() async {
String url =
"$baseurl/wp-json/wc/v3/reports/orders/totals?consumer_key=$username&consumer_secret=$password";
setState(() {
isOrderStatusOptionsReady = false;
isOrderStatusOptionsError = false;
});
dynamic response;
try {
response = await http.get(url);
if (response.statusCode == 200) {
if (json.decode(response.body) is List &&
!json.decode(response.body).isEmpty) {
json.decode(response.body).forEach((item) {
if (item is Map) {
orderStatusOptions.putIfAbsent(item["slug"], () => false);
}
});
setState(() {
isOrderStatusOptionsReady = true;
});
} else {
setState(() {
isOrderStatusOptionsReady = false;
isOrderStatusOptionsError = true;
orderStatusOptionsError = "Failed to fetch order status options";
});
}
} else {
String errorCode = "";
if (json.decode(response.body) is Map &&
json.decode(response.body).containsKey("code") &&
json.decode(response.body)["code"] is String) {
errorCode = json.decode(response.body)["code"];
}
setState(() {
isOrderStatusOptionsReady = false;
isOrderStatusOptionsError = true;
orderStatusOptionsError =
"Failed to fetch order status options. Error: $errorCode";
});
}
} catch (e) {
setState(() {
isOrderStatusOptionsReady = false;
isOrderStatusOptionsError = true;
orderStatusOptionsError =
"Failed to fetch order status options. Error: $e";
});
}
}
Widget _myAppBar() {
Widget myAppBar;
myAppBar = AppBar(
title: Text("Orders List"),
actions: <Widget>[
GestureDetector(
child: Padding(
padding: const EdgeInsets.only(left: 10),
child: Icon(Icons.search),
),
onTap: () {
setState(() {
isSearching = !isSearching;
});
},
),
GestureDetector(
child: Padding(
padding: const EdgeInsets.symmetric(horizontal: 10),
child: Icon(Icons.filter_list),
),
onTap: _orderFilter,
),
],
);
}
return myAppBar;
}
void _orderFilter() async {
showDialog(
context: context,
barrierDismissible: false,
builder: (BuildContext context){
// fetchOrderStatus();
return StatefulBuilder(builder: (context, StateSetter setState) {
return AlertDialog(
title: Text("Sort & Filter"),
titlePadding: EdgeInsets.fromLTRB(15, 20, 15, 0),
content: Container(
width: 300,
height: 400,
child: SingleChildScrollView(
child: Column(
mainAxisAlignment: MainAxisAlignment.start,
crossAxisAlignment: CrossAxisAlignment.start,
children: <Widget>[
Text(
"Sort by",
style: Theme.of(context).textTheme.subhead,
),
Row(
children: <Widget>[
Expanded(
child: Container(
child: DropdownButton<String>(
underline: SizedBox.shrink(),
value: sortOrderByValue,
onChanged: (String newValue) {
FocusScope.of(context)
.requestFocus(FocusNode());
setState(() {
sortOrderByValue = newValue;
});
},
items: <String>[
"date",
"id",
"title",
"slug",
"include"
].map<DropdownMenuItem<String>>((String value) {
return DropdownMenuItem<String>(
value: value,
child: Text(
value.titleCase,
textAlign: TextAlign.center,
style: Theme.of(context).textTheme.body1,
),
);
}).toList(),
),
),
),
InkWell(
child: Padding(
padding:
const EdgeInsets.symmetric(horizontal: 10),
child: Icon(
Icons.arrow_downward,
color: (sortOrderValue == "desc")
? Theme.of(context).primaryColor
: Colors.black,
),
),
onTap: () {
setState(() {
sortOrderValue = "desc";
});
},
),
InkWell(
child: Padding(
padding:
const EdgeInsets.symmetric(horizontal: 10),
child: Icon(
Icons.arrow_upward,
color: (sortOrderValue == "asc")
? Theme.of(context).primaryColor
: Colors.black,
),
),
onTap: () {
setState(() {
sortOrderValue = "asc";
});
},
),
],
),
Text(
"Filter by",
style: Theme.of(context).textTheme.subhead,
),
Text(
"Order Status",
style: Theme.of(context).textTheme.body1.copyWith(
fontWeight: FontWeight.bold, fontSize: 16),
),
isOrderStatusOptionsReady
? ListView(
children:
orderStatusOptions.keys.map((String key) {
return new CheckboxListTile(
title: Text(key),
value: orderStatusOptions[key],
onChanged: (bool value) {
setState(() {
orderStatusOptions[key] = value;
});
},
);
}).toList(),
)
: Container(
child: Center(
child: SpinKitFadingCube(
color: Theme.of(context).primaryColor,
size: 30.0,
),
),
)
],
),
),
),
contentPadding: EdgeInsets.fromLTRB(15, 10, 15, 0),
actions: <Widget>[
FlatButton(
child: Text("Close"),
onPressed: () {
Navigator.of(context).pop();
},
),
FlatButton(
child: Text("Ok"),
onPressed: () {
Navigator.of(context).pop();
},
)
],
);
});
});
}
}
You have a couple of options
Fetch the data before showing the dialog. Using either async/await keywords or .then, you wait for the fetching of data to complete, then use the data in the dialog
void _orderFilter() async {
await fetchOrderStatus();
showDialog(...); //Use the response in the dialog
}
Create a new stateful widget for the dialog and have fetchOrderStatus() be a method in that class. This allows you to have more control over what to display as well as state changes in the dialog.
#gaurav-jain I have followed your question from Github where you asked a question about my answer to this problem. How I did it is i have a button that when clicked immediately opens the dialog that then waits for the Future to load data from the API: The async function _showOptions() renders the dialog that renders a list of checkboxes with options fetched from API:
new RaisedButton(
color: Colors.green,
padding: EdgeInsets.all(20.0),
onPressed: () {
if (state._isLoading){
// don't do anything when form is submitting and this button is pressed again
return null;
}
else {
if (state._formKey.currentState.validate()) {
state._showOptions().then((selected){
print(state.selectedOptions);
if (state.selectedOptions.isNotEmpty) {
_submitForm();
}
else {
showDialog(
context: context,
builder: (context) {
return AlertDialog(
content: Text('You have not selected any option'),
actions: <Widget>[
FlatButton(
child: Text('OK'),
onPressed: () {
Navigator.of(context, rootNavigator: true).pop();
},
),
],
);
}
);
}
});
}
else {
Scaffold.of(context).showSnackBar(
SnackBar(
content: Text('Your form has errors. Rectify them and submit again'),
)
);
}
}
},
child: Text(state._isLoading ? 'Submitting...' : 'Submit', style: new TextStyle(color: Colors.white)),
),
The state here is the parent widget's state, but the async dialog has it's own state to make it work. You can refer back to the github comment for the other pieces of the code here https://github.com/flutter/flutter/issues/15194#issuecomment-450490409
As suggested by #wxker, 2nd approach, I have implemented other stateful widget which returns AlertDialog.
Parent Widget Calling showDialog on tap:
IconButton(
icon: Icon(Icons.filter_list),
onPressed: () {
showDialog(
context: context,
barrierDismissible: false,
builder: (BuildContext context) {
return OrdersListFiltersModal(
baseurl: widget.baseurl,
username: widget.username,
password: widget.password,
sortOrderByValue: sortOrderByValue,
sortOrderValue: sortOrderValue,
orderStatusOptions: orderStatusOptions,
onSubmit:
(sortOrderByValue, sortOrderValue, orderStatusOptions) {
setState(() {
this.sortOrderByValue = sortOrderByValue;
this.sortOrderValue = sortOrderValue;
this.orderStatusOptions = orderStatusOptions;
});
handleRefresh();
},
);
},
);
},
),
Child stateful widget returning alert with default value and function callback in constructor to change parent widget state.
Widget build(BuildContext context) {
return AlertDialog(
title: Text("Sort & Filter"),
titlePadding: EdgeInsets.fromLTRB(15, 20, 15, 0),
content: Container(
height: 400,
child: SingleChildScrollView(
child: Column(
mainAxisAlignment: MainAxisAlignment.start,
crossAxisAlignment: CrossAxisAlignment.start,
children: <Widget>[
Text(
"Sort by",
style: Theme.of(context).textTheme.subhead,
),
Padding(
padding: const EdgeInsets.fromLTRB(10, 0, 10, 0),
child: Row(
children: <Widget>[
Expanded(
child: Container(
child: DropdownButton<String>(
underline: SizedBox.shrink(),
value: sortOrderByValue,
onChanged: (String newValue) {
FocusScope.of(context).requestFocus(FocusNode());
setState(() {
sortOrderByValue = newValue;
});
},
items: <String>[
"date",
"id",
"title",
"slug",
"include"
].map<DropdownMenuItem<String>>((String value) {
return DropdownMenuItem<String>(
value: value,
child: Text(
value.titleCase,
textAlign: TextAlign.center,
style: Theme.of(context).textTheme.body1,
),
);
}).toList(),
),
),
),
InkWell(
child: Padding(
padding: const EdgeInsets.symmetric(horizontal: 10),
child: Icon(
Icons.arrow_downward,
color: (sortOrderValue == "desc")
? Theme.of(context).primaryColor
: Colors.black,
),
),
onTap: () {
setState(() {
sortOrderValue = "desc";
});
},
),
InkWell(
child: Padding(
padding: const EdgeInsets.symmetric(horizontal: 10),
child: Icon(
Icons.arrow_upward,
color: (sortOrderValue == "asc")
? Theme.of(context).primaryColor
: Colors.black,
),
),
onTap: () {
setState(() {
sortOrderValue = "asc";
});
},
),
],
),
),
Text(
"Filter by",
style: Theme.of(context).textTheme.subhead,
),
SizedBox(
height: 10,
),
Padding(
padding: const EdgeInsets.only(left: 10),
child: Text(
"Order Status",
style: Theme.of(context)
.textTheme
.body1
.copyWith(fontWeight: FontWeight.bold, fontSize: 16),
),
),
SizedBox(
height: 10,
),
isOrderStatusOptionsError
? Row(
children: <Widget>[
Expanded(
child: Padding(
padding: const EdgeInsets.fromLTRB(10, 10, 10, 10),
child: Text(
orderStatusOptionsError,
style: Theme.of(context).textTheme.body1,
),
),
),
],
)
: isOrderStatusOptionsReady
? Column(
children: orderStatusOptions.keys.map((String key) {
return GestureDetector(
onTap: () {
setState(() {
orderStatusOptions[key] =
!orderStatusOptions[key];
});
},
child: Container(
color: Colors.transparent,
height: 30,
child: Row(
children: <Widget>[
Checkbox(
value: orderStatusOptions[key],
onChanged: (bool value) {
setState(() {
orderStatusOptions[key] = value;
});
},
),
Expanded(
child: Text(
key.titleCase,
style:
Theme.of(context).textTheme.body1,
),
),
],
),
),
);
}).toList(),
)
: Container(
padding: EdgeInsets.fromLTRB(0, 20, 0, 0),
child: Center(
child: SpinKitPulse(
color: Theme.of(context).primaryColor,
size: 50,
),
),
)
],
),
),
),
contentPadding: EdgeInsets.fromLTRB(15, 10, 15, 0),
actions: <Widget>[
FlatButton(
child: Text("Close"),
onPressed: () {
Navigator.of(context).pop();
},
),
FlatButton(
child: Text("Ok"),
onPressed: () {
widget.onSubmit(
sortOrderByValue, sortOrderValue, orderStatusOptions);
Navigator.of(context).pop();
},
)
],
);
}
Future<void> fetchOrderStatusOptions() async {
String url =
"${widget.baseurl}?consumer_key=${widget.username}&consumer_secret=${widget.password}";
setState(() {
isOrderStatusOptionsReady = false;
isOrderStatusOptionsError = false;
});
http.Response response;
try {
response = await http.get(url);
if (response.statusCode == 200) {
if (json.decode(response.body) is List &&
!json.decode(response.body).isEmpty) {
Map<String, bool> tempMap = orderStatusOptions;
json.decode(response.body).forEach((item) {
if (item is Map &&
item.containsKey("slug") &&
item["slug"] is String &&
item["slug"].isNotEmpty) {
tempMap.putIfAbsent(item["slug"], () => false);
}
});
setState(() {
isOrderStatusOptionsReady = true;
orderStatusOptions = tempMap;
});
} else {
setState(() {
isOrderStatusOptionsReady = false;
isOrderStatusOptionsError = true;
orderStatusOptionsError = "Failed to fetch order status options";
});
}
} else {
String errorCode = "";
if (json.decode(response.body) is Map &&
json.decode(response.body).containsKey("code") &&
json.decode(response.body)["code"] is String) {
errorCode = json.decode(response.body)["code"];
}
setState(() {
isOrderStatusOptionsReady = false;
isOrderStatusOptionsError = true;
orderStatusOptionsError =
"Failed to fetch order status options. Error: $errorCode";
});
}
} catch (e) {
setState(() {
isOrderStatusOptionsReady = false;
isOrderStatusOptionsError = true;
orderStatusOptionsError =
"Failed to fetch order status options. Error: $e";
});
}
}
}