Reputation: 195
Is it possible to have the .getDownloadURL() string in a stream so that it can be accessed by multiple places in a widget tree and be constantly up to date whenever its changed?
at the moment i'm attempting to setup a streambuilder:
return Scaffold(
body: ListView.builder(
itemCount: products.length,
itemBuilder: (context, index) {
return StreamBuilder<String>(
stream: ImageDatabaseService().getImageLocation(products[index]),
builder: (context, snapshot) {
return ProductTile(product: products[index]);
});
},
The stream is coming from the ImageDataseService class:
class ImageDatabaseService {
String _imageLocation;
StorageReference ref;
void init() {}
Stream<String> getImageLocation(Product product) {
ref = FirebaseStorage.instance
.ref()
.child('images/' + product.kaizenID + '.png');
return getURL();
}
Future<String> getURL() async {
await ref.getDownloadURL().then((location) {
return location;
});
}
}
The issue is that ImageDatabaseService returns a Future String when it needs to return a Stream String but then at the widget end i just need a String
Ive been scouring these forums and the net but haven't come across anything useful.
Upvotes: 0
Views: 305
Reputation: 195
What was interesting though was that the provider doesn't count a showModalSheet in a void method in the widget build method as a child. I had to put another stream provider in it for the EditProduct tree to pick it up
Widget build(BuildContext context) {
var _imageLocation = Provider.of<String>(context);
void _showEditProductPanel() {
showModalBottomSheet(
isScrollControlled: true,
context: context,
builder: (context) {
return Container(
padding: EdgeInsets.symmetric(vertical: 50.0, horizontal: 60.0),
child: StreamProvider<String>.value(
initialData: '',
value: ImageDatabaseService().imageLocation(widget.product),
child: EditProductForm(product: widget.product),
));
});
}
return Padding(
padding: EdgeInsets.only(top: 8.0),
child: Card(
margin: EdgeInsets.fromLTRB(20, 6, 20, 0),
child: ListTile(
leading: Image.network(_imageLocation),
title: Text(widget.product.name ?? ''),
subtitle: Text('KaizenID: ${widget.product.kaizenID}'),
trailing: FlatButton(
child: Icon(Icons.edit),
onPressed: () => _showEditProductPanel(),
),
),
),
);
}
Upvotes: 0
Reputation: 576
Change your ImageDatabaseService class to;
class ImageDatabaseService {
StorageReference ref;
void init() {}
Stream<String> get imageLocation(Product product) {
ref = FirebaseStorage.instance
.ref()
.child('images/' + product.kaizenID + '.png');
return ref.getDownloadURL()
.asStream().map((downloadUrl)
=> downloadUrl;
}
}
It will return a String in snapshot.data
inside your StreamBuilder.
Dont forget to change your stream to;
stream: ImageDatabaseService().imageLocation(products[index]),
Dont forget to add a condition to check for the connection state in your builder.
if(snapshot.ConnectionState == ConnectionState.active){
return ProductTile(product: products[index]);
} else{
return Center(child: CircularProgressIndicator(),);
}
Upvotes: 1