I'm a newbie in Flutter.
I have stored data in firestore in nested collections as you can see hereFirestore1 and hereFirestore2.
I wrote code for that as below:
class Timeline extends StatefulWidget {
#override
_TimelineState createState() => _TimelineState();
}
class _TimelineState extends State<Timeline>
with AutomaticKeepAliveClientMixin<Timeline> {
final eventref = FirebaseFirestore.instance.collection('event');
final slider = SleekCircularSlider(
appearance: CircularSliderAppearance(
spinnerMode: true,
size: 50.0,
));
List<EventCard> event = [];
getEvents() async {
print(user.uid);
QuerySnapshot snapshot =
await eventref.doc(user.uid).collection('post').limit(2).get();
List<EventCard> event = [];
snapshot.docs.forEach((doc) {
print('this is doc ------');
print(doc);
event.add(EventCard.fromMap(doc.data()));
});
return event;
}
#override
bool get wantKeepAlive => true;
#override
Widget build(context) {
return Scaffold(
body: Container(
child: FutureBuilder(
future: getEvents(),
builder: (context, snapshot) {
if (!snapshot.hasData) {
return slider;
}
print('reached here:${snapshot.data}');
return ListView(
children: snapshot.data,
);
},
)),
);
}
}
class EventCard extends StatelessWidget {
final String id;
final String event;
final String organiser;
final String description;
final String date;
final String startTime;
EventCard({
this.id,
this.event,
this.organiser,
this.description,
this.date,
this.startTime,
});
factory EventCard.fromMap(Map<String, dynamic> doc) {
return EventCard(
id: doc['id'],
event: doc['Event'],
organiser: doc['Organiser'],
description: doc['Description'],
date: doc['Date'],
startTime: doc['Start Time'],
);
}
#override
Widget build(BuildContext context) {
return Container(
child: Text('Done'),
);
}
}
Sorry for long code, but only response i'm getting with this is here Debug Result
I tried to make 'EventCard' without build method as i saw in a tutorial online, but here it show error 'No concrete implementation of EventCard'
Any help? Thanks in Advance.
Related
#This is my model class
List<SliderModel> sliderModelFromJson(String str) => List<SliderModel>.from(json.decode(str).map((x) => SliderModel.fromJson(x)));
String sliderModelToJson(List<SliderModel> data) => json.encode(List<dynamic>.from(data.map((x) => x.toJson())));
class SliderModel {
SliderModel({
this.id,
this.title,
this.description,
this.image,
this.type,
this.url,
this.schoolid,
});
int id;
String title;
dynamic description;
String image;
String type;
String url;
String schoolid;
factory SliderModel.fromJson(Map<String, dynamic> json) => SliderModel(
id: json["id"],
title: json["title"],
description: json["description"],
image: json["image"],
type: json["type"],
url: json["url"],
schoolid: json["schoolid"],
);
Map<String, dynamic> toJson() => {
"id": id,
"title": title,
"description": description,
"image": image,
"type": type,
"url": url,
"schoolid": schoolid,
};
}
#this is my services class where i call my api
static Future<List<SliderModel>> getSliderData(String id) async{
var dio = don.Dio();
don.Response response =await dio.get("https://shikshyasoftware.com.np/CoreApplicationandAPIService-4617993073/api/shikshyanotice?schoolid=$id") ;
try{
var responseData = response.data;
if(response.statusCode==200){
print("responseData:-${responseData}");
return sliderModelFromJson(jsonEncode(responseData));
}
}catch(e){
rethrow;
}
}
#this is my controller class
class SliderController extends GetxController{
var isLoading = true.obs;
var sliderData = <SliderModel>[];
Future<void> fetchImageSilder(String id) async{
try{
isLoading(true);
var slider = await Services.getSliderData(id);
sliderData = slider;
print(sliderData.length);
}finally{
isLoading(false);
}
}
SliderModel findById(String id){
return sliderData.firstWhere((e) => e.schoolid == id,orElse: ()=>null);
}
}
#this is my view where i tried to call the controller and load the image like this
var isInit = true;
void didChangeDependencies() {
// TODO: implement didChangeDependencies
if(isInit) {
final schoolId = ModalRoute.of(context).settings.arguments;
Get.put(SliderController().fetchImageSilder(schoolId));
}
isInit = false;
super.didChangeDependencies();
}
SliderController sliderData = Get.put(SliderController());
Obx((){
if(sliderData.isLoading.value){
return Center(
child: LinearProgressIndicator(
minHeight: 95.h,
color: Colors.grey.shade100,
backgroundColor: Colors.grey.shade200,
),
);
}else{
return SizedBox(
// height: MediaQuery.of(context).size.height*0.15,
// width: MediaQuery.of(context).size.width*0.99,
height: 95.h,
width: double.infinity,
child:CarouselSlider(
items:sliderData.sliderData.map((e) =>ClipRRect(
borderRadius: BorderRadius.circular(5.r),
child: Stack(
fit: StackFit.expand,
children: [
Image.network(e.image??Image.asset("icons/shik_banner_20200553123753.png"),fit: BoxFit.fill,errorBuilder: (BuildContext context, Object exception, StackTrace stackTrace) {
return Image.asset("icons/shik_banner_20200553123753.png");
},)
],
),
) ).toList()
, options: CarouselOptions(viewportFraction: 1,autoPlay: false,autoPlayAnimationDuration: const Duration(milliseconds: 800),
),
),
);
}
#i am not getting any error but my loading screen continues to load and image is not shown and i am getting show this W/Choreographer(22264): Frame time is 16.052103 ms in the future! Check that graphics HAL is generating vsync timestamps using the correct timebase. in my run and i dont know what to do to load my image need your help thanks in advance
Try to use folllowing code. I will suggest to use the StatefulWidget Widget to call your methods specially if your methods having the paramters. initState helps to call our functions. If you finds this answer helpful please upvote
class MyHomePage extends StatefulWidget {
const MyHomePage({Key? key, required this.title}) : super(key: key);
final String title;
#override
State<MyHomePage> createState() => _MyHomePageState();
}
class _MyHomePageState extends State<MyHomePage> {
final _sliderController= Get.put(SliderController());
#override
void initState() {
super.initState();
_sliderController.fetchImageSilder(schoolId);//Here you can pass parameters to your function
}
#override
Widget build(BuildContext context) {
return Scaffold(
appBar: AppBar(
title: Text(widget.title),
),
body: Obx((){
if(sliderData.isLoading.value){
return Center(
child: LinearProgressIndicator(
minHeight: 95.h,
color: Colors.grey.shade100,
backgroundColor: Colors.grey.shade200,
),
);
}else{
return Widget()// Pass your Widget
}
);
}
}
// Getx Controller
class SliderController extends GetxController{
var isLoading = true.obs;
RxList<SliderModel> sliderData = [].obs; // If you are using `Obx()` then your list type should be obs
Future<void> fetchImageSilder(String id) async{
try{
isLoading(true);
var slider = await Services.getSliderData(id);
sliderData.add(slider); // Add your data into `RxList`
print(sliderData.length);
}finally{
isLoading(false);
}
}
SliderModel findById(String id){
return sliderData.firstWhere((e) => e.schoolid == id,orElse: ()=>null);
}
}
I am building a food recipe app where user can browse various recipes.
The functionality is that, when user hit delete button, the item will not be shown in listing. I navigated the the mealId to the previous screen, i.e. Listing screen through
floatingActionButton: FloatingActionButton(
onPressed: () {
Navigator.of(context).pop(mealId);
},
child: const Icon(Icons.delete),
),
I receive the pop() value in backward widget like:
void selectMeal(BuildContext context) {
Navigator.of(context)
.pushNamed(MealsDetailsScreen.routeName, arguments: id)
.then((result) {
if (result != null) {
removeItem(result);
print(result); // it prints the expected id
}
});
}
And in the code attached fully, I wanted to remove the item details via mealId
void _removeMeal(String mealId) {
setState(() {
print("$mealId from didChangedDependancies"); //it also prints the expected id
displayedMeals.removeWhere((meal) => meal.id == mealId);
});
}
The code where I set the function to remove:
import 'package:flutter/material.dart';
import '../models/meals.dart';
import '../models/dummy_data.dart';
import '../widgets/meal_item.dart';
class CategoryMealaScreen extends StatefulWidget {
static const routeName = '/category-meals';
#override
State<CategoryMealaScreen> createState() => _CategoryMealaScreenState();
}
class _CategoryMealaScreenState extends State<CategoryMealaScreen> {
late String categoryTitle;
late List<Meal> displayedMeals;
var _loadedInitData = false;
#override
void initState() {
super.initState();
}
#override
void didChangeDependencies() {
if (!_loadedInitData) {
final routeArgs =
ModalRoute.of(context)!.settings.arguments as Map<String, String>;
categoryTitle = routeArgs['title'].toString();
final categoryId = routeArgs['id'];
displayedMeals = dummyMeals.where((meal) {
return meal.categories.contains(categoryId);
}).toList();
_loadedInitData = true;
}
super.didChangeDependencies();
}
void _removeMeal(String mealId) {
setState(() {
print("$mealId from didChangedDependancies");
displayedMeals.removeWhere((meal) => meal.id == mealId);
});
}
#override
Widget build(BuildContext context) {
final routeArgs = // received data from widget CategoryItems()
ModalRoute.of(context)!.settings.arguments as Map<String, String>;
final categoryTitle = routeArgs['title'];
final categoryId = routeArgs['id'];
final displayedMeals = dummyMeals.where((meal) {
return meal.categories.contains(categoryId);
}).toList();
return Scaffold(
appBar: AppBar(
title: Text(categoryTitle.toString()),
),
body: ListView.builder(
itemCount: displayedMeals.length,
itemBuilder: (ctx, index) {
return MealItem(
id: displayedMeals[index].id,
title: displayedMeals[index].title,
imageUrl: displayedMeals[index].imageUrl,
complexity: displayedMeals[index].complexity,
affordability: displayedMeals[index].affordability,
duration: displayedMeals[index].duration,
removeItem: _removeMeal,
);
}),
);
}
}
No error shows on console.
I'll be vary happy if you guys help me out! Thanks a lot😎
Remove final displayedMeals inside your build method.
Use the displayedMeals variable outside your build method instead.
I want to add my data in listview.
also tried using this https://flutter.dev/docs/cookbook/lists/long-lists
I got data in futureAlbum, and snapshot has data. but i can't convert these data in listView.builder. so, how to implement listview in FutureBuilder?
body: Center(
child: FutureBuilder<ListAlbum>(
future: futureAlbum,
builder: (context, snapshot) {
if (snapshot.hasData) {
print(snapshot.data);
return Text(snapshot.data!.idEmployee.toString()); // in this section i want to add listview
} else if (snapshot.hasError) {
return Text('${snapshot.error}');
}
return const CircularProgressIndicator();
},
),
),
full code of calling api
class OrganizationList extends StatefulWidget {
const OrganizationList({Key? key}) : super(key: key);
#override
_OrganizationListState createState() => _OrganizationListState();
}
class _OrganizationListState extends State<OrganizationList> {
late Future<ListAlbum> futureAlbum;
#override
void initState() {
super.initState();
futureAlbum = listData();
}
#override
Widget build(BuildContext context) {
return Scaffold(
body: Center(
child: FutureBuilder<ListAlbum>(
future: futureAlbum,
builder: (context, snapshot) {
if (snapshot.hasData) {
print(snapshot.data);
return Text(snapshot.data!.idEmployee.toString()); // in this section i want to add listview
} else if (snapshot.hasError) {
return Text('${snapshot.error}');
}
return const CircularProgressIndicator();
},
),
),
);
}
}
class ListAlbum {
final int idEmployee;
final String avatar;
final String fullName;
final String officeID;
final String email;
final String designation;
final String department;
final String mobileNumber;
final String workStation;
final String businessUnit;
ListAlbum({
required this.idEmployee,
required this.avatar,
required this.fullName,
required this.officeID,
required this.email,
required this.designation,
required this.department,
required this.mobileNumber,
required this.workStation,
required this.businessUnit,
});
factory ListAlbum.fromJson(Map<String, dynamic> json) {
return ListAlbum(
idEmployee: json['idEmployee'],
avatar: json['avatar'],
fullName: json['fullName'],
officeID: json['officeID'],
email: json['email'],
designation: json['designation'],
department: json['department'],
mobileNumber: json['mobileNumber'],
workStation: json['workStation'],
businessUnit: json['businessUnit'],
);
}
}
Future<ListAlbum> listData() async {
final token =
'eyJ0eXAiOiJKV1QiLCJhbGciOiJIUzI1NiJ9.eyJzdWIiOjI4OTksImlzcyI6Imh0dHBzOi8vcG9ydGFsLWFwaS5qb21ha2hhdGEuY29tL2FwaS9hdXRoL2xvZ2luIiwiaWF0IjoxNjI5NTI2OTc1LCJleHAiOjE2Mjk2MTMzNzUsIm5iZiI6MTYyOTUyNjk3NSwianRpIjoiRktiT295eEYwaEpDUXMxdiJ9.o4eM_C4hlluHe9Azk0MspPJtYZ7agdpFA6xwKiijLj8';
String url =
'https://portal-api.jomakhata.com/api/getOrganizationData?token=${token}';
Dio dio = new Dio();
dio.options.headers['Content-Type'] = 'application/json';
final body = {'limit': 5, 'orderBy': 'idEmployee', 'orderType': 'DESC'};
final response = await dio.post(url, data: body);
if (response.statusCode == 200) {
print(response.statusCode);
print(response.data);
var data = ListAlbum.fromJson(response.data["data"]["data"][0]);
return data;
} else {
throw Exception('Failed!');
}
}
What list I want to implement!
First, you have all members is ListAlbum marked as required, but some of your results in the response doesn't have all of these, for example second row has no avatar. You can overcome this by marking these fields as not required, like this (I made here all members optional - adjust it as you need):
class ListAlbum {
final int? idEmployee;
final String? avatar;
final String? fullName;
final String? officeID;
final String? email;
final String? designation;
final String? department;
final String? mobileNumber;
final String? workStation;
final String? businessUnit;
ListAlbum({
this.idEmployee,
this.avatar,
this.fullName,
this.officeID,
this.email,
this.designation,
this.department,
this.mobileNumber,
this.workStation,
this.businessUnit,
});
factory ListAlbum.fromJson(Map<String, dynamic> json) {
return ListAlbum(
idEmployee: json['idEmployee'],
avatar: json['avatar'],
fullName: json['fullName'],
officeID: json['officeID'],
email: json['email'],
designation: json['designation'],
department: json['department'],
mobileNumber: json['mobileNumber'],
workStation: json['workStation'],
businessUnit: json['businessUnit'],
);
}
}
Next, convert your listData function so that it will return a list of ListAlbum objects. You can grab the data from your response, convert and return like this:
Future<List<ListAlbum>> listData() async {
final token =
'eyJ0eXAiOiJKV1QiLCJhbGciOiJIUzI1NiJ9.eyJzdWIiOjI4OTksImlzcyI6Imh0dHBzOi8vcG9ydGFsLWFwaS5qb21ha2hhdGEuY29tL2FwaS9hdXRoL2xvZ2luIiwiaWF0IjoxNjI5NTI2OTc1LCJleHAiOjE2Mjk2MTMzNzUsIm5iZiI6MTYyOTUyNjk3NSwianRpIjoiRktiT295eEYwaEpDUXMxdiJ9.o4eM_C4hlluHe9Azk0MspPJtYZ7agdpFA6xwKiijLj8';
String url =
'https://portal-api.jomakhata.com/api/getOrganizationData?token=${token}';
Dio dio = new Dio();
dio.options.headers['Content-Type'] = 'application/json';
final body = {'limit': 5, 'orderBy': 'idEmployee', 'orderType': 'DESC'};
final response = await dio.post(url, data: body);
if (response.statusCode == 200) {
print(response.statusCode);
print(response.data);
return response.data["data"]["data"]
.map<ListAlbum>((json) => ListAlbum.fromJson(json))
.toList();
} else {
throw Exception('Failed!');
}
}
Finally, change the future return type and create the ListView from this list, this is an example, adjust it:
class _OrganizationListState extends State<OrganizationList> {
late Future<List <ListAlbum>> futureAlbum;
#override
void initState() {
super.initState();
futureAlbum = listData();
}
#override
Widget build(BuildContext context) {
return Scaffold(
body: Center(
child: FutureBuilder<List<ListAlbum>>(
future: futureAlbum,
builder: (context, snapshot) {
if (snapshot.hasData) {
print(snapshot.data);
return ListView.builder(
itemCount: snapshot.data!.length,
itemBuilder: (context, index) {
final ListAlbum item = snapshot.data![index];
return ListTile(
leading: Text(item.idEmployee.toString()),
title: Text(item.fullName!),
subtitle: Text(item.designation!),
trailing: Text(item.businessUnit!),
);
},
);
} else if (snapshot.hasError) {
return Text('${snapshot.error}');
}
return const CircularProgressIndicator();
},
),
));
}
}
...and I don't know whether token is a secret or not, but if it is, you should revoke it.
Try this:
Future<List<ListAlbum>> listData() async {
final token =
'eyJ0eXAiOiJKV1QiLCJhbGciOiJIUzI1NiJ9.eyJzdWIiOjI4OTksImlzcyI6Imh0dHBzOi8vcG9ydGFsLWFwaS5qb21ha2hhdGEuY29tL2FwaS9hdXRoL2xvZ2luIiwiaWF0IjoxNjI5NTI2OTc1LCJleHAiOjE2Mjk2MTMzNzUsIm5iZiI6MTYyOTUyNjk3NSwianRpIjoiRktiT295eEYwaEpDUXMxdiJ9.o4eM_C4hlluHe9Azk0MspPJtYZ7agdpFA6xwKiijLj8';
String url =
'https://portal-api.jomakhata.com/api/getOrganizationData?token=${token}';
Dio dio = new Dio();
dio.options.headers['Content-Type'] = 'application/json';
final body = {'limit': 5, 'orderBy': 'idEmployee', 'orderType': 'DESC'};
final response = await dio.post(url, data: body);
if (response.statusCode == 200) {
print(response.statusCode);
print(response.data);
List<ListAlbum> _list=response.data["data"]["data"].map((e)=>ListAlbum.fromJson(e)).toList();
return _list;
} else {
throw Exception('Failed!');
}
}
And your widget to this:
class OrganizationList extends StatefulWidget {
const OrganizationList({Key? key}) : super(key: key);
#override
_OrganizationListState createState() => _OrganizationListState();
}
class _OrganizationListState extends State<OrganizationList> {
late Future<List<ListAlbum>> futureAlbum;
#override
void initState() {
super.initState();
futureAlbum = listData();
}
#override
Widget build(BuildContext context) {
return Scaffold(
body: Center(
child: FutureBuilder<List<ListAlbum>>(
future: futureAlbum,
builder: (context, snapshot) {
if (snapshot.hasData) {
print(snapshot.data);
return Column(
children:[
for(ListAlbum item in snapshot.data)
Text(item.idEmployee.toString())]);
//Or you can also use listview.builder here instead of column, but this will work for proof of concept.
} else if (snapshot.hasError) {
return Text('${snapshot.error}');
}
return const CircularProgressIndicator();
},
),
),
);
}
}
I am using Firebase Database to store information regarding my flutter app.
I have manually updated my collections and documents.
But in one instance I want my users to setdata in my documents so it gets reflected in the app for that particular user. But, when the user does setdate it goes and creates new documents which I do not want, I want the user to setdata in the existing document. I did try but no luck.
Here are my codes:
class FirestoreService {
FirestoreService._();
static final instance = FirestoreService._();
Future<void> setData(
{#required String path, Map<String, dynamic> data}) async {
final reference = Firestore.instance.document(path);
await reference.setData(data);
}
abstract class Database {
Future<void> setRackBook(RackBookItems rackBookItems);
}
bool documentCheckBox() => true;
class FirestoreDatabase implements Database {
final String uid;
FirestoreDatabase({#required this.uid}) : assert(uid != null);
final _service = FirestoreService.instance;
#override
Future<void> setRackBook(RackBookItems rackBookItems) async =>
await _service.setData(
path: APIPath.rackBookItems(uid, rackBookItems.id),
data: rackBookItems.toMap());
}
class PageScreen extends StatefulWidget {
final RackBookItems rackBookItems;
final Database database;
const PageScreen(this.rackBookItems, {#required this.database});
static Future<void> show(
BuildContext context, {
Database database,
RackBookItems rackBookItems,
}) async {
final database = Provider.of<Database>(context);
await Navigator.of(context, rootNavigator: true).push(
MaterialPageRoute(
fullscreenDialog: false,
builder: (context) => PageScreen(
rackBookItems,
database: database,
),
),
);
}
#override
_PageScreenState createState() => _PageScreenState();
}
class _PageScreenState extends State<PageScreen> {
final _formKey = GlobalKey<FormState>();
bool _validateAndSaveForm() {
final form = _formKey.currentState;
if (form.validate()) {
form.save();
return true;
}
return false;
}
Future<void> _completed() async {
if (_validateAndSaveForm()) {
try{
final checkBox = widget.rackBookItems?.checkBox ?? documentCheckBox();
final rackBookItems = RackBookItems(checkBox: checkBox);
await widget.database.setRackBook(rackBookItems);
Navigator.of(context).pop();
} on PlatformException catch (e) {
PlatformExceptionAlertDialog(
title: 'Operations failed',
exception: e,
).show(context);
}
}
}
#override
Widget build(BuildContext context) {
final auth = Provider.of<AuthBase>(context, listen: true);
return SafeArea(
child: Scaffold(
body: Column(
children: <Widget>[
StreamBuilder<User>(
stream: auth.onAuthStateChange,
builder: (context, snapshot) {
User user = snapshot.data;
if (snapshot.hasData) {
return Provider<Database>(
create: (_) => FirestoreDatabase(uid: user.uid),
child: Text('Data'),
);[![enter image description here][1]][1]
}
return Center(
child: CircularProgressIndicator(),
);
},
),
Form(
key: _formKey,
child: RaisedButton(
child: Text(
'Done',
style: TextStyle(color: Theme.of(context).accentColor),
),
onPressed: _completed,
),
)
],
),
),
);
}
}
class RackBookItems {
final String id;
final String rackId;
final String title;
final bool checkBox;
const RackBookItems({
this.id,
this.rackId,
this.title,
this.checkBox,
});
Map<String, dynamic> toMap() {
return {
'checkBox': checkBox,
};
}
factory RackBookItems.fromMap(Map<String, dynamic> data, String id) {
if (data == null) {
return null;
}
final String id = data['id'];
final String rackId = data['rackId'];
final String title = data['title'];
final bool checkBox = data['checkBox'];
return RackBookItems(
id: id,
rackId: rackId,
title: title,
checkBox: checkBox,
);
}
}
This is how my firebase looks like.
[1]: https://i.stack.imgur.com/Z07ai.png
Is there any error with the path I have given?
class APIPath {
static String rackBookItems( String uid, String id) =>
'rackBookItems/$id/';
}
You need to use updateData, this method required you to know the document's Document ID
Firestore.instance.collection('rackBookItems').document('book1').updateData({
'newData' : 14
});
If you need to update all of your documents, you can pull all of the documents and use a for loop to update them.
QuerySnapshot qs = await Firestore.instance.collection('rackBookItems').getDocuments();
List<DocumentSnapshot> books = qs.documents;
for (int i = 0; i < books.length; i++){
Firestore.instance.collection('rackBookItems').documents(books[i].documentID).updateData({
'title' : newData
});
}
updateData is good but in case the document does not exist you should use setData and set merge: true
class FirestoreService {
FirestoreService._();
static final instance = FirestoreService._();
Future<void> setData(
{#required String path, Map<String, dynamic> data}) async {
final reference = Firestore.instance.document(path);
await reference.setData(data, merge:true);
}
I am trying to use StreamProvider and StreamBuilder to pull data from firestore into my app with the code below. I am getting the error "streamusers and "userslist" are not defined as well as "testuser" is not a type. Here is a picture of my firestore databasefirestore setup]1
does anyone know how I can fix this so that it pulls the data from firestore and updates dynamically when new users are added?
Main.dart:
class _MyHomePageState extends State<MyHomePage> {
final auth = FirebaseAuth.instance;
final db = DatabaseService();
#override
Widget build(BuildContext context) {
var user = Provider.of<FirebaseUser>(context);
bool loggedIn = user != null;
final _width = MediaQuery.of(context).size.width;
final _height = MediaQuery.of(context).size.height;
StreamProvider<List<User>>.value(
value: db.streamUsers(user),
child: UsersList(),
),
StreamBuilder<TestUser>(
stream: db.streamTestUser(user.uid),
builder: (context, snapshot) {
var user = snapshot.data;
if (user != null) {
return Stack(...
I also have my db.dart file as so:
class DatabaseService {
final Firestore _db = Firestore.instance;
Future<User> getUser(String id) async {
var snap = await _db.collection('users').document(id).get();
return User.fromMap(snap.data);
}
Stream<User> streamTestUser(String id) {
return _db
.collection('users')
.document(id)
.snapshots()
.map((snap) => User.fromMap(snap.data));
}
}
And finally my user_model.dart file:
class User {
final String name;
final String photourl;
final int totalquestions;
User({this.name, this.photourl, this.totalquestions});
factory User.fromMap(Map data) {
return User(
name: data['name'] ?? '',
photourl: data['photourl'] ?? '',
totalquestions: data['totalquestions'] ?? '',
);
}
}
Try using Builder inside StreamProvider instead of StreamBuilder.
Mine is working using this approach.
class MyHomePage extends StatelessWidget {
#override
Widget build(BuildContext context) {
var user = Provider.of<FirebaseUser>(context);
return StreamProvider<User>.value(
value: db.getUser(user?.uid),
catchError: (_, __) => null,
child: Builder(
builder: (context) {
///Passing UserData Down the Builder
var _userSnapshot = Provider.of<UserData>(context);
///Check UserData Availability
if (_userSnapshot == null) {
return Center(
child: Text('User Empty'),
);
} else {
return Scaffold(
body: Column(
children: <Widget>[
Text(_userSnapshot?.name),
Text(_userSnapshot?.photourl),
Text(_userSnapshot?.totalquestions),
],
),
);
}
},
),
);
}