gjs
gjs

Reputation: 193

Update Flutter UI after changing data on Firebase Firestore

I have an app with a profile page with username, email, and profile picture.

What I am trying to do is, the user click on a button to change the profile picture, opening a new page with a simple Circle Avatar Widget and a button, which will upload the image to Firebase Storage and Firebase Firestore, adding to the Firestore collection of that specific current user uid.

Everything works fine, I can see the changes on the Firebase storage, the image being added by the uid + the URL on the current user collection.

This is the code of the edit_user_image_screen:

import 'dart:io';

import 'package:cloud_firestore/cloud_firestore.dart';
import 'package:firebase_auth/firebase_auth.dart';
import 'package:firebase_storage/firebase_storage.dart';
import 'package:flutter/material.dart';
import 'package:image_picker/image_picker.dart';
import 'package:tradie_app/scr/providers/authService.dart';
import 'package:tradie_app/scr/widgets/loading.dart';

class EditCompanyImageScreen extends StatefulWidget {
  @override
  _EditCompanyImageScreenState createState() => _EditCompanyImageScreenState();
}

class _EditCompanyImageScreenState extends State<EditCompanyImageScreen> {
  // Keep track of the form for validation
  final _formKey = GlobalKey<FormState>();

  // Loading Icon
  bool loading = false;

  final AuthService _authService = AuthService();
  final FirebaseAuth _firebaseAuth = FirebaseAuth.instance;
  final FirebaseFirestore _firebaseFirestore = FirebaseFirestore.instance;

  File _image;

  Future getImage(bool gallery) async {
    ImagePicker picker = ImagePicker();
    PickedFile pickedFile;
    // Let user select photo from gallery
    if (gallery) {
      pickedFile = await picker.getImage(
        source: ImageSource.gallery,
      );
    }
    setState(() {
      if (pickedFile != null) {
        _image = File(pickedFile.path);
        uploadFile(_image); // Use if you only need a single picture
      } else {
        print('No image selected.');
      }
    });
  }

  Future<String> uploadFile(File image) async {
    String downloadURL;
    Reference ref = FirebaseStorage.instance
        .ref()
        .child("images/${_firebaseAuth.currentUser.uid}");
    await ref.putFile(image);
    downloadURL = await ref.getDownloadURL();
    return downloadURL;
  }

  Future uploadToFirebase() async {
    final CollectionReference users =
        _firebaseFirestore.collection("Companies");
    final String uid = _firebaseAuth.currentUser.uid;

    String url = await uploadFile(
        _image); // this will upload the file and store url in the variable 'url'
    await users.doc(uid).update({'url': url});
    final result = await users.doc(uid).get();
    return result.data()["url"];
  }

  @override
  Widget build(BuildContext context) {
    return loading
        ? Loading()
        : Scaffold(
            appBar: AppBar(
              title: Text("Update Profile Image"),
            ),
            body: Form(
              key: _formKey,
              child: Column(
                children: [
                  Container(
                    child: Stack(
                      children: <Widget>[
                        Align(
                          alignment: Alignment.center,
                          child: IconButton(
                            icon: Icon(Icons.camera_alt),
                            onPressed: () async {
                              getImage(true);
                            },
                          ),
                        ),
                        Container(
                          child: _image != null
                              ? Container(
                                  height: 200,
                                  width: 200,
                                  decoration: BoxDecoration(
                                    image: DecorationImage(
                                        image: FileImage(
                                          _image,
                                        ),
                                        fit: BoxFit.contain),
                                  ),
                                )
                              : Container(
                                  decoration: BoxDecoration(
                                    color: Colors.grey[200],
                                    borderRadius: BorderRadius.circular(50),
                                  ),
                                  width: 100,
                                  height: 100,
                                  child: Icon(
                                    Icons.camera_alt,
                                    color: Colors.grey[800],
                                  ),
                                ),
                        ),
                      ],
                    ),
                  ),
                  Row(
                    children: [
                      ElevatedButton(
                        style: ElevatedButton.styleFrom(
                          primary: Colors.black,
                        ),
                        child: Text(
                          "Submit",
                          style: TextStyle(color: Colors.white),
                        ),
                        onPressed: () async {
                          uploadToFirebase();
                          Navigator.pop(context);
                        },
                      ),
                    ],
                  ),
                ],
              ),
            ),
          );
  }
}

And on the company_profile_screen, I have this snippet of code:

Stream getCompanyImageData() async* {
    final CollectionReference users =
        _firebaseFirestore.collection("Companies");
    final String uid = _firebaseAuth.currentUser.uid;
    final result = await users.doc(uid).get();
    yield result.data()["url"];
  }

My problem:

When I go back from edit_user_image_screen to company_screen, the App UI is not updating, I can see the changes on Firebase, and if I reload Android Studio, I can see the changes on the UI, but not automatically.

Here is the code where I am displaying the image on the company_screen:

Column(
    children: [
                                  StreamBuilder(
                                    stream: getCompanyImageData(),
                                    builder: (BuildContext context,
                                        AsyncSnapshot snapshot) {
                                      if (snapshot.connectionState ==
                                          ConnectionState.waiting) {
                                        return Center(
                                          child: CircularProgressIndicator(),
                                        );
                                      }
                                      return Image.network(
                                        snapshot.data.toString(),
                                        width: 100,
                                        height: 100,
                                      );
                                    },
                                  ),
                                ],
                              ),

Upvotes: 1

Views: 3032

Answers (2)

Huthaifa Muayyad
Huthaifa Muayyad

Reputation: 12383

Try it like this, and cancel your top function getCompanyImageData()

Column(children: [
      StreamBuilder(
        stream: _firebaseFirestore.collection("Companies").doc(_firebaseAuth.currentUser.uid).snapshots(),
        builder: (BuildContext context, AsyncSnapshot snapshot) {
          if (snapshot.connectionState == ConnectionState.waiting) {
            return Center(
              child: CircularProgressIndicator(),
            );
          }
          return Image.network(
            snapshot.data.data()["url"],
            width: 100,
            height: 100,
          );
        },
      ),

Upvotes: 2

M.M.Hasibuzzaman
M.M.Hasibuzzaman

Reputation: 1151

This would depend on your state management,

CollectionRef.users.doc(ViewModelUser.user.value.mobile).snapshots().listen((event) {
      ViewModelUser.setUser(UserModel.fromJson(event.data()));
    });

This is my code where I listen for changes in my profile, when there is a change firebase sends me the updated data and I update my userData, my state management does the rest of updating the UI.

Upvotes: 1

Related Questions