Issue with where to put Provider to access data

Viewed 48

I am new to Flutter and taking a course at Udemy while simultaneously developing my own app using what I am learning. I am trying to code a simple profile page where the user can change their profile picture. I have a provider called Auth that handles the login using Firebase Api. In that provider class I am setting the users profile picture retrieved from Firebase. I am confused though how to access that in my profile page. I have this code in the profile page

class UserProfileScreen extends StatefulWidget {
  static const routeName = '/user-profile';
  @override
  State<UserProfileScreen> createState() => _UserProfileScreenState();
}

class _UserProfileScreenState extends State<UserProfileScreen> {
  String tempImg = null;

  void _showOptions(BuildContext context) {
    showModalBottomSheet(
        context: context,
        builder: (context) {
          return Container(
            height: 150,
            child: Column(
              children: <Widget>[
                ListTile(
                    leading: Icon(Icons.photo_camera),
                    title: Text("Take a picture from camera")),
                ListTile(
                  onTap: () {
                    Navigator.pop(context);
                    _showPhotoLibrary();
                  },
                  leading: Icon(Icons.photo_library),
                  title: Text("Choose from photo library"),
                ),
              ],
            ),
          );
        });
  }

  void _showPhotoLibrary() async {
    final file = await ImagePicker.pickImage(source: ImageSource.gallery);
    setState(() {
      tempImg = file.path;
    });
  }

  @override
  Widget build(BuildContext context) {
    final tempImg = Provider.of<Auth>(context);

    return Scaffold(
        body: SafeArea(
      child: Column(
        children: [
          Container(
            child: Container(
              width: double.infinity,
              height: 200,
              child: Column(
                  children: <Widget>[
                    Container(
                      width: 200,
                      height: 100,
                      child: tempImg == null
                          ? Image.network(
                              "https://firebasestorage.googleapis.com/v0/b/refmastersbeta.appspot.com/o/assets%2Fblank-profile-picture.png?alt=media&token=2c87bb88-b8a4-4e60-8c00-df36f39656cf")
                          //Image.network("images/place-holder.png")
                          : Image.asset(tempImg),
                      //: Image.file(File(tempImg),
                      /*
                    CircleAvatar(
                      //backgroundImage: NetworkImage(user.userImageUrl),
                      backgroundImage: NetworkImage(tempImg),
                      radius: 60.0,
                    ),

I think that tempImg is being written over every-time the builder if run though. So where do I call the provider to retrieve and set the tempImg?

Thanks @mohamed-shawky. I think I am heading in the right direction now. How do I set the image url to the image the user picks now? In my auth class I have a setter that looks like this

class Auth with ChangeNotifier {
  
 String _userImageUrl;
  set userImageUrl(newuserImageUrl) {
    _userImageUrl = newuserImageUrl;
    notifyListeners();
  }

and my user profile page is

import 'package:flutter/material.dart';
import '../providers/auth.dart';
import 'package:image_picker/image_picker.dart';
import 'package:provider/provider.dart';

class UserProfileScreen extends StatelessWidget {
  static const routeName = '/user-profile';

  void _showOptions(BuildContext context) {
    showModalBottomSheet(
        context: context,
        builder: (context) {
          return Container(
            height: 150,
            child: Column(
              children: <Widget>[
                ListTile(
                    leading: Icon(Icons.photo_camera),
                    title: Text("Take a picture from camera")),
                ListTile(
                  onTap: () {
                    Navigator.pop(context);
                    _showPhotoLibrary();
                  },
                  leading: Icon(Icons.photo_library),
                  title: Text("Choose from photo library"),
                ),
              ],
            ),
          );
        });
  }

  void _showPhotoLibrary() async {
    Auth().userImageUrl = "test image";
  }

  @override
  Widget build(BuildContext context) {
    final loggedInUser = Provider.of<Auth>(context);

    return Scaffold(
      body: SafeArea(
        child: Column(
          children: [
            Container(
              /*
            decoration: BoxDecoration(
                image: DecorationImage(
                    image: NetworkImage(user.userImageUrl), fit: BoxFit.cover)),*/
              child: Container(
                width: double.infinity,
                height: 200,
                child: Column(
                  children: <Widget>[
                    CircleAvatar(
                      backgroundImage: NetworkImage(loggedInUser.userImageUrl),
                      radius: 60.0,
                    ),
                    FlatButton(
                      child: Text("Take Picture",
                          style: TextStyle(color: Colors.white)),
                      color: Colors.green,
                      onPressed: () => _showOptions(context),
                    )
                  ],
                ),
              ),
            ),
            SizedBox(
              height: 60,
            ),
            Text(
              loggedInUser.userName,
              style: TextStyle(
                fontSize: 25.0,
                color: Colors.blueGrey,
                letterSpacing: 2.0,
                fontWeight: FontWeight.w400,
              ),
            ),
            SizedBox(
              height: 10,
            ),
          ],
        ),
      ),
    );
  }
}
1 Answers

this is not the right way to use provider. first of all, you should make a class that extends from ChangeNotifier you can use it as a controller you then you need to set it in your ChangeNotifierProvider in your main

class UserProvider extends ChangeNotifier() {
File userImge = null;
void _showPhotoLibrary() async {
    userImge = await ImagePicker.pickImage(source: ImageSource.gallery);
    //dont use setState any more with provider use notifyListeners() 
    notifyListeners() 
  }
}

   

replace :

final tempImg = Provider.of<Auth>(context);

to

final userProvider = Provider.of<UserProvider>(context);

now you can use it like that :

userProvider.userImge != null ? Image.file(File(userProvider.userImge) : Any Widget Else
Related