0

I am using File_Picker.dart I am having an issue with one of the function I have written. When I press on the icon delete, the record is not deleted, and the screen is not refreshed. What I mean is that the card is still displayed. Also, what I am trying to do it to be able to add a file one by one, without removing the file previously selected. But each time I am clicking on the button 'Open File picker' which is calling '_openFileExplorer()', the file selected previously is removed from the screen. I have not find how to stop this to happen.

If you can help me to solve this it would be appreciated. Many thanks.

import 'dart:io';
import 'package:file_picker/file_picker.dart';
import 'package:flutter/material.dart';
import 'package:flutter/services.dart';
import 'package:firebase_core/firebase_core.dart';
import 'package:firebase_storage/firebase_storage.dart';

class FilePickerDemo extends StatefulWidget {
  @override
  _FilePickerDemoState createState() => _FilePickerDemoState();
}

class _FilePickerDemoState extends State<FilePickerDemo> {
  //FirebaseStorage storage = FirebaseStorage.instance;
  final GlobalKey<ScaffoldState> _scaffoldKey = GlobalKey<ScaffoldState>();
  late String _fileName;
  List<PlatformFile>? _paths;
  bool _loadingPath = false;
  bool _multiPick = true;
  FileType _fileType = FileType.media;

  /*
  @override
  void initState() {
    super.initState();
    Firebase.initializeApp();
  }
   */

  void _openPictureFileExplorer() async {
    setState(() => _loadingPath = true);

/*
try{
    var files = (await FilePicker.platform.pickFiles(
      type: _fileType,
      allowMultiple: _multiPick,
    ))
        ?.files;

    _paths = _paths!..addAll(files!.map((e) => e));
    _loadingPath = false;
} on PlatformException catch (e) {
  print("Unsupported operation" + e.toString());
} catch (ex) {
  print('$ex');
}

 */

    try {
      _paths = (await FilePicker.platform.pickFiles(
        type: _fileType,
        allowMultiple: _multiPick,
      ))
          ?.files;
    } on PlatformException catch (e) {
      print("Unsupported operation" + e.toString());
    } catch (ex) {
      print('$ex');
    }

    if (!mounted) return;

    setState(() {
      _loadingPath = false;
      print(_paths!.last.name);
      _fileName = _paths != null ?
      _paths!.map((e) => e.name).toString() : '...';
    });
  }

  void _openDocumentFileExplorer() async {
    setState(() => _loadingPath = true);


try{
    var files = (await FilePicker.platform.pickFiles(
      type: _fileType,
      allowMultiple: _multiPick,
    ))
        ?.files;

    _paths = _paths!..addAll(files!.map((e) => e));
    
    _loadingPath = false;
} on PlatformException catch (e) {
  print("Unsupported operation" + e.toString());
} catch (ex) {
  print('$ex');
}


/*
    try {
      _paths = (await FilePicker.platform.pickFiles(
        type: FileType.custom,
        allowMultiple: _multiPick,
        allowedExtensions: ['pdf','docx'],
      ))
          ?.files;
    } on PlatformException catch (e) {
      print("Unsupported operation" + e.toString());
    } catch (ex) {
      print('$ex');
    }

    if (!mounted) return;

    setState(() {
      _loadingPath = false;
      print(_paths!.last.name);
      _fileName = _paths != null ?
      _paths!.map((e) => e.name).toString() : '...';
    });

 */


  }


  void _clearCachedFiles() {
    FilePicker.platform.clearTemporaryFiles().then((result) {
      ScaffoldMessenger.of(context).showSnackBar(
        SnackBar(
          backgroundColor: result! ? Colors.green : Colors.red,
          content: Text((result
              ? 'Temporary files removed with success.'
              : 'Failed to clean temporary files')),
        ),
      );
    });
  }

  // Select and image from the gallery or take a picture with the camera
  // Then upload to Firebase Storage

 /*
  Future<void> _upload() async {

    try {

      final String fileName = _fileName;
      File imageFile = File(_paths.toString());

      try {
        // Uploading the selected image with some custom meta data
        await storage.ref(fileName).putFile(
            imageFile,
            );

        // Refresh the UI
        setState(() {});
      } on FirebaseException catch (error) {
        print(error);
      }
    } catch (err) {
      print(err);
    }
  }


  */


  // Delete the selected image
  // This function is called when a trash icon is pressed
  void _delete(int index) {
    if(_paths!=null || _paths!.length> 1) {
      _paths!.removeAt(index);
      setState(() {});
      print ('2:' +_paths!.length.toString());
    }
  }

