How to store image in flutter firestore and display it - flutter

Trying to store image in books collection flutter but not letting me store and retrieve it later. Please help me trace the bug. Problem is with coverImage that is not letting me store the image URL in firebase so that the image could be displayed when its fetched later.
if (name != null &&
price != null &&
author != null &&
description != null &&
discountpercentage != null &&
rating != null) {
if (action == 'create') {
await books_collection.add({
"name": name,
"price": price,
"author": author,
"description": description,
"discountpercentage": discountpercentage,
"rating": rating,
"createdAt": Timestamp.now(),
"coverImage": Timestamp.now(),
// "url": uploadFilterImage()
});
}
if (action == 'update') {
// Update the product
await books_collection.doc(documentSnapshot!.id).update({
"name": name,
"price": price,
"author": author,
"description": description,
"discountpercentage": discountpercentage,
"rating": rating,
"createdAt": Timestamp.now(),
"coverImage": uploadFilterImage()
});
Future<String> uploadFilterImage() async {
String url = "";
final ImagePicker _picker = ImagePicker();
XFile? image = await _picker.pickImage(source: ImageSource.gallery);
Uint8List fileBytes = await image!.readAsBytes();
if (fileBytes != null) {
final _firebaseStorage = FirebaseStorage.instance;
var name = Timestamp.now().millisecondsSinceEpoch;
print("$name");
var snapshot = _firebaseStorage.ref().child('$name');
print("$name");
TaskSnapshot task = await snapshot.putData(
fileBytes,
SettableMetadata(contentType: 'image/jpeg'),
);
url = await task.ref.getDownloadURL();
if (url.isNotEmpty) {
Get.snackbar("successfull", "image uploaded");
}
}
return url;
}

You need to await the uploadFilterImage() call in order to process the async function and not return a Future, but return the final value instead. The same is true for both your create and update cases.
await books_collection.doc(documentSnapshot!.id).update({
"name": name,
"price": price,
"author": author,
"description": description,
"discountpercentage": discountpercentage,
"rating": rating,
"createdAt": Timestamp.now(),
"coverImage": await uploadFilterImage() // here
});

Related

No object exists at the desired reference

I am trying to get an image from the storage and use the url for a default profile picture but i am getting this error.
firebase_storage/object-not-found No object exists at the desired reference.
This is my code.
void authenticateStudent() async {
User? currentStudent;
final FirebaseAuth firebaseAuth = FirebaseAuth.instance;
await firebaseAuth
.createUserWithEmailAndPassword(
email: umailController.text.trim(),
password: passwordController.text.trim(),
)
.then((auth) {
currentStudent = auth.user;
}).catchError((onError) {
print(onError);
});
if (currentStudent != null) {
FirebaseStorage.instance
.ref()
.child('profile')
.getDownloadURL()
.then((url) {
imageUrl = url;
});
saveDataToFirestore(currentStudent!).then((value) {
Navigator.pop(context);
print("User added successfully");
});
}
}
Future saveDataToFirestore(User currentStudent) async {
FirebaseFirestore.instance
.collection("students")
.doc(currentStudent.uid)
.set({
"studentUID": currentStudent.uid,
"fname": fnameController.text.trim(),
"lname": lnameController.text.trim(),
"Mobile": phoneController.text.trim(),
"Program": selectedProgram,
"student_id": studentidController.text.trim(),
"cohort": selectedCohort,
"umail": currentStudent.email,
"profilepicture": imageUrl,
"active": active,
"status": status
});
}
The database is structured like this
This is my code.
void authenticateStudent() async {
User? currentStudent;
final FirebaseAuth firebaseAuth = FirebaseAuth.instance;
await firebaseAuth
.createUserWithEmailAndPassword(
email: umailController.text.trim(),
password: passwordController.text.trim(),
)
.then((auth) {
currentStudent = auth.user;
}).catchError((onError) {
print(onError);
});
if (currentStudent != null) {
FirebaseStorage.instance
.ref()
.child('profile')
.getDownloadURL()
.then((url) {
imageUrl = url;
});
saveDataToFirestore(currentStudent!).then((value) {
Navigator.pop(context);
print("User added successfully");
});
}
}
Future saveDataToFirestore(User currentStudent) async {
FirebaseFirestore.instance
.collection("students")
.doc(currentStudent.uid)
.set({
"studentUID": currentStudent.uid,
"fname": fnameController.text.trim(),
"lname": lnameController.text.trim(),
"Mobile": phoneController.text.trim(),
"Program": selectedProgram,
"student_id": studentidController.text.trim(),
"cohort": selectedCohort,
"umail": currentStudent.email,
"profilepicture": imageUrl,
"active": active,
"status": status
});
}
The database is structured like this
Your code says:
FirebaseStorage.instance
.ref()
.child('profile')
.getDownloadURL()
But in the screenshot, the file is called profile.png. The path must match completely and exactly, so:
FirebaseStorage.instance
.ref()
.child('profile.png')
.getDownloadURL()

How do I get a list of column data from an array into a list in flutter (dart)

I've been trying to get a column from a array into a list, I'm can't seem to figure how to do it, and I couldn't find a solution online. Most of the array i find only aren't nested.
{
"status": true,
"data": {
"1": [
{
"id": "1",
"name": "500MB [SME]",
"price": "220",
"telco_price": "0"
},
{
"id": "2",
"name": "1GB [SME]",
"price": "410",
"telco_price": "0"
},
{
"id": "3",
"name": "2GB [SME]",
"price": "800",
"telco_price": "0"
},
],
"2": [
{
"id": "AIR1000",
"name": "1.5GB ",
"price": "920",
"telco_price": "920"
},
{
"id": "AIR2000",
"name": "4.5GB",
"price": "1840",
"telco_price": "1840"
},
{
"id": "AIR2500",
"name": "6GB",
"price": "2300",
"telco_price": "2300"
}
],
"3": [
{
"id": "9MOB500",
"name": "500MB",
"price": "400",
"telco_price": "400"
},
{
"id": "9MOB1000",
"name": "1.5GB",
"price": "850",
"telco_price": "850"
},
{
"id": "9MOB2000",
"name": "2GB",
"price": "1020",
"telco_price": "1020"
},
]
}
}
firstly, i want to get all names into a list variable which i can then populate easily on one of my page...
i want it into var nameList = []; where its' stated "1" then the next into another variable like that
Do on fetch like
import 'package:http/http.dart' as http;
....
List<DataClass> nameList = [];
fetch() async {
final response = await http.get(Uri.parse(url));
if (response.statusCode == 200) {
final data = jsonDecode(response.body);
MyResponse myResponse = MyResponse.fromJson(data);
final values = myResponse.data?.values;
if (values != null) {
for (final v in values) {
if(v!=null) nameList.addAll(v.toList());
}
}
}
}
Try this model class
import 'dart:convert';
class MyResponse {
final bool? status;
final Map<String, List<DataClass>?>? data;
MyResponse({
this.status,
required this.data,
});
Map<String, dynamic> toMap() {
final result = <String, dynamic>{};
if(status != null){
result.addAll({'status': status});
}
if(data != null){
result.addAll({'data': data});
}
return result;
}
factory MyResponse.fromMap(Map<String, dynamic> map) {
return MyResponse(
status: map['status'],
data: Map<String, List<DataClass>?>.from(map['data']),
);
}
String toJson() => json.encode(toMap());
factory MyResponse.fromJson(String source) => MyResponse.fromMap(json.decode(source));
}
class DataClass {
final String? id;
final String? name;
final String? price;
final String? telco_price;
DataClass({
this.id,
this.name,
this.price,
this.telco_price,
});
Map<String, dynamic> toMap() {
final result = <String, dynamic>{};
if (id != null) {
result.addAll({'id': id});
}
if (name != null) {
result.addAll({'name': name});
}
if (price != null) {
result.addAll({'price': price});
}
if (telco_price != null) {
result.addAll({'telco_price': telco_price});
}
return result;
}
factory DataClass.fromMap(Map<String, dynamic> map) {
return DataClass(
id: map['id'],
name: map['name'],
price: map['price'],
telco_price: map['telco_price'],
);
}
String toJson() => json.encode(toMap());
factory DataClass.fromJson(String source) =>
DataClass.fromMap(json.decode(source));
}

The body might complete normally, causing 'null' to be returned, but the return type, 'FutureOr<DataModel>', is a potentially non-nullable type

Future<DataModel> submitData(
int id,
String user,
String userId,
String title,
String description,
String location,
String jobType,
int category,
String salary,
String companyName,
String url,
DateTime lastDate,
bool isPublished,
bool isClosed,
DateTime timestamp) async {
var response = await http.post(Uri.https('jobspace-isnp.herokuapp.com', 'api/jobs'),
body: {
"id": id,
"user": user,
"user_id": userId,
"title": title,
"description": description,
"location": location,
"job_type": jobType,
"category": category,
"salary": salary,
"company_name": companyName,
"url": url,
"last_date": lastDate,
"is_published": isPublished,
"is_closed": isClosed,
});
var data = response.body;
print(data);
if (response.statusCode == 201) {
String responseString = response.body;
dataModelFromJson(responseString);
} else
return null;
}
I am getting this error: The body might complete normally, causing 'null' to be returned, but the return type, 'FutureOr', is a potentially non-nullable type.
Try adding either a return or a throw statement at the end.
How can I solve it?
Using null safety in your code, can submitData function return null value. to do that just add ? after DataModel so your code will be like this
Future<DataModel?> submitData(
int id,
String user,
String userId,
String title,
String description,
String location,
String jobType,
int category,
String salary,
String companyName,
String url,
DateTime lastDate,
bool isPublished,
bool isClosed,
DateTime timestamp) async {
var response = await http.post(Uri.https('jobspace-isnp.herokuapp.com', 'api/jobs'),
body: {
"id": id,
"user": user,
"user_id": userId,
"title": title,
"description": description,
"location": location,
"job_type": jobType,
"category": category,
"salary": salary,
"company_name": companyName,
"url": url,
"last_date": lastDate,
"is_published": isPublished,
"is_closed": isClosed,
});
var data = response.body;
print(data);
if (response.statusCode == 201) {
String responseString = response.body;
dataModelFromJson(responseString);
} else
return null;
}
read more about null safety

i want to get the image link in firestore

i want to get the image link in database, but i get the image url in other document and (name & etc) in other document.
database.collection("car").add({
"item Name": nameText.text,
"item Price": priceText.text,
"seller Number": cellNoText.text,
"seller add": addText.text,
"image 1 Url": await uploadPic()
.then((value) async {
DocumentReference docRef = Firestore
.instance
.collection("car")
.document();
await docRef.setData(
{"image 1 Url": value},
merge: true);
}),
});
this is the function to upload the image to firebase storage
uploadPic() async {
String fileName = path.basename(_image1.path);
StorageReference reference = storage.ref().child(fileName);
StorageUploadTask uploadTask = reference.putFile(_image1);
StorageTaskSnapshot taskSnapshot = await uploadTask.onComplete;
String url = await taskSnapshot.ref.getDownloadURL();
imageUrl1 = url;
return url;
}
can you guys help?
Your image url has been created in the wrong location because of the then of the uploadPic(), and its null in the car document because you need to call the Future function before adding it to the document:
Future uploadPic() async {
String fileName = path.basename(_image1.path);
StorageReference reference = storage.ref().child(fileName);
StorageUploadTask uploadTask = reference.putFile(_image1);
StorageTaskSnapshot taskSnapshot = await uploadTask.onComplete;
String url = await taskSnapshot.ref.getDownloadURL();
return url;
}
Future saveData() async {
String imageUrl = await uploadPic(); //calling and adding the result to a variable before adding
database.collection("car").add({
"item Name": nameText.text,
"item Price": priceText.text,
"seller Number": cellNoText.text,
"seller add": addText.text,
"imageUrl": imageUrl,
});
}

How do i convert a String to a List<Map<String,String>>

I have a list which contains several keys and values, which are then mapped into a DataTable to be displayed.
List<Map<String, String>> listOfColumns = [
{"Name": "John", "Number": "1", "State": " "},
{"Name": "Brad", "Number": "2", "State": " "},
{"Name": "Ryan", "Number": "3", "State": " "},
{"Name": "Grant", "Number": "4", "State": " "},
];
Now, i want the data in the data table to be saved. So I simply used the File IO system i created an asynchronous function called _save() and _read(), in _save() i converted listOfColumns to a string.
_read() async {
try {
final directory = await getExternalStorageDirectory();
final file = File('${directory.path}/my_file.txt');
text = await file.readAsString();
} catch (e) {
print("Couldn't read file");
}
}
_save() async {
final directory = await getExternalStorageDirectory();
final file = File('${directory.path}/my_file.txt');
final List<Map<String, String>> data = listOfColumns;
await file.writeAsString(data.toString());
print('saved');
}
Now when it comes to reading the data from the file, here's the thing - How do i actually turn the variable text back into List<Map<String,String>>? Im totally lost on how to achieve this. Any help is highly appreciated. Thanks.
You should actually save it as JSON in the first place (using jsonEncode and then you can easily convert it back:
Future<void> _save() async {
...
final jsonString = jsonEncode(listOfColumns);
await file.writeAsString(jsonString);
}
Now, you can easily load your data using jsonDecode:
Future<void> _read() async {
...
final decoded = jsonDecode(await file.readAsString()) as List;
listOfColumns = decoded.cast<Map<String, dynamic>>()
.map((map) => map.cast<String, String>()).toList();
}