Search code examples
listviewflutterdartgoogle-cloud-firestorestring-interpolation

How to retrieve Firestore data from inside a function?


I am trying to call firestore data, the title of a collection, inside a function from a button. It worked when I just used it inside an onPressed:

Expanded(
   child: IconButton(
      icon: Icon(
        Icons.share,
         onPressed: () => Share.share(
         '${(snapshot.data.documents[index]['title'])}',  //this displays the 'title' 
fields of my firestore collections in ListView
         ))),

But when trying to call from a function (in a different share plugin), whatever I try just prints the actual code and not the content, how do I retrieve the firestore collection's "title" in the function below, I thought string interpolation ${ like this } was the only way but it doesn't work for this:

MaterialButton(
              child: Text('Share text'),
              onPressed: () async => await _shareText(),
            ),

function:

Future<void> _shareText() async {
try {
  Share.text('my text title',
      'HERE => This is my text to share with other applications.', 'text/plain');  
// no variation of ${snapshot.data.documents[index]['title']} works here
} catch (e) {
  print('error: $e');
}}

The string I get the data is:

${snapshot.data.documents[index]['title']} 

Is there another way to call this?

import 'package:flutter/cupertino.dart';
import 'package:flutter/material.dart';
import 'package:cloud_firestore/cloud_firestore.dart';
import 'package:flutter_staggered_grid_view/flutter_staggered_grid_view.dart';
import 'dart:ui';
import 'package:google_fonts/google_fonts.dart';
import 'package:material_design_icons_flutter/material_design_icons_flutter.dart';
import 'package:esys_flutter_share/esys_flutter_share.dart';
import 'dart:async';
import 'image.dart';


class Recipe extends StatefulWidget {
@override
_RecipeState createState() => _RecipeState();
}

class _RecipeState extends State<Recipe> {
 var firestoreDb = Firestore.instance.collection("recipes").snapshots();



  // THIS ${(snapshot.data.documents[index].data['title'])} does not work in 
  share plugin:
Future<void> _shareText() async {
try {
  Share.text('Share Text ',
      '${(snapshot.data.documents[index].data['title'])}', 'text/plain');
} catch (e) {
  print('error: $e');
}
}

@override
Widget build(BuildContext context) {
return Scaffold(
  appBar: AppBar(
    title: Row(
        mainAxisAlignment: MainAxisAlignment.spaceEvenly,
        children: <Widget>[
          Container(
              padding: const EdgeInsets.all(8.0),
              child: Text(
                'Recipes',
                style: GoogleFonts.lato(
                  fontSize: 22.0,
                  color: Colors.amberAccent.shade50,
                ),
              )),
          IconButton(
            icon: Icon(MdiIcons.foodForkDrink, color: Color(0xffffe0b2), 
size: 32.0),
            onPressed: () {
             null;
            },
          ),
        ]),
    backgroundColor: Colors.lightBlue,
    elevation: 50.0,
  ), //AppBar

  body: Container(
    width: MediaQuery.of(context).size.width,
    child: StreamBuilder(
        stream: firestoreDb,
        builder: (context, snapshot) {
          if (!snapshot.hasData) Text('Loading...');
          return StaggeredGridView.countBuilder(
            crossAxisCount: 2,
            mainAxisSpacing: 1.0,
            crossAxisSpacing: 1.0,
            padding: EdgeInsets.symmetric(horizontal: 2.0, vertical: 6.0),
            shrinkWrap: true,
            itemCount: snapshot.data.documents.length,
            itemBuilder: (context, int index) => Container(
              child: Column(
                children: <Widget>[
                  Card(
                    color: Colors.white,
                    shape: RoundedRectangleBorder(
                      borderRadius: BorderRadius.circular(12.0),
                    ),

                    child: Column(children: <Widget>[
                      ListTile(
                        title: Text(
                          '${(snapshot.data.documents[index]['title'])}',
                          style: GoogleFonts.lato(
                            fontSize: 20.0,
                            height: 1.2,
                            fontWeight: FontWeight.w500,
                          ),
                          textAlign: TextAlign.center,
                        ),

                        subtitle: Row(
                            mainAxisSize: MainAxisSize.max,
                            crossAxisAlignment: CrossAxisAlignment.start,
                            children: <Widget>[



                              MaterialButton(
                                child: Text('Share text'),
                                onPressed: () async => await _shareText(),
                              ),

                              SizedBox(height: 5.0),
                              ImageInput(),  //this displays image called 
from image_picker to share , it works for sharing an image. 


                              Expanded(
                                child: Text(
                                  '${(snapshot.data.documents[index] 
   ['subtitle'])}',
                                  textAlign: TextAlign.right,
                                  style: GoogleFonts.lato(
                                    fontSize: 13.0,
                                    fontWeight: FontWeight.w900,
                                    fontStyle: FontStyle.italic,
                                    color: Colors.blue,
                                  ),
                                ), //subtitle: Text
                              ),
                            ] //children
                        ), //Row
                      ), //listtile
                    ]),
                  ),
                ],
              ),
            ),
            staggeredTileBuilder: (int index) => StaggeredTile.fit(2),
          );
        }),
  ),
);
} //build
} //class

