mellowchest
mellowchest

Reputation: 21

image_picker flutter error, how can I save image in application permanently?

so i am having trouble saving the users pfp when they navigate to a new section on my application, when the user clicks of from the current tab and comes back the pfp disappears, it kills the path it seems. i want to be able to upload a image as the pfp, and when i navigate to a new section within the application for it to still be there. code below:

import 'dart:io';
import 'package:cloud_firestore/cloud_firestore.dart';
import 'package:flutter/cupertino.dart';
import 'package:flutter/material.dart';
import 'package:flutter/material.dart';
import 'package:flutter/services.dart';
import 'package:flutter/widgets.dart';
import 'package:image_picker/image_picker.dart';
import 'package:path_provider/path_provider.dart';
import 'package:path/path.dart';

import 'save_pfp.dart';

File? image;
class BuildProfile extends StatefulWidget {
  
  const BuildProfile({super.key});
  @override
  State<BuildProfile> createState() => _BuildProfileState();
}
class _BuildProfileState extends State<BuildProfile> {





 Future getImage() async{
  try{
    image = (await ImagePicker().pickImage(source: ImageSource.gallery)) as File?  ;
    if (image == null) return;
    
 final imagePermanent = await saveImagePermanently(image!.path);
    setState(() => image = imagePermanent);
  } on PlatformException catch (e) {
    print('failed to pick image: $e');
  }
 }

 Future<File> saveImagePermanently(String imagePath) async{
  final directory = await getApplicationDocumentsDirectory();
final fileName = basename(imagePath);
 image = File('${directory.path}/$fileName');
  return File(imagePath).copy(image!.path);
}








  @override
  Widget build(BuildContext context) {
    return CircleAvatar(
                      backgroundColor: Colors.grey.shade400,
                      backgroundImage: image == null ? null
                      : FileImage(image!),
                      radius: 56,
                      child: Align(
                        alignment:const  Alignment(3.2, 0.73),
                        child: RawMaterialButton(
                        onPressed: () {
                         showModalBottomSheet(context: context, 
                         backgroundColor: Colors.black38,
                           builder: (context) =>  Container(
                            height: 180,
                       child: Row(
                        mainAxisAlignment: MainAxisAlignment.center,
                        children: <Widget>[
                      const Text('camera',
                    style: TextStyle(color: Colors.white)),
                  IconButton(
                 onPressed: () {
                  // _getFromCamera;
              getImage();
                  },
                icon: const Icon(CupertinoIcons.camera, 
                 size: 26,
                color: Colors.white,
                           )),
                 IconButton(
                 // pick from gallery
                onPressed:() {
                getImage();

I have tried different solutions, but run into the same error.

Upvotes: 1

Views: 127

Answers (1)

mr.Penguin
mr.Penguin

Reputation: 1619

In my case, I'm using Provider strategy to save the picked photos and consume them whenever I want in whatever code I am, this is how I proceeded:

First, get the photos from the image picker:

  void _setImageFromPhone(ImageSource imageSource) async {
    final pickedFile = await ImagePicker().pickImage(source: imageSource, imageQuality: 75);

    if (pickedFile == null) {
      return;
    }

    log(pickedFile.path);
    widget.formModel.addNewPhotos(pickedFile.path);
  }

The provider where I save the picked photos:

class FormModel extends ChangeNotifier {
  final List<String> _photos = [];

  void addNewPhotos(String photo) {
    _photos.add(photo);
    notifyListeners();
  }

  //getter for photos
  UnmodifiableListView<String> get photos => UnmodifiableListView(_photos);
}

After that you can consume the photos you add wherever you want :

 @override
  Widget build(BuildContext context) {
    return Consumer<FormModel>(
      key: formModelConsumerKey,
      builder: (
        context,
        formModel,
        child,
      ) {
        return 
            Row(
                children:[

                ]
            )
        Container(
              height: MediaQuery.of(context).size.width * 0.35,
              width: MediaQuery.of(context).size.width * 0.35,
              decoration: BoxDecoration(
                color: LIGHT_GREEN_COLOR,
                borderRadius: const BorderRadius.all(
                  Radius.circular(10),
                ),
                image: DecorationImage(
                  image: Image.file(File(formModel.photos.first!)).image,
                  fit: BoxFit.fill,
                ),
              ),
              child: SizedBox();
              );

        }
        );
        }

Also do not forget to provide your Provider class in the top parent widgets, small example bellow :

 return MultiProvider(
            providers: [
              ChangeNotifierProvider(create: (context) => FormModel()),
            ],
            child: MaterialApp()           
        )

Upvotes: 1

Related Questions