AsyncSnapshot rejecting Type Annotation - flutter

I have a StreamBuilder that is taking data from my bloc component.
However it keeps rejecting my type annotation AsyncSnapshot<List<int>> snapshot and only accepts dynamic as a type AsyncSnapshot<List<dynamic>> snapshot. Yet in the examples i've viewed they do have type annotaions with no complaints.
Here is my stream creation.
Widget buildList(StoriesBloc bloc) {
return StreamBuilder(
stream: bloc.topIds,
builder: (BuildContext context, AsyncSnapshot<List<int>> snapshot) {
if (!snapshot.hasData) {
return Text("Still Waiting for Ids to fetch");
}
return ListView.builder(
itemCount: snapshot.data.length,
itemBuilder: (context, int index) {
return Text('${snapshot.data[index]}');
},
);
},
);
}
Here is the VSCode error generated.
What could i be doing wrong ?

Turns out my bloc.topIds result type was not of type List<int>.
Observable<List> get topIds => _topIds.stream;
So i simply changed it to fulfill the required type.
Observable<List<int>> get topIds => _topIds.stream;
And that fixed the issue. Hope it helps someone else.

Related

uid is not defined for type 'Object' in flutter

i am trying to check if a user id is the same as the current user's id by using data.uid but i keep getting this error:
The getter 'uid' isn't defined for the type 'Object'.
this is the code
Widget build(BuildContext context) {
return FutureBuilder(
future: Future.value(FirebaseAuth.instance.currentUser),
builder: (context, futureSnapshot){
if(futureSnapshot.connectionState == ConnectionState.waiting){
return Center(child: CircularProgressIndicator(),);
}
return StreamBuilder <QuerySnapshot>(
stream: firestore.collection('chats').orderBy('timeStamp', descending: true).snapshots(),
builder:(ctx, chatSnapshot){
if(chatSnapshot.connectionState == ConnectionState.waiting){
return Center(child: CircularProgressIndicator(),);
}
final chatdocs = chatSnapshot.data!.docs;
return ListView.builder(
reverse: true,
itemCount: chatdocs.length ,
itemBuilder: (ctx, index) => messageBubble(
chatdocs[index]['text'],
chatdocs[index]['userId'] == futureSnapshot.data!.uid, //this is the error
)
);
}
);
} );
Since you don't declare the type of the Future in your FutureBuilder, it resolves to an Object. And an Object doesn't have a uid property, which is why you get the error.
To solve this declare the type of your FutureBuilder, which in your case would be:
return FutureBuilder<User>(
Note that I have no idea why you're using a FutureBuilder here to begin with. The FirebaseAuth.instance.currentUser is a synchronous value, so you don't need a FutureBuilder to access it. Removing the FutureBuilder would lead to the exact same result.
If you're trying to make your code respond to auth state changes, like that it takes a moment for Firebase to restore the user's sign-in state when you start the app, you'll want to actually listen to authStateChanges with a StreamBuilder for that nowadays, as shown in the first code snippet in the documentation on getting the current user. Here too, you'll want to declare your StreamBuilder with a User type, just like we did above for the FutureBuilder.
You can try json decoding your variable into the object User you are looking for:
If the futureSnapshot.data is a user you'll be able to use the uid as a map key to check with chatdocs[index]['userId']
Like this:
import 'dart:convert';
final Map<String, dynamic> _valueMap = json.decode(futureSnapshot.data!);
chatdocs[index]['userId'] == _valueMap['uid'];
Try the following code:
StreamBuilder<QuerySnapshot>(
stream: firestore.collection('chats').orderBy('timeStamp', descending: true).snapshots(),
builder: (ctx, chatSnapshot) {
if (chatSnapshot.connectionState == ConnectionState.waiting) {
return const Center(
child: CircularProgressIndicator(),
);
}
final List<QueryDocumentSnapshot<Object?>> chatdocs = chatSnapshot.data!.docs;
final String uid = FirebaseAuth.instance.currentUser?.uid ?? '';
return ListView.builder(
reverse: true,
itemCount: chatdocs.length,
itemBuilder: (ctx, index) {
final Map<String, dynamic> chat = (chatdocs[index]).data() as Map<String, dynamic>;
return messageBubble(
chat['text'],
chat['userId'] == uid,
);
},
);
},
),

Fetching data properly with Futurebuilder and json response

How can I render my response in my text widget?
My json snapshot.data is as following:
"{\"0\":{\"Breed\":\"American Hairless Terrier\",\"count\":1},\"1\":{\"Breed\":\"Bolognese\",\"count\":2},\"2\":{\"Breed\":\"Cavalier King Charles Spaniel\",\"count\":12},\"3\":{\"Breed\":\"Central Asian Shepherd Dog\",\"count\":1},\"4\":{\"Breed\":\"Papillon\",\"count\":1}}"
I tried to display my data like this:
Text(snapshot.data[index.toString()]['Breed']),
but I am getting:
type 'String' is not a subtype of type 'int' of 'index'
try this, might not be perfect but i will give you some idea, the error is because you are assigning int value to Text widget
Text((snapshot.data[index].
['Breed']).toString());
if you want to show it in
futureBuilder and listview
here:
FutureBuilder(
future: FirebaseFirestore.
instance.
collection("groups").
doc(groupId).snapshots(),
//here your collection name
// and doc id
builder: (context, AsyncSnapshot<DocumentSnapshot> snapshot) {
if (!snapshot.hasData) {
return Text("Loading");
}
var userDocument = snapshot.data["Breeds"];
return ListView.builder(
itemCount: userDocument.length,
shrinkWrap: true,
itemBuilder: (context, index) {
return Text(userDocument[index]);
),
}
);
The indices 0,1,2,3.. are strings(wrapped with quotation marks). But you are providing int.
Try
Text(snapshot.data['Breed'][index.toString()])

Flutter Deferred Not Loaded Error was thrown

I would like to test functions, widgets etc. from lazy loaded packages. I'm using Dart’s deferred imports to shrink the main.dart.js file.
For example: import 'package:spitch/app/splashscreen.dart' deferred as splashscreen;
But because the packages etc. are not ready I get in my tests the following error: "the following _ Deferred Not Loaded Error was thrown building ..."
I have not found anything in the dart and flutter docs about how to test deferred loaded data.
Make sure you call .loadLibrary(); in the deferred object before rendering the widget.
The deffered library/page should be called in async, so wrap it inside a future builder.
Good Examples:
FutureBuilder(
future: home.loadLibrary(),
builder: (BuildContext context, AsyncSnapshot snapshot) {
if (snapshot.connectionState == ConnectionState.done) return home.HomePage();
return Material(child: Center(child: Text('Loading...')));
},
)
void get()async{
await home.loadLibrary().then((value){
// Your navigation code
push(home.HomePage(), context);
});
}
Bad Examples:
return FutureBuilder(
future: home.loadLibrary(),
builder: (context, snapShot) {
return home.HomeBasement();
});
return FutureBuilder<void>(
future: signIn.loadLibrary(),
builder: (BuildContext context, AsyncSnapshot<dynamic> snapshot) {
if (snapshot.hasData) {
return signIn.SignInPage();
} else {
return const Txt(text: 'Loading...');
}
});
In case you are using any linting, please make sure you are not setting any object types like void, dynamic, widget?. If you specify the type, it will throw the error.
Note: You must open the modified code on Incognito tab or a cache
cleared browser, If previous app data is hosted on the page, this will
return the old Error only. So better go Incognito

Flutter/Dart Non-Nullable - Use Snapshot data directly

I am using expansion tiles in my code, and was using snapshot.data.length then accessing data directly from the snapshot when I was using the nullable version of Dart.
However, I changed it down the line to the non-nullable version, and it is throwing the errors below -- how can I access the snapshot data, or convert it into a List/Map to be able to use it?
The attached image shows the errors it's showing me. I tried converting the snapshot.data to another var but that didn't work either.
So I hope this solves your problem. Attached the code and some comments. I tested it in Dartpad and it worked fine like that. If it's still not working please provide more code.
class MyWidget extends StatelessWidget {
#override
Widget build(BuildContext context) {
// you need to define what the future builder will return
return FutureBuilder<List<BudgetItem>>(
// helper.getAllItems() needs to have a return type
// "Future<List<BudgetItem>>"
future: helper.getAllItems(),
builder: (context, snapshot) {
if (snapshot.hasData) {
return ListView.builder(
shrinkWrap: true,
itemCount: snapshot.data!.length,
itemBuilder: (context, index) {
// snapshot.data[index] is now from type "BudgetItem" and you can
// access whatever properties it has
return ListTile(title: Text(snapshot.data![index].title));
},
);
}
// if there is no data you still need to return sth like a loading spinner
return Container();
},
);
}

How to mix stream with Provider?

I am use Provider. I want mix different data source with stream.
Use case: Chat app where some message are from system (date/error message) but other are from database (Firestore).
For example for just get message from database I now use StreamBuilder:
StreamBuilder<QuerySnapshot>(
stream: Firestore.instance.collection('message').snapshots(),
builder: (BuildContext context, AsyncSnapshot<QuerySnapshot> snapshot) {
return new ListView.builder(
itemCount: snapshot.data.documents.length,
itemBuilder: (context, index) {
return messageBuilder(snapshot.data.documents[index], xa);
});
But with StreamBuilder cannot mix data from other source.
I want inject message at messages[index] for different message type.
Possible solution is create separate messages List and feed into ListView.builder:
return new ListView.builder(
itemCount: messages.length,
itemBuilder: (context, index) {
final message = messages[index];
return messageBuilder(message, xa);
});
But how I can use Provider to mix stream from Firestore and also system message into messages List?
How I can bring together data source into final List messages?
Thanks for help!