How to get data from database and into listview.builder - firebase

I am trying to get data from Firebase RTDB and then display them as a list using Listview.builder.
This worked well before, however I have added a new node into my database to have it be more stuctured. The problem is, inspite of there being data, it's showing up as empty when I try to retrieve it.
Database before:
Database Now:
Code:
Future<List> getParentDetails() async {
schoolName = await getSchoolName();
databaseReference
.child("users")
.child(schoolName.toString()) // 👈👈👈(newly added)
.child("parents")
.onValue
.listen(
(event) {
if (event.snapshot.exists) {
setState(
() {
var value = event.snapshot.value;
parentList = Map.from(value)
.values
.map((e) => Parents.fromJson(Map.from(e)))
.toList();
},
);
} else {
print("No Data Exists");
}
},
);
return parentList;
}
UI Code:
ListView.builder(
itemCount: parentList.length,
itemBuilder: (context, int index) {
final Parents parents = parentList[index];
final String parentEmail = parents.email;
final String parentName = parents.name;
final String parentPhone = parents.phone;
// final String parentUID = parents.uid;
return Padding(
padding: const EdgeInsets.all(8.0),
child: Card(
elevation: 0.2,
child: ExpansionTile(
// collapsedBackgroundColor: Colors.grey,
title: Text(
parentName.toUpperCase(),
style: GoogleFonts.lexendMega(
fontSize: 12,
),
textAlign: TextAlign.center,
),
children: [
Column(
children: [
Text(
parentEmail,
textAlign: TextAlign.center,
style: GoogleFonts.lexendMega(fontSize: 12),
),
SizedBox(
height: 5,
),
Text(
parentPhone,
textAlign: TextAlign.center,
style: GoogleFonts.lexendMega(fontSize: 12),
),
SizedBox(
height: 5,
),
],
)
],
),
),
);
},
),
New Edit:
getSchoolName() async {
// ignore: unused_local_variable
final ref = FirebaseDatabase.instance.reference();
User user = auth.currentUser;
String adminUID = user.uid.toString();
print("Getting School Name");
databaseReference.child("users").child("admin").child(adminUID).once().then(
(DataSnapshot snapshot) {
setState(() {
schlName = snapshot.value["school"];
print(schlName); // 👈👈👈 (Prints - Highway Secondary School)
});
},
);
return await schlName;
}
Future<List> getParentDetails() async {
schoolName = await getSchoolName();
databaseReference
.child("users")
.child("Highway Secondary School")
.child("parents")
.onValue
.listen(
(event) {
if (event.snapshot.exists) {
setState(
() {
var value = event.snapshot.value;
print(value); // 👈👈👈 (See print value below)
parentList = Map.from(value)
.values
.map((e) => Parents.fromJson(Map.from(e)))
.toList();
},
);
} else {
print("No Data Exists");
}
},
);
return parentList;
}
Output:
{L9LnmRTZJgVJWjNhrcTqoRdMlas2: {driver: Locate the driver: , phone: ********, school: Highway Secondary School, name: Parent One, user uid: L9LnmRTZJgVJWjNhrcTqoRdMlas2, email: **********#gmail.com}, Z9nHn3HZ3MZqgS7RsKsFiofD4ty2: {driver: Locate the driver: , phone: ********, school: Highway Secondary School, name: Parent Two, user uid: Z9nHn3HZ3MZqgS7RsKsFiofD4ty2, email: ***********#gmail.com}}
Edit 2:
Future<List> getParentDetails() async {
schoolName = await getSchoolName();
print(schoolName); 👈👈👈 (Prints - null)
var ref = databaseReference.child("users/$schoolName/parents");
var snapshot = await ref.get();
if (snapshot.exists) {
setState(() {
var value = snapshot.value;
parentList = Map.from(value)
.values
.map((e) => Parents.fromJson(Map.from(e)))
.toList();
});
} else {
print("No Data Exists");
}
return parentList;
}
With newly added line of code above, the code doesn't get any data from the database (from the current database).
Without the newly added line of code, I get data from the old database without any issues.
The intention of the new database is to be more organized.

This will not work:
Future<List> getParentDetails() async {
schoolName = await getSchoolName();
databaseReference
.child("users")
.child("Highway Secondary School")
.child("parents")
.onValue
.listen(
(event) {
if (event.snapshot.exists) {
setState(
() {
var value = event.snapshot.value;
print(value); // 👈👈👈 (See print value below)
parentList = Map.from(value)
.values
.map((e) => Parents.fromJson(Map.from(e)))
.toList();
},
);
} else {
print("No Data Exists");
}
},
);
return parentList;
}
Calling listen starts an asynchronous process, but your main code continues to run. So your return parentList runs before the parentList = Map.from(value) is ever called. Adding some more print statements will show that in the order of they are output.
You also return a Future, which you can do only once, while listen can be called many times. If you only get about the current value, you should use get() instead of listen as shown in the documentation on reading data once.
With that, the code would look something like:
Future<List> getParentDetails() async {
schoolName = await getSchoolName();
var ref = databaseReference.child("users/Highway Secondary School/parents");
var snapshot = await ref.get();
if (snapshot.exists) {
setState(
() {
var value = snapshot.value;
parentList = Map.from(value)
.values
.map((e) => Parents.fromJson(Map.from(e)))
.toList();
},
);
} else {
print("No Data Exists");
}
return parentList;
}
Update: to also fix getSchoolName it's important to not mix then with async/await, but use one or the other only.
getSchoolName() async {
final ref = FirebaseDatabase.instance.reference();
User user = auth.currentUser;
String adminUID = user.uid.toString();
var snapshot = databaseReference.child("users/admin").child(adminUID).get();
schlName = snapshot.value["school"];
setState(() {});
return schlName;
}

Related

How can use GoogleMap and get data put into array from firestore database?

How can use GoogleMap and get data put into array from firestore database?
Now I can used default data and realize used marker in GoogleMap, but I need to get data from firestore database, so how could I did?
in my code,
final Completer<GoogleMapController> _controller = Completer();
List<String> images = [
'assets/accomodation.png',
'assets/beach.png',
'assets/boat.png',
'assets/campsite.png',
];
Uint8List? markerImage;
final List<Marker> _markers = <Marker>[];
final List<LatLng> _latLang = <LatLng>[
LatLng(33.6941, 72.9734),
LatLng(33.7008, 72.9682),
LatLng(33.6992, 72.9744),
LatLng(33.6939, 72.9771),
LatLng(33.6910, 72.9807),
LatLng(33.7036, 72.9785)
];
static const CameraPosition _kGooglePlex = CameraPosition(
target: LatLng(33.6910, 72.98072),
zoom: 15,
);
Future<Uint8List> getBytesFromAsset(String path, int width) async {
ByteData data = await rootBundle.load(path);
ui.Codec codec = await ui.instantiateImageCodec(data.buffer.asUint8List(),
targetWidth: width);
ui.FrameInfo fi = await codec.getNextFrame();
return (await fi.image.toByteData(format: ui.ImageByteFormat.png))!
.buffer
.asUint8List();
}
#override
void initState() {
super.initState();
loadData();
}
loadData() async {
for (int i = 0; i < images.length; i++) {
final Uint8List markerIcon =
await getBytesFromAsset(images[i].toString(), 100);
_markers.add(Marker(
markerId: MarkerId(i.toString()),
position: _latLang[i],
icon: BitmapDescriptor.fromBytes(markerIcon),
infoWindow: InfoWindow(title: 'The title of the marker')));
setState(() {});
}
}
#override
Widget build(BuildContext context) {
return Scaffold(
appBar: AppBar(
backgroundColor: mobileBackgroundColor,
centerTitle: false,
title: SvgPicture.asset(
'assets/yomate_new_logo.svg',
color: primaryColor,
height: 32,
),
),
body: SafeArea(
child: GoogleMap(
initialCameraPosition: _kGooglePlex,
mapType: MapType.normal,
myLocationButtonEnabled: true,
myLocationEnabled: true,
markers: Set<Marker>.of(_markers),
onMapCreated: (GoogleMapController controller) {
_controller.complete(controller);
},
),
),
);
}
Can give me idea?
I tried to use this methods, but I have not any idea and get error.....
final List<LatLng> _latLang = <LatLng>[];
loadData() async {
await FirebaseFirestore.instance.collection('Campsite').get().then(
(value) {
setState(() {
List.from(value.data['CamperSiteLatitude']).forEach((element) {
LatLng data = new LatLng(element);
_latLang.add(data);
});
});
},
);
}
This is my data format... every data has CamperSiteLatitude & CamperSiteLongitude
And could I custom markerIcon? if the data type is campsite, I hope can show assets/campsite.png, the data type is accomodation show assets/accomodation.png', the data type is beach show assets/beach.png', the data type is boat ramp show 'assets/boat.png'
tried this one
loadData() async {
final Uint8List markerIcon =
await getBytesFromAsset('assets/campsite.png', 100);
await FirebaseFirestore.instance.collection('Campsite').get().then(
(querySnapshot) {
querySnapshot.docs.forEach((element) {
_markers.add(
Marker(
markerId: MarkerId(element.data()['CamperSiteID']),
position: LatLng(element.data()['CamperSiteLatitude'],
element.data()['CamperSiteLongitude']),
icon: BitmapDescriptor.fromBytes(markerIcon),
infoWindow: InfoWindow(
title: element.data()['CamperSiteName'],
),
),
);
setState(() {});
print(element.data()['type']);
});
},
);
}

Flutter How to observ UserModel with GetX after 2.8.1

I am using getX for fetching data from Firebase.
I used this one before 2.8 update. It was working.
class UserController extends GetxController {
final Rx<UserModel> _userModel = UserModel(
email: '',
name: '',
uid: '',
kullaniciAdi: '',
bildirim: 0,
userRole: 0,
).obs;
UserModel get user => _userModel.value;
set user(UserModel value) => _userModel.value = value;
void clear() {
_userModel.value = UserModel(
email: '',
name: '',
uid: '',
kullaniciAdi: '',
bildirim: 0,
userRole: 0,
);
}
}
I can observ this with GetX or Obx widget. But now, I can't do that anymore.
Here is my Firebase Database code fetching user codes:
Future getUserFromDB(String uid) async {
try {
var userData = await _firestore.collection("customers").doc(uid).get();
var map = userData.data();
//debugPrint(map!['email']);
return UserModel.fromData(userData.data());
} on FirebaseException catch (e) {
return e.message;
}
}
And this is my UserModel:
class UserModel {
String? uid;
String? name;
String? email;
int? bildirim;
int? userRole;
String? kullaniciAdi;
String? pphoto;
UserModel({
this.uid,
this.name,
this.email,
this.bildirim,
this.userRole,
this.kullaniciAdi,
this.pphoto,
});
UserModel.fromData(Map<String, dynamic>? dataMap)
: uid = dataMap!['id'],
name = dataMap['name'],
email = dataMap['email'],
bildirim = dataMap['bildirim'],
kullaniciAdi = dataMap['kullaniciAdi'];
Map<String, dynamic> toData() {
return {
'uid': uid,
'name': name,
'email': email,
'userRole': userRole,
'bildirim': bildirim,
'kullaniciAdi': kullaniciAdi,
'pphoto': pphoto,
};
}
}
I would like to listen this userModel after fetching data. But whenever I use Obx or GetX widget they returns an error.
Here is GetX widget and error;
GetX<UserController>(
initState: (_) async {
Get.find<UserController>().user = await FirebaseDatabase()
.getUserData(homeController.userVeri!.uid);
},
builder: (_) {
if (_.user.uid != null) {
return Text(
_.user.name.toString(),
style: const TextStyle(
color: Colors.white,
fontSize: 30,
fontWeight: FontWeight.w500),
);
} else {
return const Text("...");
}
},
),
Error is:
Null check operator used on nulls value
It seems to me, that the only possible cause for the error is that you are getting the userVeri!.uid, with a null check(!). Inside the initState builder of your GetX widget. I would suggest first checking whether the userVeri.uid is not null before requesting their data. What I mean is more like this.
GetX<UserController>(
initState: (_) async {
if(homeController.userVeri != null){
Get.find<UserController>().user = await FirebaseDatabase()
.getUserData(homeController.userVeri!.uid);
}
},
builder: (_) {
if (_.user.uid != null && homeController.userVeri != null) {
return Text(
_.user.name.toString(),
style: const TextStyle(
color: Colors.white,
fontSize: 30,
fontWeight: FontWeight.w500),
);
} else {
return const Text("...");
}
},
),

Dart/Flutter - the method forEach was called on null

I'm trying to get the "Child_Name" and "Parent_Name" from firebase rtdb and create a list of the names using ListView.builder. I have done this before in another part of the app and it works perfectly. I am trying to apply the same logic again but I am getting an error.
Error is occurs inside the setState where the line childrenList = Map.from(value) is.
View of my firebase rtdb
is here (image)
Error:
- [ERROR:flutter/lib/ui/ui_dart_state.cc(186)] Unhandled Exception: NoSuchMethodError: The method 'forEach' was called on null.
- Tried calling: forEach(Closure: (dynamic, dynamic) => void)
Code(1):
Future<List> getListOfChildren() async {
print("Getting Children");
databaseReference
.child("users")
.child("Absent_Children")
.child(formattedDate)
.onValue
.listen(
(event) {
setState(
() {
var value = event.snapshot.value;
childrenList = Map.from(value)
.values
.map((e) => Children.fromJson(Map.from(e)))
.toList();
},
);
},
);
return childrenList;
}
Code(2): Class for the data
class Children {
final String childName;
final String parentName;
Children({
this.childName,
this.parentName,
});
static Children fromJson(Map<dynamic, dynamic> json) {
return Children(
childName: json["Child_Name"],
parentName: json["Parent_Name"],
);
}
}
Code(4): formattedDate
getTodaysDate() {
setState(
() {
DateTime now = DateTime.now();
var date = DateFormat("dd-mm-yyyy");
formattedDate = date.format(now).toString();
},
);
}
Code(3): My ListView.builder
body: childrenList.isEmpty
? Center(child: CircularProgressIndicator())
: ListView.builder(
itemCount: childrenList.length,
itemBuilder: (context, int index) {
final Children child = childrenList[index];
final String childName = child.childName;
final String parentName = child.parentName;
return Padding(
padding: const EdgeInsets.all(8.0),
child: Card(
elevation: 0,
child: ExpansionTile(
title: Text(
childName.toUpperCase(),
style: GoogleFonts.lexendMega(),
textAlign: TextAlign.center,
),
children: [
Column(
children: [
Text(
parentName,
textAlign: TextAlign.center,
style: GoogleFonts.lexendMega(fontSize: 13),
),
],
)
],
),
),
);
},
),
Thank you.
As I said here too, it looks like there's no data as databaseReference.child("users").child("Absent_Children").child(formattedDate) and your code doesn't handle that situation.
If the absence of data is a normal occurrence, you should check if the snapshot has a value before trying to access its value:
databaseReference
.child("users")
.child("Absent_Children")
.child(formattedDate)
.onValue
.listen(
(event && event.snapshot.exists) { // 👈 add exists check here
setState(
() {
var value = event.snapshot.value;
childrenList = Map.from(value)
.values
.map((e) => Children.fromJson(Map.from(e)))
.toList();
},
);

How can I loop over an array in firebase?

Im trying to get data from firebase. But im a bit struggling with that heres how it looks now
getusers() async {
var firestore = FirebaseFirestore.instance;
List listOfIds = [];
QuerySnapshot qn= await firestore
.collection('videos')
.get()
.then((QuerySnapshot querySnapshot) {
querySnapshot.docs.forEach((doc) {
setState(() {
});
});
});
if (!mounted) return;
_allResults =qn.docs;
What I want is get the hashtasg array field and then add it to the qn.doc data in _allresults . But how can I do that ?
Heres my firebase so you can see how it looks
And last step I wanna loop over the howle hashtag array
This is my widget
class Openalldocs extends StatefulWidget {
final TextEditingController searchinginput;
static const route = '/openalldocs';
const Openalldocs({Key key, this.searchinginput}) : super(key: key);
#override
_OpenalldocsState createState() => _OpenalldocsState();
}
class _OpenalldocsState extends State<Openalldocs> {
List _allResults = [];
List _resultsList = [];
Future resultsLoaded;
bool nosuerfound = false;
String searchresult;
#override
void initState() {
super.initState();
widget.searchinginput.addListener(_onsearchChanged);
setState(() {
nosuerfound = true;
});
}
#override
void dispose() {
widget.searchinginput.removeListener(_onsearchChanged());
super.dispose();
}
#override
void didChangeDependencies() {
widget.searchinginput.text;
resultsLoaded = getusers();
super.didChangeDependencies();
}
_onsearchChanged() {
setState(() {
nosuerfound = false;
});
searchResults();
}
searchResults() {
var showResults = [];
if (widget.searchinginput.text != "") {
for (var tripsnapshot in _allResults) {
var title = DatbaseService.instance
.videosfromsnapshot(tripsnapshot)
.hashtag1
.toLowerCase();
var title2 = DatbaseService.instance
.videosfromsnapshot(tripsnapshot)
.hashtag2
.toLowerCase();
var title3 = DatbaseService.instance
.videosfromsnapshot(tripsnapshot)
.hashtag3
.toLowerCase();
if (title.contains(widget.searchinginput.text.toLowerCase()) ||
title2.contains(widget.searchinginput.text.toLowerCase()) ||
title3.contains(widget.searchinginput.text.toLowerCase())) {
setState(() {
nosuerfound = true;
});
showResults.add(tripsnapshot);
}
}
} else {
setState(() {
nosuerfound = true;
});
showResults = List.from(_allResults);
}
setState(() {
_resultsList = showResults;
});
}
getusers() async {
var firestore = FirebaseFirestore.instance;
List listOfIds = [];
QuerySnapshot qn= await firestore
.collection('videos')
.get()
.then((QuerySnapshot querySnapshot) {
querySnapshot.docs.forEach((doc) {
setState(() {
_allResults.add(doc.data()["hashtag1"]);
});
});
});
if (!mounted) return;
searchResults();
return "Complete";
}
#override
Widget build(BuildContext context) {
final user = Provider.of<Userforid>(context);
if (nosuerfound == true) {
return ListView.builder(
itemCount: _resultsList.length,
itemBuilder: (BuildContext context, int index) {
return Column(
crossAxisAlignment: CrossAxisAlignment.start,
children: [
// the AMOUNT is how many hashtags you want to show
for (var i = 0; i < _resultsList.length; i += 1) ...[
// the SizedBox will only exist between the elements in the list
// as before
if (i != 0) SizedBox(height: 6),
// create a builder to allow declaring a variable
Builder(
builder: (context) {
// declare the hashtag variable
final hashtag = 'hashtag${i + 1}';
return InkWell(
onTap: () {
// do something with the hashtag stored in the variable
// this will make it relative to the element in the list
},
child: Column(
children: <Widget>[
// why is there a Column inside another with only one child?
// I would recommend to remove it
Column(
children: [
HighlightedMatchesText(
searchString: widget.searchinginput.text,
// notice how I am using the hashtag variable here
// instead of a constant? ('hashtag1'), by the way
// the for loop will make the hashtag start at 0
// you can change it by increment in the declaration
// `final hashtag = 'hashtag${i+1}'`, if you want
// the existing behavior
content: _resultsList[index][hashtag],
),
],
),
// what is this? if it is to add more space between the items
// in the list, I recommend removing it from here, and add it
// to the first `SizedBox` in the for loop
// in case you do that, the Column that this widget belong
// would also only now contain one widget, so, there is no
// need to have it
SizedBox(height: 3),
],
You are using the Firestore methods correctly, the querySnapshot.docs is an array of all documents in that collection that you are looping through with forEach - You only require further logic on the doc.data().
in this case: push all "hashtag1" to the results
.then((QuerySnapshot querySnapshot) {
querySnapshot.docs.forEach((doc) {
setState(() {
_allResults.add(doc.data()["hashtag1"]);
});
});
Update Suggested code block
Future<String> getusers() async {
var firestore = FirebaseFirestore.instance;
List listOfIds = [];
QuerySnapshot qn= await firestore
.collection('videos')
.get();
for (var doc in qn.docs) {
setState(() {
_allResults.add(doc.data()["hashtag1"]);
});
}
});
});
if (!mounted) return "Error loading";
searchResults();
return "Complete";
}
yea check out this. if any error, let me no because i am not on system
List<QueryDocumentSnapshot> _allResults =[]
QuerySnapshot qn = await firestore.collection('videos').get();
if (!mounted) return;
setState(() {
_allResults = qn.docs;
});
UPDATE
This line states that the _resultList is a List of documents, and you want to access all the hashtags from it, because you have the for-loop, which goes until it reaches the length of _resultList, therefore you are getting all the hashtags. If you only want to show the hashtag1, then change this:
content: _resultsList[index].data()[hashtag],
to this:
content: _resultsList[index].data()["hashtag1"],
If you want to have all the documents in this List, use this:
.then((QuerySnapshot querySnapshot) {
_allResults = querySnapshot.docs;
}

How to delete picture from the data file in flutter app

In my app I am taking picture and storing it in the device also storing the path using sqlite . Now if I delete the data using the code given below it delete from the local database(sqlite) but do not delete the picture from the file . for example I create 3 transaction and delete 2 of them but in file I still have 3 images(in file) . So how to delete them . please help .
Saving :
Future _takeImage() async {
PickedFile imageFile = await ImagePicker().getImage(
source: ImageSource.camera,
maxWidth: 600,
);
_saveImg(imageFile);
}
Future _saveImg(PickedFile imageFile) async {
if (imageFile == null) {
return;
}
setState(() {
_storedImage = File(imageFile.path);
});
final appDirectory = await sysPath.getApplicationDocumentsDirectory();
final fileName =
path.basename(_storedImage.path); //name of the photo created by camera.
final savedImage = await _storedImage
.copy('${appDirectory.path}/$fileName'); // storing image.
widget.onSelectImage(savedImage.path);
}
Deleting :
Future<void> deleteExpanse(int id) async {
try {
final MyDatabase dbManager = MyDatabase();
await dbManager.deleteTransaction(id, "Expense");
DataSample temp = _expenseItems.firstWhere((element) => id == element.id);
await _deleteImage(temp);
_expenseItems.removeWhere((element) => element.id == id);
} catch (error) {
throw error;
}
notifyListeners();
}
_deleteImage(DataSample data )async {
final directory = await getApplicationDocumentsDirectory();
final path = join(directory.path, data.image );
bool isExist = await File(path).exists();
if (isExist) {
await File(path).delete();
}
}
for detail code :
taking or choosing picture from here and passing it to a method =>
class ImageInput extends StatefulWidget {
final Function onSelectImage;
final String imageFile;
ImageInput(this.onSelectImage, this.imageFile);
#override
_ImageInputState createState() => _ImageInputState();
}
class _ImageInputState extends State<ImageInput> {
File _storedImage;
Future _choseImage() async {
try {
PickedFile imageFile = await ImagePicker().getImage(
source: ImageSource.gallery,
maxWidth: 600,
);
_saveImg(imageFile);
} catch (error) {
throw error;
}
}
Future _takeImage() async {
try {
PickedFile imageFile = await ImagePicker().getImage(
source: ImageSource.camera,
maxWidth: 600,
);
_saveImg(imageFile);
} catch (error) {
throw error;
}
}
Future _saveImg(PickedFile imageFile) async {
try {
if (imageFile == null) {
return;
}
bool a = await File(imageFile.path).exists();
setState(() {
if(a){
_storedImage = File(imageFile.path);
}
});
final appDirectory = await sysPath.getApplicationDocumentsDirectory();
final fileName = path
.basename(_storedImage.path); //name of the photo created by camera.
final savedImage = await _storedImage
.copy('${appDirectory.path}/$fileName'); // storing image.
widget.onSelectImage(savedImage.path);
} catch (error) {
throw error;
}
}
#override
void initState() {
// TODO: implement initState
_storedImage = widget.imageFile.isEmpty ? null : File(widget.imageFile);
super.initState();
}
#override
Widget build(BuildContext context) {
return Row(
children: <Widget>[
Container(
height: MediaQuery.of(context).size.height * 0.24,
width: MediaQuery.of(context).size.width * 0.5,
decoration: BoxDecoration(
color: Colors.white,
border: Border.all(width: 1, color: Color(0xFF495464)),
),
child: _storedImage != null
? Image.file(
_storedImage,
fit: BoxFit.cover,
width: double.infinity,
)
: Text(
"No Image Chosen",
style: GoogleFonts.courgette(
fontSize: MediaQuery.of(context).size.width * 0.05),
),
alignment: Alignment.center,
),
SizedBox(width: 10),
Expanded(
child: FittedBox(
child: Column(
crossAxisAlignment: CrossAxisAlignment.start,
children: [
FlatButton.icon(
icon: Icon(
Icons.camera,
color: Color(0xFF495464),
),
label: Text(
'Take Picture',
style: TextStyle(color: Color(0xFF495464), fontSize: 20),
),
onPressed: _takeImage,
),
FlatButton.icon(
icon: Icon(
Icons.photo_library,
color: Color(0xFF495464),
),
label: Text(
'Choose Picture',
style: TextStyle(color: Color(0xFF495464), fontSize: 20),
),
onPressed: _choseImage,
),
],
),
),
),
],
);
}
}
it comes here and then I pass it to the provider delete method given above(I only give the expense delete method above) =>
var _initState = true;
var trData;
String initialPrice = '';
var _newTransaction = DataSample(
id: null,
datetime: null,
title: '',
image: '',
price: 0.0,
description: '',
);
#override
void didChangeDependencies() {
if (_initState) {
trData = ModalRoute.of(context).settings.arguments as Map;
if (trData['id'] != 0) {
if (trData['type'] == "Expense") {
_newTransaction = Provider.of<ExpanseProvider>(context, listen: false)
.findId(trData['id']);
} else {
_newTransaction = Provider.of<IncomeProvider>(context, listen: false)
.findId(trData['id']);
}
_selectedDate = _newTransaction.datetime;
initialPrice = _newTransaction.price.toString();
}
}
_initState = false;
super.didChangeDependencies();
}
final _gKey = GlobalKey<FormState>();
DateTime _selectedDate = DateTime.now();
String _pickedImage = '';
void _selectImage(String pickedImage) {
_pickedImage = pickedImage;
}
void _saveInput(String page) {
final _isValid = _gKey.currentState.validate();
if (!_isValid) {
return;
}
_gKey.currentState.save();
_newTransaction = DataSample(
title: _newTransaction.title,
datetime: _selectedDate,
image: _pickedImage.isEmpty ? _newTransaction.image : _pickedImage,
id: _newTransaction.id,
price: _newTransaction.price,
description: _newTransaction.description,
);
deleteOrUpdate(page);
}
Future<void> deleteOrUpdate(String page) async {
if (_newTransaction.id == null) {
if (page == 'Expense') {
await Provider.of<ExpanseProvider>(context, listen: false)
.addExpanseTransaction(_newTransaction)
.then((value) => Navigator.of(context).pop())
.catchError((error) {
return _onError();
});
} else {
await Provider.of<IncomeProvider>(context, listen: false)
.addIncomeTransaction(_newTransaction)
.then((value) => Navigator.of(context).pop())
.catchError((error) {
return _onError();
});
}
} else {
if (page == 'Expense') {
await Provider.of<ExpanseProvider>(context, listen: false)
.updateExpense(_newTransaction)
.then((value) => Navigator.of(context).pop())
.catchError((error) {
return _onError();
});
} else {
await Provider.of<IncomeProvider>(context, listen: false)
.updateIncome(_newTransaction)
.then((value) => Navigator.of(context).pop())
.catchError((error) {
return _onError();
});
}
}
}
I once faced a similar issue using the async file deletion, I then switched to the deleteSync method. I guess in your case it should have no side effect since you already await for deletion.
Documentation: https://api.flutter.dev/flutter/dart-io/FileSystemEntity/deleteSync.html

Resources