I copied my ImageInput() class page into the main page because I can't get both the image and text to share together, I still see the "undefined" errors for both text and snapshot in the share text field. This same fix doesn't work for the text, although it's on the same page now. What am I doing wrong?

MaterialButton(
      child: Text('Send it!'),
      onPressed: () async => await _shareImageAndText(snapshot, index),
    ),

---

Future<void> _shareImageAndText(snapshot, index) async {
try {
  List<int> imageBytes = await _imageFile.readAsBytes();
  var uint8List = Uint8List.fromList(imageBytes);
  await Share.file('esys image', 'esys.jpg', uint8List, 'image/jpeg',
      text: (snapshot.data.documents[index].data['title']) );
      //text: 'My optional text.');
  // (snapshot.data.documents[index].data['title']), 'text/plain');
  } catch (e) {
  print('error: $e');
  }}

class ImageInput extends StatefulWidget {
@override
_ImageInputState createState() => _ImageInputState();
}

class _ImageInputState extends State<ImageInput> {

 File _imageFile;

 void _getImage(BuildContext context, ImageSource source){
ImagePicker.pickImage(source: source, maxWidth: 200.0).then((File image){
  setState((){
    _imageFile = image;
  });
  Navigator.pop(context);

});
 }

  void _openImagePicker(BuildContext context) {
 showModalBottomSheet(context: context, builder: (BuildContext context) {
  return Container(
    height: 180.0,
    padding: EdgeInsets.all(10.0),
    child: Column(
        children: [
          Text('Choose photo',
            style:TextStyle(fontWeight: FontWeight.bold),),
          SizedBox(height: 10.0),
          FlatButton(
            textColor: Theme.of(context).primaryColor,
            child: Text('Use Camera'),
            onPressed: () {
              _getImage(context, ImageSource.camera);
            },),
          FlatButton(
            textColor: Theme.of(context).primaryColor,child:
          Text('Open Gallery'),
            onPressed: () {
              _getImage(context, ImageSource.gallery);
            },)

        ]
    ),);
});
}

  @override
  Widget build(BuildContext context) {
  return Column(
  children: <Widget>[
    OutlineButton(
      onPressed: () {
        _openImagePicker(context);
      },
      child:Row(
          mainAxisAlignment: MainAxisAlignment.start,
          children: <Widget>[
            Icon(Icons.camera_alt),
            SizedBox(
              width:1.0,
            ),
            // Text('Add Image'),
          ]
      ),//Row
    ),//outline button

    SizedBox(height: 10.0),
    _imageFile == null ? Text('Add a Pic')  : Image.file(_imageFile,
      fit: BoxFit.cover,
      height: 200.0,
      width: 200.0,
      // width: MediaQuery.of(context).size.width,
      alignment: Alignment.topCenter,
    ),

    MaterialButton(
      child: Text('Send it!'),
      onPressed: () async => await _shareImageAndText(),

    ),
  ],
);
}
}

Solution

  • Future<void> _shareText(snapshot, index) async {
    try {
      Share.text('Share Text ',
          (snapshot.data.documents[index].data['title']), 'text/plain');
    } catch (e) {
      print('error: $e');
    }
    }
    

    and pass the snapshot parameter inside your StreamBuilder call it like this,

    onPressed: () async => await _shareText(snapshot, index),