Trying to display username on Homepage using Flutter - flutter

Using the following code, I am able to retrieve the username of the currently logged in user but when I try to display it, it displays as null.
import 'package:cloud_firestore/cloud_firestore.dart';
import 'package:firebase_auth/firebase_auth.dart';
import 'package:flutter/material.dart';
import 'package:localeventsapp/Screens/Login/login_screen.dart';
import 'package:localeventsapp/model/category.dart';
import 'package:localeventsapp/model/event.dart';
import 'package:localeventsapp/styleguide.dart';
import 'package:localeventsapp/ui/event_details/event_details_page.dart';
import 'package:localeventsapp/ui/homepage/form_widget.dart';
import 'package:provider/provider.dart';
import '../../app_state.dart';
import '../../authentication_service.dart';
import 'category_widget.dart';
import 'event_widget.dart';
import 'home_page_background.dart';
CollectionReference users = FirebaseFirestore.instance.collection("Users");
FirebaseAuth auth = FirebaseAuth.instance;
String uid = auth.currentUser.uid.toString();
// String uName = getUsername(uid).toString();
String getUsername(String uid) {
String username;
DocumentReference documentReference = users.doc(uid);
documentReference.get().then((snapshot) {
username = snapshot.data()['displayName'].toString();
print("Username is " + username);
});
return username;
}
class HomePage extends StatelessWidget {
#override
Widget build(BuildContext context) {
return Scaffold(
body: ChangeNotifierProvider<AppState>(
create: (_) => AppState(),
child: Stack(
children: <Widget>[
HomePageBackground(
screenHeight: MediaQuery.of(context).size.height,
),
SafeArea(
child: SingleChildScrollView(
child: Column(
crossAxisAlignment: CrossAxisAlignment.start,
children: <Widget>[
Padding(
padding: const EdgeInsets.symmetric(horizontal: 32.0),
child: Row(
children: <Widget>[
Text(
"TuLink",
style: fadedTextStyle,
),
Spacer(),
],
),
),
Padding(
padding: const EdgeInsets.symmetric(horizontal: 32.0),
child: Text(
getUsername(uid).toString(),
style: whiteHeadingTextStyle,
),
),
Padding(
padding: const EdgeInsets.symmetric(vertical: 24.0),
child: Consumer<AppState>(
builder: (context, appState, _) =>
SingleChildScrollView(
scrollDirection: Axis.horizontal,
child: Row(
children: <Widget>[
for (final category in categories)
CategoryWidget(category: category),
],
),
),
),
),
Padding(
padding: const EdgeInsets.symmetric(horizontal: 16.0),
child: Consumer<AppState>(
builder: (context, appState, _) => Column(
children: <Widget>[
for (final event in events.where((e) => e
.categoryIds
.contains(appState.selectedCategoryId)))
GestureDetector(
onTap: () {
Navigator.of(context).push(
MaterialPageRoute(
builder: (context) =>
EventDetailsPage(event: event),
),
);
},
child: EventWidget(
event: event,
),
)
],
),
),
),
FloatingActionButton.extended(
onPressed: () {
Navigator.push(context,
MaterialPageRoute(builder: (context) => FormPage()));
},
label: Text('Create'),
icon: Icon(Icons.create),
elevation: 2,
shape: RoundedRectangleBorder(borderRadius: BorderRadius.all(Radius.circular(16.0))),
backgroundColor: Color(0xFF6F35A5),
),
ElevatedButton(
child: Text('Sign Out',
style: TextStyle(
color: Colors.black,
fontSize: 16,
)),
onPressed: () {
context.read<AuthenticationService>().signOut();
Navigator.of(context).push(MaterialPageRoute(builder: (context) => LoginScreen()));
}),
],
),
),
),
],
),
),
);
}
}
class CircularButton extends StatelessWidget {
final double width;
final double height;
final Color color;
final Icon icon;
final Function onClick;
CircularButton(
{this.color, this.width, this.height, this.icon, this.onClick});
#override
Widget build(BuildContext context) {
return Container(
decoration: BoxDecoration(color: color, shape: BoxShape.circle),
width: width,
height: height,
child: IconButton(
icon: icon,
enableFeedback: true,
onPressed: onClick,
),
);
}
}
Specifically this part :
Padding(
padding: const EdgeInsets.symmetric(horizontal: 32.0),
child: Text(
getUsername(uid).toString(),
style: whiteHeadingTextStyle,
),
),
The "getUsername(uid).toString()" portion returns a null here.
This is the getUsername method:
String getUsername(String uid) {
String username;
DocumentReference documentReference = users.doc(uid);
documentReference.get().then((snapshot) {
username = snapshot.data()['displayName'].toString();
print("Username is " + username);
});
return username;
}
But print returns the name just fine. I'm kind of stumped.
Any ideas?