  @override
  Widget build(BuildContext context) {
    return MaterialApp(
      home: Scaffold(
        key: _scaffoldKey,
        appBar: AppBar(
          title: const Text('File Picker example app'),
        ),
        body: Center(
            child: Padding(
              padding: const EdgeInsets.only(left: 10.0, right: 10.0),
              child: SingleChildScrollView(
                child: Column(
                  mainAxisAlignment: MainAxisAlignment.center,
                  children: <Widget>[
                    Padding(
                      padding: const EdgeInsets.only(top: 20.0),

                      child:Card(
                          child:
                          Container(
                            // color: Colors.red,
                            alignment: Alignment.center,
                            child: Row(
                              mainAxisAlignment: MainAxisAlignment.center,
                              children:[
                                //Attachement
                                FlatButton(
                                  onPressed: () {  },
                                  child:
                                  InkWell(
                                    child: Container(
                                      //  color: Colors.white,
                                        child: Column(
                                          mainAxisAlignment: MainAxisAlignment.center,
                                          children: [
                                            Icon(Icons.attach_file),
                                            Text('Attachement'),
                                          ],
                                        )
                                    ),
                                    onTap: () {

                                    },
                                  ),
                                ),

                                //Photo
                                FlatButton(
                                  onPressed: () {  },
                                  child:
                                  InkWell(
                                    child: Container(
                                      //   color: Colors.white,
                                        child: Column(
                                          mainAxisAlignment: MainAxisAlignment.center,
                                          children: [
                                            Icon(Icons.add_a_photo_rounded),
                                            Text('Photo'),
                                          ],
                                        )
                                    ),
                                    onTap: () {_openPictureFileExplorer(); },
                                  ),
                                ),
                              ],
                            ),
                          )),
                    ),


                    Builder(
                      builder: (BuildContext context) => _loadingPath ?
                          Padding(
                        padding: const EdgeInsets.only(bottom: 10.0),
                           child:const CircularProgressIndicator(),
                      )
                          : _paths != null && _paths!.isNotEmpty
                          ? Container(
                        padding: const EdgeInsets.only(bottom: 30.0),
                        height:
                        MediaQuery.of(context).size.height * 0.50,
                          child: Scrollbar(
                            child: ListView.separated(
                              itemCount:
                              _paths != null && _paths!.isNotEmpty
                                  ? _paths!.length
                                  : 1,
                              itemBuilder:
                                  (BuildContext context, int index) {
                                final bool isMultiPath =
                                    _paths != null && _paths!.isNotEmpty;
                                final String name =
                                    (isMultiPath
                                        ? _paths!
                                        .map((e) => e.name)
                                        .toList()[index]
                                        : _fileName ?? '...');

                                final path = _paths!
                                    .map((e) => e.path)
                                    .toList()[index]
                                    .toString();

                                return Container(
                                  height: 114,
                                  child: Card(
                                    shape: RoundedRectangleBorder(
                                      borderRadius: BorderRadius.circular(15.0),
                                    ),
                                    elevation: 10,
                                      child: ClipPath(
                                        clipper: ShapeBorderClipper(
                                            shape: RoundedRectangleBorder(
                                                borderRadius: BorderRadius.circular(15))),
                                        child: Row(
                                          crossAxisAlignment: CrossAxisAlignment.center,
                                          mainAxisAlignment: MainAxisAlignment.start,
                                          children: [
                                            Container(
                                              height: 113,width: 113,
                                              child: Image.file(File(path),
                                                fit: BoxFit.fill,
                                                width: double.infinity,),
                                            ),
                                            Expanded(
                                              child: Padding(
                                                padding: const EdgeInsets.all(10.0),
                                                child: Text(name,
                                                  style: TextStyle(fontWeight: FontWeight.bold),),
                                              ),
                                            ),
                                              Padding(
                                                padding: const EdgeInsets.only(right:25.0),
                                                child: IconButton(onPressed: (){
                                                  //delete a record and the card displaying this record
                                                  _delete(index);
                                                },

                                                  icon:Icon (Icons.delete, color: Colors.red,),),
                                              )
                                          ],
                                        ),
                                      ),
                                      //subtitle: Text(path),
                                  ),
                                );
                              },
                              separatorBuilder:
                                  (BuildContext context, int index) =>
                               const SizedBox(),)),)
                              :const SizedBox(child:Text('No documents')),
                          ),
                      ],
                ),
              ),
            )),
      ),
    );
  }
}
Laurent Thomas
  • 232
  • 4
  • 24

1 Answers1

1

The problem here is that the paths variable is made up of a list of PlatformFile and you are trying to remove a string value which doesn't exist in that list.

