title: How to upload image to Firebase Storage and automatically store it in Cloud Firestore?
body: <p>I'm currently stuck at where I'm trying to upload image to <code>Firestore Storage</code> and automatically store the image <code>URL</code> to <code>Cloud Firestore</code>. I have tried to manually upload the image to <code>Firebase Storage</code> and pasting the image url to <code>Cloud Firestore</code> then retrieving it to show the image in my app and it works. Heres the coding that I have done so far:</p>
  <p><code>models/enter.dart</code></p>
  <pre><code>
  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&lt;String, dynamic&gt; json){
      return Enter(
          enter: json['enter'],
          price: json['price'],
          url: json['url'],
          enterId: json['enterId']
      );
    }
  
    Map&lt;String,dynamic&gt; toMap(){
      return {
        'enter':enter,
        'price':price,
        'url':url,
        'enterId':enterId
      };
    }
  }
  </code></pre>
  <p><code>services/firestore_service2</code></p>
  <pre><code>import 'package:cloud_firestore/cloud_firestore.dart';
  import 'package:journal_app/src/models/enter.dart';
  
  class FirestoreService2 {
    FirebaseFirestore _db = FirebaseFirestore.instance;
  
    //Get Entries
    Stream&lt;List&lt;Enter&gt;&gt; getEnter(){
      return _db
          .collection('enters')
          .snapshots()
          .map((snapshot) =&gt; snapshot.docs
          .map((doc) =&gt; Enter.fromJson(doc.data()))
          .toList());
    }
  
    //Upsert
    Future&lt;void&gt; setEnter(Enter enter){
      var options = SetOptions(merge:true);
  
      return _db
          .collection('enters')
          .doc(enter.enterId)
          .set(enter.toMap(),options);
    }
  
    //Delete
    Future&lt;void&gt; removeEnter(String enterId){
      return _db
          .collection('enters')
          .doc(enterId)
          .delete();
    }
  
  }
  </code></pre>
  <p><code>provider/enter_provider.dart</code></p>
  <pre><code>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 =&gt; _enter;
    String get price =&gt; _price;
    String get url =&gt; _url;
    Stream&lt;List&lt;Enter&gt;&gt; get enters =&gt; 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 &amp;&amp; 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);
    }
  
  }
  </code></pre>
  <p><code>screens/enter.dart</code> where user insert product name, price and image</p>
  <pre><code>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() =&gt; _EnterScreenState();
  }
  
  class _EnterScreenState extends State&lt;EnterScreen&gt; {
  
    final enterController = TextEditingController();
    final enterController2 = TextEditingController();
  
    @override
    void dispose() {
      enterController.dispose();
      enterController2.dispose();
      super.dispose();
    }
  
    @override
    void initState() {
      final enterProvider = Provider.of&lt;EnterProvider&gt;(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&lt;EnterProvider&gt;(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) =&gt; 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) =&gt; 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(),
            ],
          ),
        ),
      );
    }
  }
  </code></pre>
  <p><code>screens/product.dart</code> where this screen show the product name, price and image in listview</p>
  <pre><code>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&lt;EnterProvider&gt;(context);
      return Scaffold(
        appBar: AppBar(
          title: Text('Products'),
        ),
        body: StreamBuilder&lt;List&lt;Enter&gt;&gt;(
            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) =&gt;
                                EnterScreen(enter: snapshot.data[index], price: snapshot.data[index])));
                      },
                    );
                  });
            }),
        floatingActionButton: FloatingActionButton(
          child: Icon(Icons.add),
          onPressed: () {
            Navigator.of(context)
                .push(MaterialPageRoute(builder: (context) =&gt; EnterScreen()));
          },
        ),
      );
    }
  }
  </code></pre>
  <p>The goal is to <code>upload</code> image to <code>Firebase Storage</code>, storing the <code>image url</code> at the same time when <code>uploading</code> new image.</p>
  <p>I need advice for this project.</p>