Reputation: 193
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
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
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