Just add a setState before your return statement
setState({}); /// only works in a statefulWidget
return username;
This is happening because by the time your fetch username the build method runs and the Ui is built that means username is displayed as null in the Ui, but when the username is fetched the variable has the value but its not displayed on screen because you need to redraw the widgets in order to show the updated value on the screen by calling setState thats how flutter works.I would recommend you to play around with the flutters counter app and try to add print statements and remove setState.
Although SetState might not be the best solution there are different techniques though but setState is a good place to start
And then later you could move on to using widgets like
ValueListenableBuilder, FutureBuilder etc

Related

flutter transfer data (color) to create a new widget

I'm creating a calendar app. The problem that I'm now facing is that I want to create a new user of the calendar. The user has the properties (which are now important) image, name and color.
I created a new File For the property color, in which the color can be changed. But I don't know how I can transfer the new color in the other file, so that I can use it to create the user.
I think it is possible to use the Material page route, but perhaps there is a more elegant way to handle this.
Does someone have an idea to handle this in a easy way?
UserSetScreen:
import 'package:calendar_vertical/screens/users_show_screen.dart';
import 'package:calendar_vertical/widgets/color_choose.dart';
import 'package:calendar_vertical/widgets/image_input.dart';
import 'package:flutter/material.dart';
import 'package:provider/provider.dart';
class UserSetScreen extends StatefulWidget {
static const routeName = '/userSetScreen';
#override
State<UserSetScreen> createState() => _UserSetScreenState();
}
class _UserSetScreenState extends State<UserSetScreen> {
final _titleController = TextEditingController();
static const values = <String>[
'Administrator',
'normaler Nutzer',
'eingeschränkter Nutzer'
];
String selectedValue = values.first;
void _saveValues(User user) {
final neuerNutzer = User(
id: DateTime.now().toString(),
name: _titleController.text,
color: Colors.amber,
setAppointments: false,
administrator: false,
);
}
#override
Widget build(BuildContext context) {
final colorData = Provider.of<ColorChoose>(context);
return Scaffold(
appBar: AppBar(
title: Text('Person hinzufügen'),
actions: [
IconButton(
onPressed: () {
Navigator.of(context).pushNamed(UsersShowScreen.routeName);
},
icon: Icon(Icons.people),
),
],
),
body: Column(
children: [
Center(
child: ImageInput(),
),
Expanded(
child: SingleChildScrollView(
child: Padding(
padding: EdgeInsets.all(10),
child: Column(
children: [
TextField(
decoration: InputDecoration(labelText: 'Name'),
controller: _titleController,
),
ColorChoose(),
//CheckboxListTile(
// value: value,
// onChanged: (value) => setState(() => this.value = value!),
// title: Text('Administrator'),
// controlAffinity: ListTileControlAffinity.leading,
//)
],
),
),
))
],
),
);
}
ColorChoose:
import 'package:flutter/material.dart';
import 'package:flutter_colorpicker/flutter_colorpicker.dart';
class ColorChoose extends StatefulWidget {
#override
State<ColorChoose> createState() => _ColorChooseState();
}
class _ColorChooseState extends State<ColorChoose> {
Color currentColor = Colors.white;
#override
Widget build(BuildContext context) {
return Row(
children: [
Text('Farbe: '),
Container(
decoration: BoxDecoration(
color: currentColor,
borderRadius: BorderRadius.all(
Radius.circular(15),
),
),
padding: const EdgeInsets.symmetric(vertical: 10.0, horizontal: 10.0),
margin: EdgeInsets.only(left: 10.0),
),
Spacer(),
ElevatedButton(
onPressed: () => _showColorPicker(context),
child: Text(
'Farbe ändern',
),
),
],
);
}
void _showColorPicker(BuildContext context) {
showDialog(
context: context,
builder: (context) => AlertDialog(
title: Text('Farbe wählen'),
titlePadding: const EdgeInsets.all(0.0),
contentPadding: const EdgeInsets.all(0.0),
content: SingleChildScrollView(
child: Wrap(
children: [
Container(
width: 300,
height: 300,
child: BlockPicker(
pickerColor: currentColor,
onColorChanged: (color) => setState(
() => this.currentColor = color,
),
),
)
],
),
),
actions: [
TextButton(
onPressed: () {
Navigator.of(context).pop();
},
child: Text('Close'),
)
],
),
);
}
}
Thank you very much.
Best regards
Patrick
I guess the best variant is to use GetX or another state manager.
Another way - to choose color right from the user screen, showing a dialog.
Finally you can pass valuenotifier to your color ColorChoose widget.

flutter Problem: How to update number of items count in cart?

I implement to add to cart functionality items added into cart successfully but the number of count in the cart badge is not updated when I reload dart page than the number of count updates.can anyone help me?
I implement to add to cart functionality items added into cart successfully but the number of count in the cart badge is not updated when I reload dart page than the number of count updates.can anyone help me?
This is my Homepage.dart
import 'dart:convert';
import 'package:flutter/material.dart';
import 'package:badges/badges.dart';
import 'package:hospital/BestDeatProducts/best_deal_product_page.dart';
import 'package:hospital/CartPage/pages/cartPage.dart';
import 'package:hospital/Drawer/dropdown_menu.dart';
import 'package:hospital/FirstSection/carousel.dart';
import 'package:hospital/Drawer/drawercontent.dart';
import 'package:hospital/FloatingActionButton/ConsultWithDoctor/consult_with_doctor.dart';
import 'package:hospital/MedicineCateory/medicine_category_page.dart';
import 'package:hospital/SecondSection/second_page.dart';
import 'package:hospital/ThirdSection/third_page.dart';
import 'package:hospital/TrendingProducts/trending_product_page.dart';
import 'package:hospital/constant.dart';
import 'package:hospital/customApiVariable.dart';
import 'package:provider/provider.dart';
import 'package:shared_preferences/shared_preferences.dart';
import 'No Internet/connectivity_provider.dart';
import 'No Internet/no_internet.dart';
import 'package:http/http.dart' as http;
class HomePage extends StatefulWidget {
#override
_HomePageState createState() => _HomePageState();
}
class _HomePageState extends State<HomePage> {
SharedPreferences loginData;
// late String username;
Future getUsername() async {
loginData = await SharedPreferences.getInstance();
setState(() {
// print("uname" + uname.toString());
print("dddpppuu1 : responceData_un" +
loginData.getString('responceData_un').toString());
print("dddpppuu2 : responceData_ue" +
loginData.getString('responceData_ue').toString());
print("dddpppuu3 : responceData_status" +
loginData.getString('responceData_status').toString());
String responceData_uid =
loginData.getString('responceData_uid').toString();
fetchData(responceData_uid);
});
}
var response;
var addToCartApi;
#override
void initState() {
// TODO: implement initState
//
super.initState();
Provider.of<ConnectivityProvider>(context, listen: false).startMonitering();
// for loading
getUsername();
}
fetchData(String argResponceData_uid) async {
var api = Uri.parse(
'$ecommerceBaseUrl/addToCartApi.php?a2rTokenKey=$a2rTokenKey&action=addToCartList&uid=${argResponceData_uid}');
print('cartpage' + api.toString());
response = await http.get(api);
print("Carousel" + response.body);
addToCartApi = jsonDecode(response.body);
print('addToCartApi' + addToCartApi['total'].toString());
print('totalPriceAfterOffer' + totalPriceAfterOffer.toString());
setState(() {});
}
#override
Widget build(BuildContext context) {
return Scaffold(
appBar: AppBar(
backgroundColor: kGreen,
title: Text(
"BK Arogyam",
style: TextStyle(fontStyle: FontStyle.italic),
),
actions: [
response != null
? Badge(
position: BadgePosition.topEnd(top: 3, end: 18),
animationDuration: Duration(milliseconds: 300),
animationType: BadgeAnimationType.slide,
badgeContent: Text(
addToCartApi['total']['num'].toString(),
style: TextStyle(color: Colors.white),
),
child: IconButton(
icon: Icon(Icons.shopping_cart),
padding: EdgeInsets.only(right: 30.0),
onPressed: () {
Navigator.push(
context,
MaterialPageRoute(builder: (context) => Cartpage()),
);
}),
)
: IconButton(
icon: Icon(Icons.shopping_cart),
// onPressed: () => print("open cart"),
onPressed: () {
Navigator.push(
context,
MaterialPageRoute(builder: (context) => Cartpage()),
);
},
),
DropDownMenu(),
],
),
floatingActionButton: FloatingActionButton(
backgroundColor: kGreen,
onPressed: () => Navigator.push(context,
MaterialPageRoute(builder: (context) => ConsultWithDoctor())),
tooltip: 'Consult With Doctor',
child: Container(
child: Image(
image: AssetImage(
"assets/icons/cwd.png",
),
color: Colors.white,
width: 40,
height: 40,
),
),
),
drawer: Drawer(
child: DrawerContent(),
),
body: pageUI());
}
Widget pageUI() {
return Consumer<ConnectivityProvider>(
builder: (consumerContext, model, child) {
if (model.isOnline != null) {
return model.isOnline
? ListView(
children: [
Carousel(),
SizedBox(
height: 10.0,
),
MedicineCategoryPage(),
SizedBox(
height: 10.0,
),
SecondPage(),
SizedBox(
height: 10.0,
),
ThirdPage(),
SizedBox(
height: 10.0,
),
TrendingProductPage(),
SizedBox(
height: 16.0,
),
BestDealProductPage(),
SizedBox(
height: 10.0,
),
],
)
: NoInternet();
}
return Container(
child: Center(
child: CircularProgressIndicator(),
),
);
},
);
}
}
You can use the change notifier provide by provider package.
And watch the video on how to use, exactly for ur use case search YouTube change notifier provider by the growing developer
Hope it helps 🙂
You can use provider(provider: ^5.0.0) or Getx(get: ^4.1.4) to handle this kind of case.
There are lots of examples are available for GetX and Provider.
If you don't want to use any of them, Then store your cart/badge count to tempCartCount variable(Example: int cartCount = 0) and set it to the badge count instead of "addToCartApi['total']['num'].toString()" , Make sure to setState on update/addCart Item.
Here I provide a simple example of how to update count on appBar.
if you want to change from any other screen make cartCount to global otherwise you can set it local/private.
import 'package:badges/badges.dart';
import 'package:flutter/material.dart';
class UpdateCountExample extends StatefulWidget {
#override
_UpdateCountExampleState createState() => _UpdateCountExampleState();
}
int cartCount = 0;
class _UpdateCountExampleState extends State<UpdateCountExample> {
List<String> cartArray = [];
#override
void initState() {
WidgetsBinding.instance!.addPostFrameCallback((timeStamp) {
setState(() {
cartCount = 0;
});
});
super.initState();
}
#override
Widget build(BuildContext context) {
return Scaffold(
appBar: AppBar(
title: Text("App Bar"),
actions: [
Padding(
padding: const EdgeInsets.only(right: 18.0, top: 5.0),
child: Badge(
badgeContent: Text(cartCount.toString()),
child: Icon(Icons.add_shopping_cart),
),
)
],
),
body: Container(
alignment: Alignment.center,
padding: EdgeInsets.all(20),
child: Column(
mainAxisSize: MainAxisSize.min,
mainAxisAlignment: MainAxisAlignment.center,
crossAxisAlignment: CrossAxisAlignment.center,
children: [
Text(
"Add item in cart",
textAlign: TextAlign.center,
style: TextStyle(fontWeight: FontWeight.bold, fontSize: 18, decoration: TextDecoration.none, color: Colors.black),
),
SizedBox(
height: 20,
),
InkWell(
onTap: () {
setState(() {
cartArray.add("value ${cartArray.length}");
cartCount = cartArray.length;
});
},
child: Container(
padding: const EdgeInsets.all(10.0),
color: Colors.amber,
child: Text(
"Add Item",
textAlign: TextAlign.center,
style: TextStyle(fontSize: 15, decoration: TextDecoration.none, color: Colors.black),
),
),
),
Expanded(
child: ListView.builder(
shrinkWrap: true,
itemCount: cartArray.length,
itemBuilder: (context, index) {
return Text(
cartArray[index],
style: TextStyle(fontSize: 20, color: Colors.black),
);
}),
)
],
),
),
);
}
}
I have used StreamBuilder to update cart items instantly.
You can use the code from this post
How to use Streambuilder in flutter

Flutter Unhandled Exception: NoSuchMethodError: The getter 'uid' was called on null

First of all, I would like to say I have seen all the previous posts on this error but none of them resolved my issue and that's why I am posting it.
Actually, I have understood the problem but unable to resolve it. So, the below dart file is my HomeScreen().
import 'package:flutter/material.dart';
import 'package:intl/intl.dart';
import 'package:mukti/authentication/firestore_service.dart';
import 'package:mukti/schedule/task.dart';
import 'package:mukti/schedule/taskdata.dart';
import 'package:provider/provider.dart';
import 'add_class.dart';
import 'package:firebase_auth/firebase_auth.dart' as auth;
class HomeScreen extends StatefulWidget {
static final String routeName = 'homeScreen';
final auth.User firebaseUser;
HomeScreen({this.firebaseUser});
#override
_HomeScreenState createState() => _HomeScreenState();
}
class _HomeScreenState extends State<HomeScreen> {
final FirestoreService firestoreService = FirestoreService();
#override
Widget build(BuildContext context) {
print("HomeScreen");
print(widget.firebaseUser);
return Scaffold(
body: SafeArea(
child: SizedBox.expand(
child: Padding(
padding: const EdgeInsets.all(48.0),
child: Column(
mainAxisAlignment: MainAxisAlignment.start,
crossAxisAlignment: CrossAxisAlignment.start,
children: [
SingleChildScrollView(
child: Container(
width: MediaQuery.of(context).size.width,
height: 450,
color: Colors.yellow[100],
child: generateTaskList(),
),
),
SizedBox(height: 45),
/* Add Class Button */
Center(
child: GestureDetector(
onTap: () {
Navigator.push(
context, MaterialPageRoute(
builder: (context) => AddClass(),
),
);
},
child: Container(
height: 75,
width: 75,
decoration: BoxDecoration(
shape: BoxShape.circle,
boxShadow: [
BoxShadow(
color: Colors.grey,
offset: Offset(0, 4), //(x,y)
blurRadius: 1.0,
),
],
color: Color(0xFFF9A826),
),
child: Icon(
Icons.add,
size: 35,
color: Colors.white,
),
),
),
),
],
),
),
),
),
);
}
Widget generateTaskList() {
//print("Firebase User : ${widget.firebaseUser.uid}");
Provider.of<TaskData>(context, listen: false).loadTaskList(widget.firebaseUser);
print('List Generated');
var taskListLength = Provider.of<TaskData>(context, listen: false).getTaskListCount();
return Consumer<TaskData>(
builder: (context, taskData, child) => ListView.builder(
itemCount: taskData.taskList.length,
itemBuilder: (context, index) {
print("TaskList");
return Container(
padding: EdgeInsets.all(16.0),
decoration: new BoxDecoration (
borderRadius: BorderRadius.circular(10),
color: Color(0xFFF9A826),
),
child: ListTile(
title: Text(
taskData.taskList[index].description ?? 'default',
style: TextStyle(
color: Colors.white,
fontWeight: FontWeight.w600,
),
),
subtitle: Text(
"${Util.getFormattedDate(taskData.taskList[index].scheduledDateTime)}" ?? 'default',
style: TextStyle(
color: Colors.white54,
),
),
),
);
}
)
);
}
}
class Util {
static String getFormattedDate(DateTime dateTime) {
return new DateFormat("EEE, MMM d, y").format(dateTime);
}
}
Initially, firebaseUser is not null, I have crossed checked it and it is printing the data in the app but when I add more entries from AddClass() and returns to HomeScreen() again, firebaseUser becomes null and no data is shown in the app anymore.
The below code is my AddClass() code:
import 'package:flutter/material.dart';
import 'package:mukti/authentication/authService.dart';
import 'package:mukti/authentication/firestore_service.dart';
import 'package:mukti/schedule/scheduled_date.dart';
import 'package:mukti/schedule/task.dart';
import 'package:mukti/ui_pages/main_screen/timepicker.dart';
import 'package:provider/provider.dart';
import 'package:table_calendar/table_calendar.dart';
import 'package:firebase_auth/firebase_auth.dart' as auth;
import 'home_screen.dart';
class AddClass extends StatefulWidget {
static final String routeName = 'addClass';
#override
_AddClassState createState() => _AddClassState();
}
class _AddClassState extends State<AddClass> {
final FirestoreService firestoreService = FirestoreService();
#override
Widget build(BuildContext context) {
print("Add Class Screen");
return Scaffold(
resizeToAvoidBottomInset: false,
backgroundColor: Color(0xFFFFFFE5),
body: SafeArea(
child: Column(
mainAxisAlignment: MainAxisAlignment.center,
crossAxisAlignment: CrossAxisAlignment.center,
children: [
/* Meeting url TextField Widget */
/* Description TextField Widget */
/* Calender */
/* Add Class Button */
Expanded(
child: GestureDetector(
onTap: () async{
auth.User firebaseUser = await Provider.of<AuthService>(context, listen: false).getUser();
DateTime scheduledDateTime = Provider.of<ScheduledDate>(context, listen: false).scheduledDateTime;
print(scheduledDateTime);
print(firebaseUser);
final task = Task(
link: 'xyz',
isDone: false,
description: 'xyz',
scheduledDateTime: scheduledDateTime,
);
firestoreService.addTask(firebaseUser, task);
print('Task Added');
Navigator.popAndPushNamed(context,
HomeScreen.routeName,
arguments: firebaseUser,
);
},
child: Align(
alignment: FractionalOffset.bottomCenter,
child: Container(
height: 50,
width: MediaQuery.of(context).size.width,
decoration: BoxDecoration(
color: Color(0xFFF9A826),
),
child: Center(
child: Text(
'SCHEDULE CLASS',
style: Theme.of(context).textTheme.bodyText1.copyWith(
color: Colors.white,
fontWeight: FontWeight.w700,
fontSize: 16,
letterSpacing: 0.5,
),
)
)
),
),
),
),
],
),
),
);
}
}
Actually, I have removed unnecessary codes, so after adding one more class to the database, I return to HomeScreen but this time firebaseUser becomes null, although I am sending it in the argument of the routes HomeScreen is receiving null. This is my problem.
How can I resolve this..?
If anyone needs more information, feel free to ask me.
Thanks

Use StreamBuilder to display data for current user (not all users' data) from Firestore

I'm trying to use StreamBuilder in flutter to return a list, but only for the current user logged in. When I tried
StreamBuilder<QuerySnapshot>(
stream: _firestore.collection('meals').where('email', isEqualTo: loggedInUser.email).orderBy('date', descending: true).snapshots(),
I keep getting the following error:
The getter 'email' was called on null.
Receiver: null
Tried calling: email
It works fine when I take the .where part out, but then it just returns all data from every single user, and I only want it to return the data linked to that current user.
Any ideas would be really helpful so thank you in advance.
Jason
EDIT:
Here's some more code for a bit more context:
import 'package:firebase_auth/firebase_auth.dart';
import 'package:cloud_firestore/cloud_firestore.dart';
import 'package:flutter/widgets.dart';
import 'package:intl/intl.dart';
import 'package:less_food/utilities/add_edit_meal_log.dart';
import 'package:less_food/utilities/constants.dart';
final _firestore = Firestore.instance;
FirebaseUser loggedInUser;
class MealLog extends StatefulWidget {
#override
_MealLogState createState() => _MealLogState();
}
class _MealLogState extends State<MealLog> {
final _auth = FirebaseAuth.instance;
FirebaseUser loggedInUser;
#override
void initState() {
super.initState();
getCurrentUser();
}
void getCurrentUser() async {
try {
FirebaseUser user = await _auth.currentUser();
if (user != null) {
setState(() {
loggedInUser = user;
print('this is: ${loggedInUser.email}');
});
}
} catch (e) {
print(e);
}
}
#override
Widget build(BuildContext context) {
return Scaffold(
body: SafeArea(
child: Column(
mainAxisAlignment: MainAxisAlignment.spaceBetween,
crossAxisAlignment: CrossAxisAlignment.stretch,
children: <Widget>[
MealsStream(),
],
),
),
);
}
}
class MealsStream extends StatelessWidget {
#override
Widget build(BuildContext context) {
return StreamBuilder<QuerySnapshot>(
stream: _firestore.collection('meals').where('email', isEqualTo: loggedInUser.email).orderBy('date', descending: true).snapshots(),
builder: (context, snapshot) {
if (!snapshot.hasData) {
return Center(
child: CircularProgressIndicator(
backgroundColor: Colors.lightBlueAccent,
),
);
}
final meals = snapshot.data.documents.reversed;
List<MealBubble> mealBubbles = [];
for (var meal in meals) {
final mealDate = meal.data['date'].toDate();
print(DateFormat('dd-MM-yyyy').format(mealDate));
final mealSelection = meal.data['mealSelection'];
final mealDietChoice = meal.data['dietChoice'];
final mealBubble = MealBubble(
date: mealDate,
selection: mealSelection,
dietChoice: mealDietChoice,
);
mealBubbles.add(mealBubble);
}
return Expanded(
child: ListView(
reverse: false,
padding: EdgeInsets.symmetric(vertical: 20.0),
children: mealBubbles,
),
);
},
);
}
}
class MealBubble extends StatelessWidget {
MealBubble({this.date, this.selection, this.dietChoice});
final DateTime date;
final String selection;
final String dietChoice;
#override
Widget build(BuildContext context) {
return Padding(
padding: EdgeInsets.all(10.0),
child: Container(
color: Colors.white,
child: Column(
children: <Widget>[
Material(
borderRadius: BorderRadius.circular(10.0),
elevation: 5.0,
color: Colors.lightBlueAccent,
child: Padding(
padding: EdgeInsets.symmetric(horizontal: 5.0),
child: Row(
mainAxisAlignment: MainAxisAlignment.spaceAround,
children: <Widget>[
Padding(
padding: const EdgeInsets.symmetric(horizontal: 13.0),
child: Text(
'${DateFormat('dd-MM-yyyy').format(date)}',
style: TextStyle(
color: Colors.white,
fontSize: 15.0,
),
),
),
Text(
selection,
textAlign: TextAlign.start,
style: TextStyle(
color: Colors.white,
fontSize: 15.0,
),
),
SizedBox(
width: 2.0,
),
Text(
dietChoice,
textAlign: TextAlign.start,
style: TextStyle(
color: Colors.white,
fontSize: 15.0,
),
),
ButtonTheme(
materialTapTargetSize: MaterialTapTargetSize.shrinkWrap,
minWidth: 0,
child: FlatButton(
child: Text(
'Edit',
style: kMealLogEditButtonTextStyle,
),
onPressed: () {
showModalBottomSheet(
context: context,
builder: (context) => AddEditMealLog(),
isScrollControlled: true,
);
},
),
),
],
),
),
),
],
),
),
);
}
}
The problem is that your global variable loggedInUser is never initialized. Still, you do have another variable with the exact same name being initialized in another class and I think this may be causing you confusion.
As you can see, you declare two FirebaseUser objects with the name loggedInUser, one with a file scope (it exists globally on the file) and another within a class, thus having class scope (it only exists inside that class!). When you initialize loggedInUser in the function _MealLongState.getCurrentUser() you are using the class variable, not the global one. Then, when you access loggedInUser from the method MealsStream.build() you are getting the global variable, which hasn't been initialized.
The solution would be to remove the declaration of the variable loggedInUser from inside the class _MealLogState.

How to display a single property of an object in listview

I have a list of goal objects with two properties, description (what I want to display) and ID (used as a key to identify it). Ultimately I want a list of goal descriptions (ex. mow lawn, get groceries etc) but I'm confused how to specify a single property with the listview builder. The reason I'm using an object is because I want to use swipe to dismiss on the list. I'm using an object to give each goal a unique key, therefore when I swipe to dismiss I can safely undo the dismissal / reorder the list.
File Structure: lib folder contains functions, goals and main. A sub-folder in the lib folder called UI contains form and home.
main.dart
import 'package:flutter/material.dart';
import 'package:aurelius/UI/home.dart';
void main() => runApp(new MyApp());
class MyApp extends StatelessWidget {
#override
Widget build(BuildContext context){
return new MaterialApp(
debugShowCheckedModeBanner: false,
title: "ToDo",
home: myWidgets(),
);
}
}
Widget myWidgets(){
return GoalsList();
}
home.dart
import 'package:flutter/material.dart';
import 'package:aurelius/goals.dart';
import 'package:aurelius/functions.dart';
//Goals List Variables
var goals = List<Goals>();
final TextEditingController listCtrl = new TextEditingController();
class GoalsList extends StatefulWidget{
#override
_GoalsListState createState() => _GoalsListState();
}
class _GoalsListState extends State<GoalsList>{
final formKey = GlobalKey<FormState>(); //key for goal form
#override
Widget build(BuildContext context){
final listSize = MediaQuery.of(context).size.height * 1;
return Scaffold(
resizeToAvoidBottomPadding: false,
extendBody: true,
backgroundColor: Colors.black,
//Navigation Bar
floatingActionButton: Padding(
padding: const EdgeInsets.all(8.0),
child: Container(
decoration: BoxDecoration(
border: Border.all(
color: Colors.white,
),
borderRadius: BorderRadius.circular(25.0),
),
child: FloatingActionButton.extended(
elevation: 4.0,
icon: const Icon(Icons.add),
label: const Text('Add Goal'),
backgroundColor: Colors.black,
splashColor: Colors.white,
//Pop-up Dialogue
onPressed: () {
showDialog(
context: context,
builder: (BuildContext context){
return AlertDialog(
title: Center(child: new Text("New Goal:",)),
content: Form(
key: formKey,
child: Column(
mainAxisSize: MainAxisSize.min,
children: <Widget>[
TextFormField(
decoration: InputDecoration(
border: OutlineInputBorder(borderRadius: BorderRadius.all(Radius.circular(12))),
),
controller: listCtrl,
),
RaisedButton(
child: Text("ADD"),
onPressed: (){
goals.add(createGoal(listCtrl.text));
listCtrl.clear();
Navigator.pop(context);
},
splashColor: Colors.blue,
elevation: 2,
)
]
),
)
);
}
);
},
),
),
),
floatingActionButtonLocation:FloatingActionButtonLocation.centerDocked,
//Bottom App Bar
bottomNavigationBar: BottomAppBar(
shape: CircularNotchedRectangle(),
notchMargin: -30.0,
color: Colors.black,
child: new Row(
mainAxisSize: MainAxisSize.max,
mainAxisAlignment: MainAxisAlignment.spaceBetween,
children: <Widget>[
IconButton(icon: Icon(Icons.person_outline),color: Colors.white,splashColor: Colors.white, onPressed: (){},),
IconButton(icon: Icon(Icons.settings),color: Colors.white,splashColor: Colors.white, onPressed: (){},),
],
),
),
//Goals List Box
body: Column(children: <Widget>[
SizedBox(height: listSize,
child: ListView.builder(
itemCount: goals.length,
itemBuilder: (context,index){
return Dismissible(
key: UniqueKey(),
//Green background and icon for left side swipe
background: Container(
color: Colors.green[300],
padding: EdgeInsets.symmetric(horizontal: 20),
alignment: AlignmentDirectional.centerStart,
child: Icon(
Icons.check_box,
color: Colors.white,
),
),
//Green background and icon for right side swipe
secondaryBackground: Container(
color: Colors.green[300],
padding: EdgeInsets.symmetric(horizontal: 20),
alignment: AlignmentDirectional.centerEnd,
child: Icon(
Icons.check_box,
color: Colors.white,
),
),
onDismissed:(direction){
if(goals.contains(index)){
setState((){
goals.removeAt(index);
});
}
},
child: Padding(
padding: const EdgeInsets.all(20),
child: Column(
crossAxisAlignment: CrossAxisAlignment.start,
children: <Widget>[
Text(goals[index].description),
],
),
),
);
},
),
),
//Potential more rows here
],
)
);
}
}
}
goals.dart
import 'package:flutter/material.dart';
import 'package:aurelius/UI/home.dart';
class Goals{
String description; //part visible to user
int id;
Goals({this.description,this.id});
}
functions.dart
import 'package:flutter/material.dart';
import 'package:aurelius/goals.dart';
import 'package:uuid/uuid.dart';
createGoal(String text){
var goal = new Goals();
goal.description = text;
goal.id = new DateTime.now().millisecondsSinceEpoch;
return goal;
}
form.dart
import 'package:flutter/material.dart';
class AddButton extends StatefulWidget {
#override
AddButtonState createState() => new AddButtonState();
}
class AddButtonState extends State<AddButton>{
Color addbuttoncolor = Colors.red;
IconData addIcon = Icons.add;
void onPressed(){
setState((){
if (addIcon == Icons.add) {
addIcon = Icons.clear;
}
else{
addIcon = Icons.add;
}
});
}
#override
Widget build(BuildContext context){
return Scaffold(
body: Container(
child: Center(
child: Column(
mainAxisAlignment: MainAxisAlignment.center,
children: <Widget>[
new RawMaterialButton(
onPressed: onPressed,
child: new Icon(
addIcon,
color: Colors.blue,
size: 35.0,
),
shape: new CircleBorder(),
elevation: 2.0,
fillColor: Colors.white,
padding: const EdgeInsets.all(15.0),
),
]
),
),
)
);
}
}
I think the problem is when you creating the goal, you don't return created goal. Your createGoal() method should return the goal like below:
createGoal(String text){
var goal = new Goals();
goal.description = text;
goal.id = new DateTime.now().millisecondsSinceEpoch;
return goal; // Add this
}
The only issue I see is that you don't return the object you create in createGoal().
To display the description with the Dismissible, you would just set its child to child: Text(goals[index].description)
To optimize the code, you can initialize the Goal id directly in the class itself. You can set the constructor as Goals(this.description) and the createGoal function will not be needed anymore.
PS: Keeping your class names singular is a better practice