Error: No AWSAccessKey was presented - flutter Amplify - flutter

I have a code like this in my flutter project:
final imageUrl = await Amplify.Storage.getUrl(key: urlKey);
return StreamBuilder(
stream: imageUrl.url,
builder: (context, snapshot) {
if (snapshot.hasData) {
if (snapshot.data.length != 0) {
return GridView.builder(
gridDelegate: SliverGridDelegateWithFixedCrossAxisCount(
crossAxisCount: 1),
itemCount: snapshot.data.length,
itemBuilder: (context, index) {
return CachedNetworkImage(
imageUrl: snapshot.data,
fit: BoxFit.cover,
placeholder: (context, url) => Container(
alignment: Alignment.center,
child: CircularProgressIndicator(),
),
);
});
} else {
// 5
return Center(child: Text('No images to display.'));
}
} else {
// 6
return Center(child: CircularProgressIndicator());
}
});

I figured that in order to access an existing object from your bucket with amplify, you have to put those objects in a Public folder. So your URL should be something like: aws..../public/other-folders-or-assets

Related

Fetch data from Firestore Document using StreamBuilder

In my Flutter app, I'm trying to get the data from a Document in Firestore. Here's the data I want to get :
Firestore document's data
I need to fetch that url from the Document. So far, when I needed to fetch data from a collection, I used a Streambuilder. But here I need to fetch data from a document, so I get this error message :
late Stream<DocumentSnapshot<Map<String, dynamic>>>? personnalData =
FirebaseFirestore.instance
.collection('Decembre')
.doc(uid)
.collection('Docs')
.doc('test')
.snapshots();
StreamBuilder<QuerySnapshot>(
stream: personnalData, // Error: The argument type 'Stream<DocumentSnapshot<Map<String, dynamic>>>?' can't be assigned to the parameter type 'Stream<QuerySnapshot<Map<String, dynamic>>>?'.
builder: (BuildContext context,
AsyncSnapshot<QuerySnapshot> snapshot) {
if (snapshot.hasError) {
return const Text('Something went wrong');
}
if (snapshot.connectionState == ConnectionState.waiting) {
return Center(child: CircularProgressIndicator());
}
return Stack(
children: snapshot.data!.docs
.map((DocumentSnapshot document) {
Map<String, dynamic> data =
document.data()! as Map<String, dynamic>;
return PageView.builder(
controller: _controller,
itemCount: 3,
itemBuilder: (context, index) {
return Container(
child: InteractiveViewer(
minScale: 0.1,
maxScale: 4.0,
child: Image.network(
// FETCH URL FROM DOCUMENT 'TEST'
width:
MediaQuery.of(context)
.size
.width,
fit: BoxFit.cover,
loadingBuilder: (context,
child,
loadingProgress) {
if (loadingProgress ==
null) {
return child;
} else {
return Center(
child:
CircularProgressIndicator(),
);
),
);
}),
),
],
),
),
);
},
child: Text('Open'));
})
.toList()
.cast(),
);
},
),
Any suggestions ?
I found the solution !
The problem was that I was trying to fetch data from a DocumentSnapshot using a StreamBuilder<QuerySnapshot> instead of StreamBuilder<DocumentSnapshot>
Here's how I solved it :
late Stream<DocumentSnapshot<Map<String, dynamic>>> personnalData =
FirebaseFirestore.instance
.collection('Decembre')
.doc(uid)
.collection('Docs')
.doc('test')
.snapshots();
StreamBuilder<DocumentSnapshot>(
stream: personnalData,
builder: (BuildContext context,
AsyncSnapshot<DocumentSnapshot> snapshot) {
if (snapshot.hasData) {
return Text(snapshot.data!['url']);
}
return CircularProgressIndicator();
}),
This code is working well for me. I hope that will help somebody !
Maybe what you need is just to specify the type of the QuerySnapshot:
late Stream<DocumentSnapshot<Map<String, dynamic>>> personnalData = // like this FirebaseFirestore.instance
.collection('Decembre')
.doc(uid)
.collection('Docs')
.doc('test')
.snapshots();
because the snapshots() is a method that returns Stream<DocumentSnapshot<Map<String, dynamic>>>, and setting only Stream<DocumentSnapshot> will be considered as a different type, which throws the error.
maybe you can try
StreamBuilder<DocumentSnapshot<Map<String, dynamic>>>(
stream: personnalData,
builder: (BuildContext context,
AsyncSnapshot<QuerySnapshot> snapshot) {
if (snapshot.hasError) {
return const Text('Something went wrong');
}
if (snapshot.connectionState == ConnectionState.waiting) {
return Center(child: CircularProgressIndicator());
}
return Stack(
children: snapshot.data!.docs
.map((DocumentSnapshot document) {
Map<String, dynamic> data =
document.data()! as Map<String, dynamic>;
return PageView.builder(
controller: _controller,
itemCount: 3,
itemBuilder: (context, index) {
return Container(
child: InteractiveViewer(
minScale: 0.1,
maxScale: 4.0,
child: Image.network(
// FETCH URL FROM DOCUMENT 'TEST'
width:
MediaQuery.of(context)
.size
.width,
fit: BoxFit.cover,
loadingBuilder: (context,
child,
loadingProgress) {
if (loadingProgress ==
null) {
return child;
} else {
return Center(
child:
CircularProgressIndicator(),
);
),
);
}),
),
],
),
),
);
},
child: Text('Open'));
})
.toList()
.cast(),
);
},
),
in streamBuilder you can add <DocumentSnapshot<Map<String, dynamic>>> same as you create stream.
Refer the following example:
StreamBuilder<DocumentSnapshot>(
stream: FirebaseFirestore.instance.collection('Decembre').doc(uid).collection('Docs').doc('test').snapshots(),
builder: (context, snapshot) {
if (snapshot.hasData) {
return ListView.builder(
itemCount: snapshot.data!.docs.length,
itemBuilder: (context, index) {
DocumentSnapshot doc = snapshot.data!.docs[index];
return Column(
children:[
Text(doc['url'])
);
});
} else {
return Text("No data");
}
},
)

Flutter FutureBuilder duplicates items inside a GridView

It seems that the GridView.builder inside FutureBuilder duplicates each element a number of times equal to the list length.
Here is the code:
InformationScreen:
List<Reference> documentReference = [];
Widget showSavedDocument() => FutureBuilder(
future: _futureListResult,
builder: (context, AsyncSnapshot<ListResult> snapshot) {
if (snapshot.connectionState == ConnectionState.done && snapshot.hasData) {
return ListView.builder(
itemCount: snapshot.data!.items.length,
itemBuilder: (context, index) {
final photo = snapshot.data!.items[index].getDownloadURL();
final photoName = snapshot.data!.items[index].name;
final metaData = snapshot.data!.items[index].getMetadata();
documentReference = snapshot.data!.items;
return Column(
children: [
FutureBuilder(
future: metaData,
builder: (context, AsyncSnapshot<FullMetadata> snapshot) {
if(snapshot.hasData) {
photoType = snapshot.data!.contentType!;
}
return Container();
},
),
FutureBuilder(
future: photo,
builder: (context, AsyncSnapshot<String?> snapshot) {
if (snapshot.hasData) {
final image = snapshot.data;
List<Document> documents = [];
for (int i = 0; i < documentReference.length; i++) {
Document document = Document(user!.uid, image!, photoName, photoType);
documents.add(document);
}
return DocumentGrid(documents: documents,); // <------------------------------
}
return Container();
},
),
],
);
},
shrinkWrap: true,
physics: const BouncingScrollPhysics(),
);
}
if (snapshot.connectionState == ConnectionState.waiting || !snapshot.hasData) {
return const Loader();
}
if (snapshot.hasError) {
return Utils.showErrorMessage(snapshot.hasError.toString());
}
return Container();
},
);
DocumentGrid
import 'package:flutter/material.dart';
import 'package:app_test/constant/color.dart';
import '../constant/text.dart';
import '../model/document.dart';
class DocumentGrid extends StatelessWidget {
final List<Document> documents;
const DocumentGrid({Key? key, required this.documents}) : super(key: key);
#override
Widget build(BuildContext context) {
return buildGridView();
}
//****************************************************************************
// Create GridView
//****************************************************************************
Widget buildGridView() => GridView.builder(
itemCount: documents.length,
gridDelegate: const SliverGridDelegateWithFixedCrossAxisCount(
crossAxisCount: 2,
crossAxisSpacing: 2,
mainAxisSpacing: 2,
),
itemBuilder: (context, index) {
final photo = documents[index].photo;
final title = documents[index].title;
final type = documents[index].type;
return buildGridViewItem(photo, title, type);
},
shrinkWrap: true,
physics: const BouncingScrollPhysics(),
);
//****************************************************************************
// Create GridView item
//****************************************************************************
Widget buildGridViewItem(String photo, String? title, String type) => Container(
width: 50,
height: 50,
color: phoneButtonColor,
child: Stack(
fit: StackFit.expand,
alignment: Alignment.center,
children: [
buildNetworkImage(photo, type),
buildBlackOpacity(title),
],
),
);
//****************************************************************************
// Create Network image
//****************************************************************************
Widget buildNetworkImage(String photo, String type) => Image.network(
fit: BoxFit.cover,
width: 100,
height: 100,
photo,
errorBuilder: (context, exception, stackTrace) {
return type == "pdf" || type != "jpg"
|| type != "jpeg" || type != "png"
? Image.asset(
fit: BoxFit.cover,
width: 100,
height: 100,
"assets/images/pdf.png",
)
: Container(
color: grey,
width: 100,
height: 100,
child: const Center(
child: Text(
errorLoadImage,
textAlign: TextAlign.center,
),
),
);
},
);
//****************************************************************************
// Create Black opacity
//****************************************************************************
Widget buildBlackOpacity(String? title) => Container(
color: Colors.black54,
padding: const EdgeInsets.symmetric(
vertical: 30,
horizontal: 20,
),
child: Column(
children: [
Expanded(
child: Center(
child: Text(
title!,
style: const TextStyle(
fontSize: 20,
color: Colors.white,
),
),
),
),
],
),
);
}
How can I solve that, thanks in advance
Problem solved
Replacing ListView by GridView
Widget showSavedDocument() => FutureBuilder(
future: _futureListResult,
builder: (context, AsyncSnapshot<ListResult> snapshot) {
if(snapshot.connectionState == ConnectionState.done && snapshot.hasData) {
return GridView.builder(
itemCount: snapshot.data!.items.length,
gridDelegate: const SliverGridDelegateWithFixedCrossAxisCount(
crossAxisCount: 2,
crossAxisSpacing: 2,
mainAxisSpacing: 2,
),
itemBuilder: (context, index) {
final instructorDocument = snapshot.data!.items;
final photo = instructorDocument[index].getDownloadURL();
final photoName = instructorDocument[index].name;
final metaData = instructorDocument[index].getMetadata();
return Column(
children: [
FutureBuilder(
future: metaData,
builder: (context, AsyncSnapshot<FullMetadata> snapshot) {
if (snapshot.hasData) {
photoType = snapshot.data!.contentType!;
}
return Container();
},
),
FutureBuilder(
future: photo,
builder: (context, AsyncSnapshot<String?> snapshot) {
if (snapshot.hasData) {
final image = snapshot.data!;
return Expanded(
child: buildGridViewItem(image, photoName, photoType),
);
}
return Container();
},
),
],
);
},
shrinkWrap: true,
physics: const BouncingScrollPhysics(),
);
}
if(snapshot.connectionState == ConnectionState.waiting || !snapshot.hasData) {
return const Loader();
}
if(snapshot.hasError) {
return Utils.showErrorMessage(snapshot.hasError.toString());
}
return Container();
},
);

FutureBuilder and Services function

I am using future builder with service function like this, when getUserProfile function
When I get the APIService.getUserProfile() funciton return Forbidden(403) error I want to navigate to login page, how can I do that where can I add this navigator function in my code ? How can I detect and return Login Page
body: FutureBuilder(
future: APIService.getUserProfile(),
builder: (
BuildContext context,
AsyncSnapshot<String> model,
) {
if (model.hasData) {
return SingleChildScrollView(
physics: ClampingScrollPhysics(),
child: Padding(
padding: const EdgeInsets.all(20),
child: Column(
crossAxisAlignment: CrossAxisAlignment.start,
children: [
Container(
height: 240,
child: FutureBuilder(
future: getCurrentUser(),
builder: (context, snapshot) {
return ListView.separated(
itemBuilder: (context, index) {
print(index);
if (username == null) {
return Text(
""); //GetUserName(documentId: user!.uid);
} else {
print("build");
return MyCard(
balance: balance ?? 0,
creditCardsNumber: 0,
userName: username.toString(),
card: myCards[index],
);
}
},
separatorBuilder: (context, index) {
return SizedBox(width: 10);
},
itemCount: 1,
shrinkWrap: true,
scrollDirection: Axis.horizontal,
);
}),
),
SizedBox(
height: 30,
),
Text(
"Recent Payments",
style: ApptextStyle.BODY_TEXT,
),
SizedBox(
height: 15,
),
FutureBuilder(
future: getCurrentUser(),
builder: (context, snapshot) {
return ListView.separated(
itemBuilder: (context, index) {
if (username != null) {
return TransactionCard(
transaction: myTransactions[index]);
} else {
return Text("");
}
},
separatorBuilder: (context, index) {
return SizedBox(height: 10);
},
itemCount: myTransactions.length,
shrinkWrap: true,
physics: NeverScrollableScrollPhysics(),
);
})
],
),
),
);
} else if (model.hasError) {
print("HEREEE");
Navigator.push(
context,
MaterialPageRoute(
builder: (context) {
return LoginScreen();
},
),
);
return Text("asdasfsdfd");
}
return Text("");
}));

