Upload and store image into firebase using flutter - firebase

I am trying to work out how a user can upload a eg a profile image and have this store in firebase. this is the code I have so far which shows the image picker but I cannot get the path nor have the image uploaded
dynamic _showSelectImageDialog() {
return Platform.isIOS ? _iosBottomSheet() : _androidDialog();
}
Future _iosBottomSheet() async => showCupertinoModalPopup(
context: context,
builder: (context) {
return CupertinoActionSheet(
// title: Text('Add Photo'),
actions: <Widget>[
CupertinoActionSheetAction(
onPressed: () => _upload(ImageSource.camera),
child: const Text('Take Photo'),
),
CupertinoActionSheetAction(
onPressed: () => _upload(ImageSource.gallery),
child: const Text('Choose Photo'),
),
],
cancelButton: CupertinoActionSheetAction(
onPressed: () => Navigator.pop(context),
child: const Text('Cancel'),
),
);
},
);
_androidDialog() {
showDialog(
context: context,
builder: (context) {
return SimpleDialog(
title: const Text('Add Photo'),
children: <Widget>[
SimpleDialogOption(
onPressed: () => _upload(ImageSource.camera),
child: const Text('Take Photo'),
),
SimpleDialogOption(
onPressed: () => _upload(ImageSource.gallery),
child: const Text('Choose From Gallery'),
),
SimpleDialogOption(
onPressed: () => Navigator.pop(context),
child: const Text(
'Cancel',
style: TextStyle(
color: Colors.redAccent,
),
),
),
],
);
},
);
}
// Select and image from the gallery or take a picture with the camera
// Then upload to Firebase Storage
_upload(ImageSource source) async {
var picker = ImagePicker();
PickedFile pickedImage;
try {
pickedImage = (await picker.pickImage(source: source, maxWidth: 1920))
as PickedFile;
File imageFile = File(pickedImage.path);
try {
// Uploading the selected image with some custom meta data
await storageRef
.child('uploads/user/avatar/${widget.user.id}/$imageFile.jpg')
.putFile(imageFile);
print(imageFile);
// Refresh the UI
setState(() {});
} on FirebaseException {
// print(error);
}
} catch (err) {
print(err);
}
Navigator.pop(context);
}
_displayProfileImage() {
// No new profile image
if (_profileImage == null) {
// No existing profile image
if (widget.user.profileImageUrl.isEmpty) {
// Display placeholder
return AssetImage('assets/images/user_placeholder.jpg');
} else {
// User profile image exists
return CachedNetworkImageProvider(widget.user.profileImageUrl);
}
} else {
// New profile image
return FileImage(File(_profileImage.path));
}
}

1) Pick image using image picker
Put this package in your pubspec.yaml
image_picker: ^0.8.4+4
2) Use this code to pick image
image = await _picker.pickImage(source: ImageSource.gallery);
3) save the image in firebase cloud and get the image URL
Put these packages in your pubspec.yaml
cloud_firestore: ^3.1.0
firebase_storage: ^10.1.0
firebase_core: ^1.10.0
Use this code to upload the image to cloud storage
var imageFile = File(image!.path);
String fileName = basename(imageFile.path);
FirebaseStorage storage = FirebaseStorage.instance;
Reference ref =
storage.ref().child("Image-" + productname.text);
Use this code to get the URL
UploadTask uploadTask = ref.putFile(imageFile);
await uploadTask.whenComplete(() async {
var url = await ref.getDownloadURL();
image_url = url.toString();
}).catchError((onError) {
print(onError);
});
4) Finally add image url to firebase database
Code to add data to firebase database
Map<String, dynamic> demodata = {
"image_url": imageurl
};
CollectionReference collectionreference =
FirebaseFirestore.instance.collection(image);
collectionreference.add(demodata);

Related

My question is about how to preview an image before it is uploaded to firebase in flutter? (image_picker_package)(provider)

