skip to Main Content

I’m trying to show all images the user uploaded to Firebase Storage to a single note but it’s only giving me one image when using note.image or duplicating the images when using image['url']. I want to use note.image. I’ve tried a few things but no success.
Sorry for adding a ton of code. I’m not sure what all needs to be changed and not sure how to to explain it all… I’m new.

Here is my model that shows a single image:

class NoteModel {

  String? image;
  String? id;
  String? title;
  String? description;
  Timestamp? date;
  String? userId;

  NoteModel({
    this.image,
    this.id,
    this.title,
    this.description,
    this.date,
    this.userId
  });

  factory NoteModel.fromJson(DocumentSnapshot streamSnapshot){

    return NoteModel(
      image: streamSnapshot['image'],
      id: streamSnapshot.id,
      title: streamSnapshot['title'],
      description: streamSnapshot['description'],
      date: streamSnapshot['date'], 
      userId: streamSnapshot['userId']
      );  
  }
}
class FirestoreService{

  FirebaseFirestore firestore = FirebaseFirestore.instance;

  Future insertNote(
  String image, 
  String title, 
  String description, 
  String userId)async{
    try{
      await firestore.collection('notes').add({
        "image":image,
        "title":title,
        "description":description,
        "date":DateTime.now(),
        "userId":userId
      });
 } catch(e){
 }
  }

Where I’m using note.image and want to see the multiple images the user uploaded:

 FirebaseFirestore firestore = FirebaseFirestore.instance;
 FirebaseStorage firebaseStorage = FirebaseStorage.instance;