Why is there an error with snapshot.data.length?

I am trying to parse data from an API. For that, I am using FutureBuilder to list all the parsed data in a ListView.
I've performed a check for nullity of snapshot.data but I keep on getting this error in the segment snapshot.data.length, it says, The property 'length' can't be unconditionally accessed because the receiver can be 'null'. Try making the access conditional (using '?.') or adding a null check to the target ('!').
I've a similar error in the snapshot.data[i] section, which says The method '[]' can't be unconditionally invoked because the receiver can be 'null'. Try making the call conditional (using '?.') or adding a null check to the target ('!').
Here is my code's section of the same:
body: Container(
child: FutureBuilder(
future: getData('hello'),
builder: (context, snapshot) {
if (snapshot.data == null) {
return Container(
child: Text("Loading"),
);
}else{
return ListView.builder(
itemCount: snapshot.data.length,
itemBuilder: (context, i) {
return ListTile(
title: snapshot.data[i].partOfSpeech,
);
});
}
},
),
),
Here's getData(String s):
Future<List> getData(String s) async {
var response = await http
.get(Uri.https('api.dictionaryapi.dev', 'api/v2/entries/en_US/' + s));
var jsonData = jsonDecode(response.body)[0];
List<Data> data = [];
for (var x in jsonData["meanings"]) {
String definition = x["definitions"][0]["definition"];
Data d = Data(x["partOfSpeech"], definition);
data.add(d);
}
return data;
}
if u are using a new version of flutter (2.2.0 or above). first try adding a null check to the target ('!'). because of the null safety feature.
body: Container(
child: FutureBuilder(
future: getData('hello'),
builder: (context, snapshot) {
if (snapshot.data == null) {
return Container(
child: Text("Loading"),
);
}else{
return ListView.builder(
itemCount: snapshot.data!.length,
itemBuilder: (context, i) {
return ListTile(
title: snapshot.data[i].partOfSpeech,
);
});
}
},
),
),
then try specifying the FutureBuilder type to a List of Data type
body: Container(
child: FutureBuilder<List<Data>>(
future: getData('hello'),
builder: (context, snapshot) {
if (snapshot.data == null) {
return Container(
child: Text("Loading"),
);
}else{
return ListView.builder(
itemCount: snapshot.data.length,
itemBuilder: (context, i) {
return ListTile(
title: snapshot.data[i].partOfSpeech,
);
});
}
},
),
),
In continuation to this answer,
I found the solution to my problem. Apparently getData was not returning a List as intended. Instead, it was returning an Object.
Typecasting the Object to List solved the problem.
Here's the corrected code:
body: Container(
child: FutureBuilder(
future: getData('hello'),
builder: (context, snapshot) {
if (snapshot.data == null) {
return Container(
child: Text("Loading"),
);
}else{
//typecasting Object to List
var data = (snapshot.data as List<Data>).toList();
return ListView.builder(
itemCount: data.length,
itemBuilder: (context, i) {
return ListTile(
title: data[i].partOfSpeech,
);
});
}
},
),
),
Put 'AsyncSnapshot' before snapshot in the builder parameter.
builder: (context, AsyncSnapshot snapshot)
Since you are checking that snapshot.data is not null you can do the following to fix it.
body: Container(
child: FutureBuilder(
future: getData('hello'),
builder: (context, snapshot) {
if (snapshot.data == null) {
return Container(
child: Text("Loading"),
);
} else{
return ListView.builder(
itemCount: snapshot.data!.length,
itemBuilder: (context, i) {
return ListTile(
title: snapshot.data[i]!.partOfSpeech,
);
});
}
},
),
),
What you need to look at is the result of getData('hello')
Apparently, it does not return something that has a length property.

Flutter query (where + order by) from firebase firestore returns error

My queries from flutter app return error. any ideas why?
Query user = FirebaseFirestore.instance.collection('users').where('approvedStatus', isEqualTo: true).orderBy('name');
How i show data from query
Container(
child: StreamBuilder(
stream: user.snapshots(),
builder: (BuildContext context, snapshot) {
if (snapshot.hasError) {
return Text('Snapshot return error');
}
if (snapshot.connectionState == ConnectionState.waiting) {
return Text("Loading ..."); // CircularProgressIndicator();
}
return Container(
height: MediaQuery.of(context).size.height,
child: ListView.builder(
shrinkWrap: true,
itemCount: snapshot.data.docs.length,
itemBuilder: (context, i) {
return Card(
child: ListTile(
title: Text(snapshot.data.docs[i]['name'].toString()),
),
);
},
),
);
},
),
),
The result i got is snapshot return error
Nevermind guys. I found the problem after printing snapshot.error
[cloud_firestore/failed-precondition] The query requires an index.
I just follow the link provided and it solve the problem . Thanks