In firebase Storage Service Dart File:
//storage reference
Future<String> uploadUserImage(File? image, String path) async {
String imageUrl;
Reference ref =
_firebaseStorage.ref().child('userImages').child('$path.jpg');
await ref.putFile(image!);
imageUrl = await ref.getDownloadURL();
return imageUrl;
}
In User Provider Dart File(State management) using ChangeNotifier:
//getter
void changeImageUrl(String imageUrl) {
_imageUrl = imageUrl;
notifyListeners();
}
//method
uploadPhotoToFirebase(File fileImage) async {
//used firebase user uid for path and File fileImage for File
try {
var imageUrl = await _storageService.uploadUserImage(fileImage, _userUid);
//assign downloadedUrl to getter
changeImageUrl(imageUrl);
} on PlatformException catch (e) {
print('Failed to pick image: $e');
}
}
User Profile Screen(UI):
//method for Image_picker
Future _pickPhotos(ImageSource imageSource) async {
final userProvider = Provider.of<UserProvider>(context, listen: false);
try {
final image = (await _picker.pickImage(source: imageSource));
if (image == null) return;
final imageTem = File(image.path);
//assigning File(String path) to firebase storage
await userProvider.uploadPhotoToFirebase(imageTem);
} on PlatformException catch (e) {
print('Failed to pick image: $e');
}
}
//Inside the build
Column(
crossAxisAlignment: CrossAxisAlignment.center,
children: [
CircleAvatar(
backgroundColor: darkGrey,
radius: 54.0,
//assign private String _imageUrl
child: _imageUrl != null
? ClipRRect(
borderRadius: BorderRadius.circular(50.0),
child: Image.network(
_imageUrl!,
width: 100,
height: 200,
fit: BoxFit.cover,
),
)
: Center(
child: Icon(Icons.person_rounded,
color: appColor, size: 80.0))),
TextButton(
style: ButtonStyle(
overlayColor: MaterialStateColor.resolveWith(
(states) => Colors.transparent)),
child: EditPhotoText(),
onPressed: () {
_pickPhotos(ImageSource.gallery);
/* Expecting this to change the local state to show
image preview but doesn't work.
*/
userProvider.changeImageUrl(_imageUrl!);
}),
Image is being stored in firebase and fetching image is working too. I am not able to figure out how to preview the image before uploading it to firebase. I think I have to use the set state to preview locally but I don't know how or is there a way I can do that through the provider package?

give permission to read and use photos

I want to give my users the opportunity to upload a profile picture. Therefor I wrote some code with permissionHandler and image_picker packages.
MaterialButton(
child: Text('Profilbild auswählen'),
onPressed: () async {
var status = await Permission.photos.status;
print(status);
if (status.isGranted) {
final pickedFile =
await _picker.pickImage(source: ImageSource.gallery);
print(pickedFile);
setState(() {
if (pickedFile != null) {
_imageFile = File(pickedFile.path);
} else {
print('No image selected.');
}
});
} else {
showDialog(
context: context,
builder: (BuildContext context) => CupertinoAlertDialog(
title: Text('Bilder Zugriff'),
content: Text(
'Wir brauchen zugriff auf deine Bilder um ein Profilbild hochladen zu können!'),
actions: <Widget>[
CupertinoDialogAction(
child: Text('Grant'),
onPressed: () async {
Navigator.of(context).pop();
await Permission.photos.request();
}),
CupertinoDialogAction(
child: Text('Settings'),
onPressed: () => openAppSettings(),
),
]));
}
}),
But the permission stays at status 'denied' although the iPhone-Settings allows the usage of gallery. How can I change that status in the application and does the rest of the code makes sense to upload the image to firebase? How is it possible to change the image live on the screen? Thought it works with .setState()...

How to upload image to Firebase Storage and automatically store it in Cloud Firestore?

I'm currently stuck at where I'm trying to upload image to Firestore Storage and automatically store the image URL to Cloud Firestore. I have tried to manually upload the image to Firebase Storage and pasting the image url to Cloud Firestore then retrieving it to show the image in my app and it works. Heres the coding that I have done so far:
models/enter.dart
class Enter {
final String enterId;
final String enter;
final String price;
final String url;
Enter({this.enter, this.price, #required this.enterId, this.url});
factory Enter.fromJson(Map<String, dynamic> json){
return Enter(
enter: json['enter'],
price: json['price'],
url: json['url'],
enterId: json['enterId']
);
}
Map<String,dynamic> toMap(){
return {
'enter':enter,
'price':price,
'url':url,
'enterId':enterId
};
}
}
services/firestore_service2
import 'package:cloud_firestore/cloud_firestore.dart';
import 'package:journal_app/src/models/enter.dart';
class FirestoreService2 {
FirebaseFirestore _db = FirebaseFirestore.instance;
//Get Entries
Stream<List<Enter>> getEnter(){
return _db
.collection('enters')
.snapshots()
.map((snapshot) => snapshot.docs
.map((doc) => Enter.fromJson(doc.data()))
.toList());
}
//Upsert
Future<void> setEnter(Enter enter){
var options = SetOptions(merge:true);
return _db
.collection('enters')
.doc(enter.enterId)
.set(enter.toMap(),options);
}
//Delete
Future<void> removeEnter(String enterId){
return _db
.collection('enters')
.doc(enterId)
.delete();
}
}
provider/enter_provider.dart
import 'package:flutter/material.dart';
import 'package:journal_app/src/models/enter.dart';
import 'package:journal_app/src/services/firestore_service2.dart';
import 'package:uuid/uuid.dart';
class EnterProvider with ChangeNotifier {
final firestoreService = FirestoreService2();
String _enter;
String _price;
String _enterId;
String _url;
var uuid = Uuid();
//Getters
String get enter => _enter;
String get price => _price;
String get url => _url;
Stream<List<Enter>> get enters => firestoreService.getEnter();
//Setters
set changeEnter(String enter){
_enter = enter;
notifyListeners();
}
set changePrice(String price){
_price = price;
notifyListeners();
}
set changeUrl(String url){
_url = url;
notifyListeners();
}
//Functions
loadAll(Enter enter){
if (enter != null && price != null){
_enter =enter.enter;
_price =enter.price;
_url=enter.url;
_enterId = enter.enterId;
} else {
_enter = null;
_price = null;
_url = null;
_enterId = null;
}
}
saveEnter(){
if (_enterId == null){
//Add
var newEnter = Enter(enter: _enter, price: _price, url: _url, enterId: uuid.v1());
print(newEnter.enter);
print(newEnter.price);
print(newEnter.url);
firestoreService.setEnter(newEnter);
} else {
//Edit
var updatedEnter = Enter(enter: _enter, price: _price, url: _url, enterId: _enterId);
firestoreService.setEnter(updatedEnter);
}
}
removeEnter(String enterId){
firestoreService.removeEnter(enterId);
}
}
screens/enter.dart where user insert product name, price and image
import 'package:date_format/date_format.dart';
import 'package:flutter/material.dart';
import 'package:journal_app/src/models/enter.dart';
import 'package:journal_app/src/providers/enter_provider.dart';
import 'package:provider/provider.dart';
class EnterScreen extends StatefulWidget {
final Enter enter;
final Enter price;
final Enter category;
EnterScreen({this.enter, this.price, this.category});
#override
_EnterScreenState createState() => _EnterScreenState();
}
class _EnterScreenState extends State<EnterScreen> {
final enterController = TextEditingController();
final enterController2 = TextEditingController();
#override
void dispose() {
enterController.dispose();
enterController2.dispose();
super.dispose();
}
#override
void initState() {
final enterProvider = Provider.of<EnterProvider>(context,listen: false);
if (widget.enter != null){
//Edit
enterController.text = widget.enter.enter;
enterController2.text = widget.enter.price;
enterProvider.loadAll(widget.enter);
enterProvider.loadAll(widget.price);
} else {
//Add
enterProvider.loadAll(null);
}
super.initState();
}
#override
Widget build(BuildContext context) {
final enterProvider = Provider.of<EnterProvider>(context);
return Scaffold(
appBar: AppBar(title: Text('Products')),
body: Padding(
padding: const EdgeInsets.all(8.0),
child: ListView(
children: [
TextField(
decoration: InputDecoration(
labelText: 'Product Name', border: InputBorder.none,
),
style: TextStyle(color: Colors.black, fontSize: 25),
maxLines: 5,
minLines: 2,
onChanged: (String value) => enterProvider.changeEnter = value,
controller: enterController,
),
TextField(
decoration: InputDecoration(
labelText: 'Product Price', border: InputBorder.none,
),
style: TextStyle(color: Colors.black, fontSize: 25),
maxLines: 5,
minLines: 2,
onChanged: (String value) => enterProvider.changePrice = value,
controller: enterController2,
),
RaisedButton(
color: Theme.of(context).accentColor,
child: Text('Save',style: TextStyle(color: Colors.white, fontSize: 20)),
onPressed: () {
enterProvider.saveEnter();
Navigator.of(context).pop();
},
),
(widget.enter != null) ? RaisedButton(
color: Colors.red,
child: Text('Delete',style: TextStyle(color: Colors.white, fontSize: 20)),
onPressed: () {
enterProvider.removeEnter(widget.enter.enterId);
Navigator.of(context).pop();
},
): Container(),
],
),
),
);
}
}
screens/product.dart where this screen show the product name, price and image in listview
import 'package:date_format/date_format.dart';
import 'package:flutter/material.dart';
import 'package:journal_app/src/models/enter.dart';
import 'package:journal_app/src/providers/enter_provider.dart';
import 'package:journal_app/src/screens/enter.dart';
import 'package:provider/provider.dart';
class ProductScreen extends StatelessWidget {
#override
Widget build(BuildContext context) {
final enterProvider = Provider.of<EnterProvider>(context);
return Scaffold(
appBar: AppBar(
title: Text('Products'),
),
body: StreamBuilder<List<Enter>>(
stream: enterProvider.enters,
builder: (context, snapshot) {
return ListView.builder(
itemCount: snapshot.data.length,
itemBuilder: (context, index) {
return ListTile(
leading: Image.network(
snapshot.data[index].url,
width: 100,
height: 100,
fit: BoxFit.fitWidth,
),
trailing:
Icon(Icons.edit, color: Theme.of(context).accentColor),
title: Text(
snapshot.data[index].enter, style: TextStyle(fontSize: 25),
),
subtitle: Text(
snapshot.data[index].price,
),
onTap: () {
Navigator.of(context).push(MaterialPageRoute(
builder: (context) =>
EnterScreen(enter: snapshot.data[index], price: snapshot.data[index])));
},
);
});
}),
floatingActionButton: FloatingActionButton(
child: Icon(Icons.add),
onPressed: () {
Navigator.of(context)
.push(MaterialPageRoute(builder: (context) => EnterScreen()));
},
),
);
}
}
The goal is to upload image to Firebase Storage, storing the image url at the same time when uploading new image.
I need advice for this project.
In order to upload image to Firebase Storage & save it in Cloud Firestore, you need to do the following:
Step 1: Get the image that you want to upload
For this, you can use the image_picker package
It will give you a PickedFile object (let's say it pickedFile). Convert this object to a File object by using this code:
final file = File(pickedFile.path);
Step 2: Upload this file to Firebase Storage:
Give the image that you want to upload a unique name.
final imageName = '${DateTime.now().millisecondsSinceEpoch}.png';
Create Firebase Storage Reference:
final firebaseStorageRef = FirebaseStorage.instance
.ref()
.child('images/$imageName'); // This will create a images directory in Firebase storage & save your image in that directory
Start uploading image:
final uploadTask = firebaseStorageRef.putFile(file);
final taskSnapshot = await uploadTask.onComplete;
Get the image URL:
final _fileURL = await taskSnapshot.ref.getDownloadURL();
Save this image URL in Cloud Firestore.
// This will save the image in "images" collection & update the "uploadedImage" value of document with id the same as the value of "id" variable.
await FirebaseFirestore.instance.collection(images).doc(id).update({'uploadedImage': _fileURL});
If you are updating an existing object then use the update method or else you can use the set method.
In your case you must follow bellow steps
First upload your image to Firebase Storage and get the download URL
Now you have the download URL and you can Upload your Enter object to Cloud FireStore with the url
Bellow method shows how could you store the image and get the download url list
Future<String> uploadImage(var imageFile ) async {
StorageReference ref = storage.ref().child("/photo.jpg");
StorageUploadTask uploadTask = ref.putFile(imageFile);
var dowurl = await (await uploadTask.onComplete).ref.getDownloadURL();
url = dowurl.toString();
return url;
}

How To Add URL From Cloud Firestore Using Using url_launcher Package

I am creating a Card layout in Flutter using Cloud Firestore. The Card contains an image, two IconButtons and some text. I want the IconButtons to open URL links that I add as a string in Firebase. How do I do this with the url_launcher package? I tried replacing const url = 'example.com'; inside the _launchURL function with const url = record.url but goth thrown an undefined error for record.
I am very new to development and Stackoverflow so if I can structure the question better please let me know. Thanks!
Row(
mainAxisAlignment: MainAxisAlignment.center,
children: <Widget>[
IconButton(
icon: Icon(FontAwesomeIcons.youtube),
onPressed: _launchURL(),
),
IconButton(
icon: Icon(FontAwesomeIcons.google),
onPressed: _launchURL(),
),
],
),
Container(
child: Text(record.gameParagraph),
),
],
),
_launchURL() async {
const url = 'example.com'; // URL to be added from Cloud Firestore
if (await canLaunch(url)){
await launch(url);
} else {
throw 'Could not launch $url';
}
}
class Record {
final String gameParagraph;
final String url;
final DocumentReference reference;
Record.fromMap(Map<String, dynamic> map, {this.reference})
: assert(map['gameParagraph'] != null),
assert(map['url'] != null),
gameParagraph = map['gameParagraph'],
url = map['url'];
Record.fromSnapshot(DocumentSnapshot snapshot)
: this.fromMap(snapshot.data, reference: snapshot.reference);
#override
String toString() => "Record<$gameParagraph:$url>";
}
you can add make _launchURL() to take a string value which will be your url _launchURL(String url) and then
_launchURL(String url) async {
if (await canLaunch(url)){
await launch(url);
} else {
throw 'Could not launch $url';
}
}
//
IconButton(
icon: Icon(FontAwesomeIcons.google),
onPressed: (){
_launchURL(url:record.url),// or _launchURL(record.url)}
),

Flutter: How to pass parameter to Future async function

I have to pass parameter to Future async function from floatingbutton
My Codes like
FloatingActionButton(
onPressed: getImageFromCam,
tooltip: 'Pick Image',
child: Icon(Icons.add_a_photo),
),
And
Future getImageFromCam() async { // for camera
var image = await ImagePicker.pickImage(source: ImageSource.camera);
setState(() {
_image = image;
});
}
It is multiple button so i have to pass index to async function.
Can anyone please help to solve this.
Thanks in advance
Sathish
You cannot explicitly specify any argument when using a tear-off. Instead, you should manually define a closure:
FloatingActionButton(
onPressed: () => getImageFromCam(index),
tooltip: 'Pick Image',
child: Icon(Icons.add_a_photo),
);
...
Future<void> getImageFromCam(int index) async {
// Do whatever you want with `index`.
final image = await ImagePicker.pickImage(source: ImageSource.camera);
setState(() => _image = image);
}

Resources