  @override
  Widget build(BuildContext context) {
    return Scaffold(
      body: StreamBuilder<QuerySnapshot>(
          stream: FirebaseFirestore.instance
              .collection("notes")
              .where('userId', isEqualTo: user?.uid ?? '')
              .snapshots(),
          builder: (context, AsyncSnapshot snapshot) {
            if (!snapshot.hasData) {
              return Center(child: CircularProgressIndicator());
            }
            return ListView.builder(
                itemCount: snapshot.data.docs.length ?? 0,
                itemBuilder: (context, index) {
                  final NoteModel note =
                      NoteModel.fromJson(snapshot.data.docs[index]);
                  return Column(children: [
                    Center(
                      child: Container(
                        decoration: BoxDecoration(
                          borderRadius: BorderRadius.circular(15),
                        ),
                        child: Card(
                          color: Color(0xFFf4f5f7),
                          margin: EdgeInsets.only(
                              right: 10, top: 20, left: 10, bottom: 10),
                          elevation: 8.0,
                          shape: RoundedRectangleBorder(
                            borderRadius: BorderRadius.circular(15),
                          ),
                          child: Column(
                            children: <Widget>[
                              Image.network(

                                note.image!, // HERE
                                
                                errorBuilder: (BuildContext context,
                                    Object exception, StackTrace? stackTrace) {
                                  return const Text(
                                      'error loading image or no image found');
                                },
                              ),

My AddNoteScreen where I can upload multiple images to Firebase Storage:

 File? imageFile;
  String? fileName;

  Future<void> uploadMultipleImages() async {
    final picker = ImagePicker();
    final List<XFile>? pickedImages = await picker.pickMultiImage();
    if (pickedImages == null) {
      return null;
    }
    setState(() {
      loading = true;
    }); 
    await Future.forEach(pickedImages, (XFile image) async {
      fileName = image.name;
      imageFile = File(image.path);

      try {
        await firebaseStorage.ref(fileName).putFile(imageFile!);
      } on FirebaseException catch (e) {
        print(e);
      }
    });

    setState(() {
      loading = false;
    });

    ScaffoldMessenger.of(context).showSnackBar(
        SnackBar(content: Text("All images uploaded successfully")));
  }

Loading images from Firebase Storage:

  Future<List> loadImages() async {
    List<Map> files = [];
    final ListResult result = await firebaseStorage.ref().listAll();
    final List<Reference> allFiles = result.items;
    await Future.forEach(allFiles, (Reference file) async {
      final String fileUrl = await file.getDownloadURL();
      files.add({
        "url": fileUrl,
        "path": file.fullPath,
      });
    });
    print(files);
    return files;
  }

Using imageUrl: image['url'] shows all the images:

              InkWell(
                onTap: () {
                  uploadMultipleImages();
                },
                child: SizedBox(
                  height: 150,
                  child: imageFile == null
                      ? Center(child: Icon(Icons.add_a_photo_rounded, size: 80))
                      : Center(
                          child: Icon(Icons.add_a_photo_rounded, size: 80)),
                ),
              ),
              SizedBox(
                height: 300,
                child: FutureBuilder(
                    future: loadImages(),
                    builder: (context, AsyncSnapshot snapshot) {
                      if (snapshot.connectionState == ConnectionState.waiting) {
                        return Center(
                          child: CircularProgressIndicator(),
                        );
                      }
                      return ListView.builder(
                          scrollDirection: Axis.horizontal,
                          shrinkWrap: true,
                          itemCount: snapshot.data?.length ?? 0,
                          itemBuilder: (context, index) {
                            final Map image = snapshot.data[index];
                            return Padding(
                                padding: EdgeInsets.only(left: 0.0),
                                child: Column(
                                  children: [
                                    Card(
                                      child: SizedBox(
                                        height: 200,
                                        child: Stack(
                                          children: [
                                            CachedNetworkImage(
                                              // imageUrl: note.image!, 
                                              imageUrl: image['url'], 
                                              placeholder: (context, url) =>
                                                  Image.asset(
                                                      'assets/placeholder.jpg'),
                                              errorWidget:
                                                  (context, url, error) =>
                                                      Icon(Icons.error),
                                            ),
                                          ],
                                        ),
                                      ),
                                    ),
ElevatedButton(
                        onPressed: () async {
                          if (imageFile == null ||
                             titleController.text.isEmpty ||
                             descriptionController.text.isEmpty 
                           ) {
                            ScaffoldMessenger.of(context).showSnackBar(SnackBar(
                                content: Text("All fields are required")));

                          } else {
                            setState(() {
                              loading = true;
                            });

                            String imageUrl = await FirebaseStorage.instance
                                .ref(fileName)
                                .putFile(imageFile!)
                                .then((result) {
                              return result.ref.getDownloadURL();
                            });

                            await FirestoreService().insertNote(
                                imageUrl,
                                titleController.text,
                                descriptionController.text,
                                widget.user.uid);

                            CollectionReference notes =
                                firestore.collection('notes');
                            QuerySnapshot allResults = await notes.get();
                            allResults.docs.forEach((DocumentSnapshot result) {
                              print(result.data());
                            });

NotesScreen page where I’m trying to use Swiper. Here it duplicates(loops?) the images using note.image! and image[‘url’]:

      body: StreamBuilder(
          stream: FirebaseFirestore.instance
              .collection("notes")
              .where('userId', isEqualTo: user.uid)
              .snapshots(),
          builder: (context, AsyncSnapshot streamSnapshot) {
            if (streamSnapshot.hasData) {
              if (streamSnapshot.data.docs.length > 0) {
                return ListView.builder(
                    itemCount: streamSnapshot.data.docs.length ?? 0,
                    itemBuilder: (context, index) {
                      final NoteModel note =
                          NoteModel.fromJson(streamSnapshot.data.docs[index]);
                      return Card(
                        shape: RoundedRectangleBorder(
                          borderRadius: BorderRadius.circular(15.0),
                        ),
                        margin:
                            const EdgeInsets.only(top: 18, left: 15, right: 15),
                        child: Column(children: [
                          SizedBox(
                            height: 210,
                            child: Expanded(
                              child: FutureBuilder(
                                  future: loadImages(),
                                  builder: (context, AsyncSnapshot snapshot) {
                                    if (snapshot.connectionState ==
                                        ConnectionState.waiting) {
                                      return const Center(
                                        child: CircularProgressIndicator(),
                                      );
                                    }
                                    return Swiper(
                                        loop: false,
                                        pagination: SwiperPagination(
                                          alignment: Alignment.bottomRight,
                                          builder: DotSwiperPaginationBuilder(
                                              activeSize: 7,
                                              size: 6,
                                              color: Colors.grey[100],
                                              activeColor: Colors.grey[600]),
                                        ),
                                        scrollDirection: Axis.horizontal,
                                        itemCount: snapshot.data.length ?? 0,
                                        itemBuilder: (context, index) {
                                          final Map image =
                                              snapshot.data[index];
                                          return Padding(
                                              padding:
                                                  const EdgeInsets.all(0.0),
                                              child: Column(
                                                children: [
                                                  Card(
                                                    child: SizedBox(
                                                      height: 200,
                                                      child: SizedBox(
                                                        height: MediaQuery.of(
                                                                context)
                                                            .size
                                                            .height,
                                                        width: MediaQuery.of(
                                                                context)
                                                            .size
                                                            .width,
                                                        child: ClipRRect(
                                                          borderRadius:
                                                              const BorderRadius
                                                                      .only(
                                                                  topLeft: Radius
                                                                      .circular(
                                                                          15),
                                                                  topRight: Radius
                                                                      .circular(
                                                                          15)),
                                                          child:
                                                              CachedNetworkImage(
                                                            fit: BoxFit.cover,
                                                            imageUrl:
                                                            note.image!,
                                                               // image['url'],
                                                            placeholder: (context,
                                                                    url) =>
                                                                Image.asset(
                                                                    'assets/placeholder.jpg'),
                                                            errorWidget: (context,
                                                                    url,
                                                                    error) =>
                                                                const Icon(Icons
                                                                    .error),
                                                          ),
                                                        ),
                                                      ),
                                                    ),
                                                  ),
                                                ],
                                              ));
                                        });
                                  }),
                            ),
                          ),

screenshot

There could be many things going wrong here so if you need to see more please let me know..

I have very little experience with this. Any help would be very much appreciated!

Cloud Firestore

firebase storage

And apologies, I might be slow to respond.

EDIT on NotesScreen:

         child:
                                                              ListView.builder(
                                                                itemBuilder: (context, index) {  
                                                                return CachedNetworkImage(
                                                                  imageUrl: note.image!,
                                                                  // image['url'],
                                                                  placeholder: (context,
                                                                      url) =>
                                                                  Image.asset(
                                                                      'assets/placeholder.jpg'),
                                                                  errorWidget: (context,
                                                                      url,
                                                                      error) =>
                                                                  const Icon(Icons
                                                                      .error),
                                                                      );
                                                                      }),

EDIT:

Changed from String to List in my AddNoteScreen(to match my FirestoreService page?) but am now getting a new error

   List imageUrl = await FirebaseStorage.instance
                                .ref(fileName)
                                .putFile(imageFile!)
                                .then((result) {
                              return result.ref.getDownloadURL(); // HERE 
                            });

                            await FirestoreService().insertNote(
                                imageUrl,

I get The return type 'Future<String> isn't a 'FutureOr<List<dynamic>>', as required by closure's context.

Here is my FirestoreService page:

class FirestoreService{

  FirebaseFirestore firestore = FirebaseFirestore.instance;

  Future insertNote(
  List image, 
  String title, 
  String description, 
  String userId)async{
    try{
      await firestore.collection('notes').add({
        "image":image,
        "title":title,
        "description":description,
        "date":DateTime.now(),
        "userId":userId
      });
 } catch(e){
 }
  }

2

Answers


  1. First change your dadas model to this:

    class NoteModel {
    
      List<String?>? images; //<--- change this
      String? id;
      String? title;
      String? description;
      Timestamp? date;
      String? userId;
    
      NoteModel({
        this.images,
        this.id,
        this.title,
        this.description,
        this.date,
        this.userId
      });
    
      factory NoteModel.fromJson(DocumentSnapshot streamSnapshot){
    
        return NoteModel(
          images: streamSnapshot['image'],
          id: streamSnapshot.id,
          title: streamSnapshot['title'],
          description: streamSnapshot['description'],
          date: streamSnapshot['date'], 
          userId: streamSnapshot['userId']
          );  
      }
    }
    

    then change your Card to this:

    Card(
        color: Color(0xFFf4f5f7),
        margin: EdgeInsets.only(right: 10, top: 20, left: 10, bottom: 10),
        elevation: 8.0,
        shape: RoundedRectangleBorder(
          borderRadius: BorderRadius.circular(15),
        ),
        child: Column(
          children: <Widget>[
            SingleChildScrollView(
                  scrollDirection: Axis.horizontal,
                  child: Row(
                    children: images
                        .map((e) => SizedBox(
                              width: MediaQuery.of(context).size.width,
                              child: Image.network(
                                e!, // HERE
                                fit: BoxFit.cover,
                                errorBuilder: (BuildContext context,
                                    Object exception, StackTrace? stackTrace) {
                                  return const Text(
                                      'error loading image or no image found');
                                },
                              ),
                            ))
                        .toList(),
                  ),
                )
          ],
        ),
      ),
    
    Login or Signup to reply.
  2. You simply have to store uploaded images in a list in firestore, with this approach you can able to get list of uploaded images by particular user.

    And after that you have to change String to List your model like below code

    class NoteModel {
      List<String>? image;
      String? id;
      String? title;
      String? description;
      Timestamp? date;
      String? userId;
    
     NoteModel({
     this.image,
     this.id,
     this.title,
     this.description,
     this.date,
     this.userId
     });
      factory NoteModel.fromJson(DocumentSnapshot streamSnapshot){
         return NoteModel(
          image: List<String>.from(streamSnapshot["image"].map((x) => x)),
          id: streamSnapshot.id,
          title: streamSnapshot['title'],
          description: streamSnapshot['description'],
          date: streamSnapshot['date'], 
          userId: streamSnapshot['userId']
        );  
      }
     }
    

    And then wrap CachedNetworkImage() with ListView.builder or GridView.builder to show all the uploaded images.

    Login or Signup to reply.
Please signup or login to give your own answer.
Back To Top
Search