You can see this if you print the value of paths in your _delete() method. It should show [Instance of 'PlatformFile', Instance of 'PlatformFile'].

In a nutshell what you're trying to do could be visualized as such

[PlatformFile(), PlatformFile()].remove("some/path/string/value")

There can be a simple fix for this assuming the list isn't sorted, you can just send the index as the reference from the onTap .

It would look like this

  void _delete(int ref) {
    // remove the element at the passed index
    _paths!.removeAt(ref);
    setState(() {});
  }

   ... some code...
   itemBuilder: (BuildContext context, int index) {
      ... some code...
       IconButton(
        onPressed: () {
         _delete(index);
         setState(() {});
        },
        icon: Icon(
         Icons.delete,
         color: Colors.red,
    ),
    ... some code...
  );
 }

Alternatively if you can't be sure of the positions of the elements in the path list, this would be the best approach.

  void _delete(String ref) {
    var _platformFileObject = _paths!.where((element) => element.path == ref).first;
    _paths!.remove(_platformFileObject);
    setState(() {});
  }

Edit to answer the second question;

In your _openFileExplorer() method, you are reassigning the new file objects rather than adding them to the _paths list. The solution would be to add the new file objects to the list.

FilePickerResult? filePickerResult = await 
       FilePicker.platform.pickFiles(
        type: _fileType,
        allowMultiple: _multiPick,
);

_paths?.addAll(filePickerResult!.files.map((e) => e));

Edited to answer the third question

The error you stated occurs because of this [lines 150-153]

itemCount:
  _paths != null && _paths!.isNotEmpty
  ? _paths!.length
  : 1

So when it goes to the builder it is trying build a list item but there's nothing to get since the list is actually empty. You should change 1 to 0.

In order to show a text when the _paths list is empty, you should try something like this.

Scrollbar(
    child: !_paths!.isEmpty
        ? ListView.separated(
            itemCount: _paths!.length,
            itemBuilder: (BuildContext context, int index) {
              return Container();
            },
            separatorBuilder: (BuildContext context, int index) {
              return Container();
            },
          )
        : Text("Text to display when _paths is empty"),
);

Additionally, I would recommend that you refactor your code for better readability.

  • Many thanks. The onTap works fine now. May I please ask you if you have find a solution to my second question? It was a way to add picture one by one. Each time I click on 'open file picker' button, it removes all the files from my view. To give you more colors, I would like to allow users to add pictures one by one, then to add pdf or other file. At the end, I should display a list of several images and files. Then by clicking on a button all those files will be stored to Firebase. I hope it is clear. Many thanks – Laurent Thomas Jul 10 '21 at 16:46
  • I have edited my solution to address your second question @LaurentThomas – Akassharjun Shanmugarajah Jul 10 '21 at 17:13
  • I hope I have answered your question @LaurentThomas – Akassharjun Shanmugarajah Jul 11 '21 at 05:17
  • I have modified my code with 'var files = (await FilePicker.platform.pickFiles(...". The application is not behaving properly then. It displays the CircularProgressIndicator and does not stop. It does not display the images. Please, do you have any idea why? – Laurent Thomas Jul 11 '21 at 06:25
  • Yes. deleting record works fine. The only issue I still have is the one I have mentioned before. Adding image one by one. it seems that the application is stuck on CircularProgressIndicator – Laurent Thomas Jul 11 '21 at 06:47
  • I can't seem to identify the issue as it's working as intended on my device. Could you update your question with the code you are currently using? Any additional information like the device you're using could be helpful too. – Akassharjun Shanmugarajah Jul 11 '21 at 07:05
  • I have copy the code. The devise I am using is iPhone 12. Many thanks – Laurent Thomas Jul 11 '21 at 07:15
  • I have modified my answer under question #2, the issue was that the _paths variable was null and there were addAll method was being called on it while it was null without a safety check. @LaurentThomas – Akassharjun Shanmugarajah Jul 11 '21 at 07:52
  • I have tried your code below, but it does not change the result. I am printing the variable to understand why. But I do not find why so far. Thank you. ```FilePickerResult? filePickerResult = await FilePicker.platform.pickFiles( type: _fileType, allowMultiple: _multiPick, ); _paths?.addAll(filePickerResult!.files.map((e) => e)); ``` – Laurent Thomas Jul 11 '21 at 08:25
  • When you say that I should refactor my code, are you referring to void _openPictureFileExplorer() async {... and void _openDocumentFileExplorer... ? Many thanks – Laurent Thomas Jul 11 '21 at 09:09