Flutter - widget variables are always null - firebase

I have a Flutter app connected to firebase, and I'm using it to receive push notifications from Firebase Cloud Messaging, using this code. Whenever I call the variables widget.title, widget.body, they are null, but when the method receives a notification, they have the value that came from FCM. What should I do?
class PushList extends StatefulWidget {
Map<dynamic, dynamic> notific;
String title, body;
Future<dynamic> fcmMessageReceiver() async {
FirebaseMessaging.instance.getInitialMessage().then((value) {
if (value != null) {}
});
FirebaseMessaging.onMessage.listen((RemoteMessage message) {
if (message.notification != null) {
notificacao = {
'title': message.notification.title,
'body': message.notification.body
};
title = message.notification.title;
body = message.notification.body;
print('MENSAGEM: $notific');
}
});
FirebaseMessaging.onMessageOpenedApp.listen((RemoteMessage message) {});
}
PushList() {
}
#override
_PushListState createState() => _PushListState();
}
class _PushListState extends State<PushList> {
#override
Widget build(BuildContext context) {
return Scaffold(
extendBody: true,
backgroundColor: Colors.white,
appBar: null,
body: ListView(
children: [
widget.notific != null
? Card(
margin: EdgeInsets.all(10),
elevation: 4,
child: ListTile(
title: Text(
widget.title,
),
subtitle: Text(
widget.body,
),
),
)
: Container(
child: Text("U don't have new notifcs."),
),
],
),
);
}
}

PushList should be immutable. Define the properties inside the state and call fcmMessageReceiver inside initState. Also you need to call setState to trigger rebuild after you set title and body:
class PushList extends StatefulWidget {
#override
_PushListState createState() => _PushListState();
}
class _PushListState extends State<PushList> {
Map<dynamic, dynamic> notific;
String title, body;
#override
void initState() {
super.initState();
fcmMessageReceiver();
}
Future<dynamic> fcmMessageReceiver() async {
FirebaseMessaging.instance.getInitialMessage().then((value) {
if (value != null) {}
});
FirebaseMessaging.onMessage.listen((RemoteMessage message) {
if (message.notification != null) {
if (mounted) {
setState(() {
notificacao = {
'title': message.notification.title,
'body': message.notification.body
};
title = message.notification.title;
body = message.notification.body;
});
}
print('MENSAGEM: $notific');
}
});
FirebaseMessaging.onMessageOpenedApp.listen((RemoteMessage message) {});
}
#override
Widget build(BuildContext context) {
return Scaffold(
extendBody: true,
backgroundColor: Colors.white,
appBar: null,
body: ListView(
children: [
notific != null
? Card(
margin: EdgeInsets.all(10),
elevation: 4,
child: ListTile(
title: Text(
title ?? '',
),
subtitle: Text(
body ?? '',
),
),
)
: Container(
child: Text("U don't have new notifcs."),
),
],
),
);
}
}

Related

set a username & profile picture firebase login and then get it for a profile later on

ok, its late and I can't quite figure this out for some reason. I am coming from swift and newer to flutter. my code is below, I can't get my username to register in my json or anything else and I can't figure out how to pull it out later either, any help would be appreciated, I can pull out all the data but I haven't figured out how to assign the displayName or profile picture on a later screen
class WelcomeScreen extends StatefulWidget {
const WelcomeScreen({Key? key}) : super(key: key);
static const String id = 'welcome_screen';
#override
_WelcomeScreenState createState() => _WelcomeScreenState();
}
class _WelcomeScreenState extends State<WelcomeScreen> with SingleTickerProviderStateMixin{
FirebaseAuth auth = FirebaseAuth.instance;
final _auth = FirebaseAuth.instance;
var _isLoading = false;
late AnimationController controller;
late Animation animation;
void _completeLogin() {
Navigator.pushReplacement<void, void>(
context,
MaterialPageRoute<void>(
builder: (BuildContext context) => Home(),
),
);
}
void _submitAuthForm(
String email,
String username,
String password,
File imageFile,
bool isLogin,
BuildContext ctx,
) async {
UserCredential authResult;
try {
setState(() {
_isLoading = true;
});
if (isLogin) {
authResult = await _auth.signInWithEmailAndPassword(
email: email,
password: password,
);
print('$username');
} else {
authResult = await _auth.createUserWithEmailAndPassword(
email: email,
password: password,
);
print('$username');
final ref = FirebaseStorage.instance
.ref()
.child('user_image')
.child(authResult.user!.uid + 'jpg');
await ref.putFile(imageFile);
final url = await ref.getDownloadURL();
await FirebaseFirestore.instance
.collection('users')
.doc(authResult.user!.uid)
.set({
'username': username,
'email': email,
'image_url': url,
});
}
} on FirebaseAuthException catch (error) {
var message = 'An error occurred, please check your credentials!';
if (error.message != null) {
message = error.message!;
}
ScaffoldMessenger.of(ctx).showSnackBar(SnackBar(content: Text(message)));
setState(() {
_isLoading = false;
});
}
}
#override
void initState() {
super.initState();
controller =
AnimationController (
duration: Duration(seconds: 1),
vsync: this,
);
animation = ColorTween(begin: Colors.transparent, end: Colors.white.withOpacity(0.5)).animate(controller);
controller.forward();
controller.addListener(() {
setState(() {
});
});
}
#override
Widget build(BuildContext context) {
FirebaseAuth.instance
.authStateChanges()
.listen((User? user) {
if (user == null) {
print('User is currently signed out!');
} else {
_completeLogin();
print('1');
}
});
return Container(
decoration: BoxDecoration(
image: DecorationImage(
image: AssetImage("images/bar1.jpg"),
fit: BoxFit.fill,
)
),
child: Scaffold(
backgroundColor: Colors.white.withOpacity(0.5),
body: Container(
child: Center(
child: SingleChildScrollView(
child: Column(
children: <Widget>[
Image.asset('assets/images/logo.png'),
AuthForm(
_submitAuthForm,
_isLoading,
),
],
),
),
),
),
),
);
}
}
and here is my auth form
FocusNode myFocusNode = FocusNode();
class AuthForm extends StatefulWidget {
const AuthForm(this.submitFn, this.isLoading, {Key? key}) : super(key: key);
final bool isLoading;
final void Function(
String email,
String userName,
String password,
File image,
bool isLogin,
BuildContext ctx,
) submitFn;
#override
_AuthFormState createState() => _AuthFormState();
}
class _AuthFormState extends State<AuthForm> {
final _formKey = GlobalKey<FormState>();
var _isLogin = true;
String _userEmail = '';
String _userName = '';
String _userPassword = '';
File _userImageFile = File('');
void _pickedImage(File image) {
_userImageFile = image;
}
void _trySubmit() {
final isValid = _formKey.currentState!.validate();
FocusScope.of(context).unfocus();
if (_userImageFile.path.isEmpty && !_isLogin) {
ScaffoldMessenger.of(context).showSnackBar(
const SnackBar(
content: Text('Please pick an image'),
),
);
return;
}
if (isValid) {
_formKey.currentState!.save();
widget.submitFn(
_userEmail.trim(),
_userName.trim(),
_userPassword.trim(),
_userImageFile,
_isLogin,
context,
);
}
}
#override
Widget build(BuildContext context) {
return Center(
child: Card(
margin: const EdgeInsets.symmetric(horizontal: 30, vertical: 20),
child: Padding(
padding: const EdgeInsets.symmetric(horizontal: 20, vertical: 16),
child: AnimatedContainer(
duration: const Duration(milliseconds: 350),
curve: Curves.easeIn,
constraints: BoxConstraints(
minHeight: _isLogin ? 224 : 390,
maxHeight: _isLogin ? 268 : 456,
),
child: Form(
key: _formKey,
child: SingleChildScrollView(
child: Column(
mainAxisSize: MainAxisSize.min,
children: <Widget>[
if (!_isLogin)
UserImagePicker(_pickedImage),
TextFormField(
cursorColor: Colors.red,
key: const ValueKey('email'),
autocorrect: false,
textCapitalization: TextCapitalization.none,
keyboardType: TextInputType.emailAddress,
decoration: InputDecoration(
labelText: 'Email address',
),
validator: (val) {
if (EmailValidator.validate(val!) == false) {
return 'Please enter a valid email address.';
}
return null;
},
onSaved: (val) {
_userEmail = val!;
},
),
if (!_isLogin)
TextFormField(
cursorColor: Colors.red,
key: const ValueKey('username'),
decoration: const InputDecoration(
labelText: 'Username',
),
validator: (val) {
if (val!.isEmpty || val.length < 4) {
return 'Username must be at least 4 characters.';
}
return null;
},
onSaved: (val) {
_userName = val!;
},
),
TextFormField(
cursorColor: Colors.red,
key: const ValueKey('password'),
decoration: const InputDecoration(
labelText: 'Password',
),
obscureText: true,
validator: (val) {
if (val!.isEmpty || val.length < 6) {
return 'Check your password, it must be 6 character or longer.';
}
return null;
},
onSaved: (val) {
_userPassword = val!;
},
),
const SizedBox(height: 12),
widget.isLoading
? const CircularProgressIndicator()
: ElevatedButton(
style: ButtonStyle(
backgroundColor: MaterialStateProperty.all(Colors.red),
),
child: Text(_isLogin ? 'Log in' : 'Sign up'),
onPressed: _trySubmit,
),
TextButton(
child: Text(_isLogin
? 'Create new account'
: 'I already have an account'),
onPressed: () {
setState(() {
_isLogin = !_isLogin;
});
},
),
if (_isLogin)
TextButton(
child: Text(
'Forgot Password?'
),
onPressed: () {
Navigator.pushNamed(context, ForgotPassword.id);
},
),
],
),
),
),
),
),
),
);
}
}
answered it my self by writing to a category in firebase then used the below code to pull it out later
import 'package:flutter/material.dart';
// Import the firebase_core and cloud_firestore plugin
import 'package:firebase_core/firebase_core.dart';
import 'package:cloud_firestore/cloud_firestore.dart';
class AddUser extends StatelessWidget {
final String fullName;
final String company;
final int age;
AddUser(this.fullName, this.company, this.age);
#override
Widget build(BuildContext context) {
// Create a CollectionReference called users that references the firestore collection
CollectionReference users = FirebaseFirestore.instance.collection('users');
Future<void> addUser() {
// Call the user's CollectionReference to add a new user
return users
.add({
'full_name': fullName, // John Doe
'company': company, // Stokes and Sons
'age': age // 42
})
.then((value) => print("User Added"))
.catchError((error) => print("Failed to add user: $error"));
}
return TextButton(
onPressed: addUser,
child: Text(
"Add User",
),
);
}
}
and this code to query it
class GetUserName extends StatelessWidget {
final String documentId;
GetUserName(this.documentId);
#override
Widget build(BuildContext context) {
CollectionReference users = FirebaseFirestore.instance.collection('users');
return FutureBuilder<DocumentSnapshot>(
future: users.doc(documentId).get(),
builder:
(BuildContext context, AsyncSnapshot<DocumentSnapshot> snapshot) {
if (snapshot.hasError) {
return Text("Something went wrong");
}
if (snapshot.hasData && !snapshot.data!.exists) {
return Text("Document does not exist");
}
if (snapshot.connectionState == ConnectionState.done) {
Map<String, dynamic> data = snapshot.data!.data() as Map<String, dynamic>;
return Text("Full Name: ${data['full_name']} ${data['last_name']}");
}
return Text("loading");
},
);
}
}
You can pass them as a constructor
Example
class UserDetail extends StatelessWidget {
final File image;
final String display;
UserDetail({Key key, required this.image, required this.display}) : super(key: key);
#override
Widget build(BuildContext context) {
return Container(child:Row(
children: <Widget>[
Image.file(image: File(image))),
Text(display),
], ),);
}
}
You can read Passing data between screens in Flutter
For more info.

Flutter : Autorun a function whenever a screen is opened

I want to run a function to check Firestore data everytime a screen is loaded.
Here is my code :
class PlaceTile extends StatefulWidget {
//String flag='inactive';
final Place place;
PlaceTile({ this.place });
#override
_PlaceTileState createState() => _PlaceTileState(place);
}
class _PlaceTileState extends State<PlaceTile> {
final Place place;
_PlaceTileState(this.place);
String flag = 'inactive';
void getUserById(String id) {
DatabaseService().placesCollection.document(id).get().then((DocumentSnapshot doc) {
print(doc.data);
});
}
checkUserStatus() async {
final FirebaseAuth auth = FirebaseAuth.instance;
final FirebaseUser user = await auth.currentUser();
String uid = user.uid;
UserDatabaseService().userCollection.getDocuments().then((QuerySnapshot snapshot) {
snapshot.documents.forEach((DocumentSnapshot doc) {
if(doc.documentID == uid)
{
if(doc.data['status']=='true')
{
setState(() {
flag = 'active';
});
}
else
{
setState(() {
flag = 'inactive';
});
}
}
});
});
return flag;
}
void showQueueDetailsPanel() {
showModalBottomSheet(context: context, builder: (context) {
return Container(
padding: EdgeInsets.symmetric(vertical: 20.0, horizontal: 60.0),
child: QueueDetails(value: place.name),
);
});
}
String value;
#override
initState() {
super.initState();
checkUserStatus();
}
Widget build(BuildContext context) {
return Padding(
padding: EdgeInsets.only(top: 8.0),
child: Card(
margin: EdgeInsets.fromLTRB(20.0, 6.0, 20.0, 0.0),
child: ListTile(
isThreeLine: true,
leading: CircleAvatar(
radius: 25.0,
backgroundColor: Colors.white,
),
title: Text(place.name),
subtitle: Column(
crossAxisAlignment: CrossAxisAlignment.start,
children: <Widget>[
//Text("People "+place.totalPeople.toString()),
Text(""),
Text("Token "+place.tokenAvailable.toString()),
],
),
trailing: FlatButton.icon(
icon: Icon(Icons.add_box_rounded),
label: Text('Join'),
onPressed: checkUserStatus() =='inactive' ? showQueueDetailsPanel : null,
),
),
)
);
}
}
The code in its current state doesn't perform the way I expect. It s a fallacy actually. Once flag is set to active, the Join buttons get disabled and for them to get re-enabled they need to be pressed for condition to be checked. But that's not possible since the buttons can't be pressed as they are disabled.
I want to run checkUserStatus() everytime this page with PlaceTile is loaded. How can I achieve that? A code snippet would be helpful.
Add your function to initState:
#override
void initState() {
super.initState();
checkUserStatus();
}
Widget build(BuildContext context) {
return FutureBuilder(
future: futurePackageListModel,
builder: (BuildContext context,
AsyncSnapshot<List<Model>> snapshot) {
if (snapshot.hasData) {
return YourWidget();
} else if (snapshot.hasError) {
return ApiStatusFail();
} else {
return Center(child: CircularProgressIndicator());
}
},
);
}

How to solve SnackBar did not work and black screen in flutter after add StreamBuilder

I am doing login and sign up using firebase. I have two error. First is the error message from firebase that did not show at the snack bar. The second is after I add StreamBuilder my apps become black screen.
Does anyone know how to solve this question? Thanks in advance.
Here is the code:
Main.dart
void main() async {
WidgetsFlutterBinding.ensureInitialized();
await Firebase.initializeApp();
runApp(MyApp());
}
class MyApp extends StatelessWidget {
// This widget is the root of your application.
#override
Widget build(BuildContext context) {
return MaterialApp(
title: 'Flutter Demo',
theme: ThemeData(
primarySwatch: Colors.blue,
),
home: StreamBuilder(
stream: FirebaseAuth.instance.authStateChanges(),
builder: (ctx, userSnapshot) {
if (userSnapshot.hasData) {
return HomePage();
}
return AuthScreen();
}),
);
}
}
AuthScreen.dart
class AuthScreen extends StatefulWidget {
#override
_AuthScreenState createState() => _AuthScreenState();
}
class _AuthScreenState extends State<AuthScreen> {
final _auth = FirebaseAuth.instance;
var _isLoading = false;
void _submitAuthForm(
String email,
String password,
String username,
bool isLogin,
BuildContext ctx,
) async {
UserCredential authResult;
try {
setState(() {
_isLoading = true;
});
if (isLogin) {
authResult = await _auth.signInWithEmailAndPassword(
email: email,
password: password,
);
} else {
authResult = await _auth.createUserWithEmailAndPassword(
email: email,
password: password,
);
await FirebaseFirestore.instance
.collection('users')
.doc(authResult.user.uid)
.set({
'username': username,
'email': email,
});
}
} on PlatformException catch (err) {
var message = 'An error occurred, pelase check your credentials!';
if (err.message != null) {
message = err.message;
}
ScaffoldMessenger.of(ctx).showSnackBar(
SnackBar(
content: Text(message),
backgroundColor: Theme.of(ctx).errorColor,
),
);
setState(() {
_isLoading = false;
});
} catch (err) {
print(err);
setState(() {
_isLoading = false;
});
}
}
#override
Widget build(BuildContext context) {
return Scaffold(
backgroundColor: Theme.of(context).primaryColor,
body: AuthForm(
_submitAuthForm,
_isLoading,
),
);
}
}
Auth_form.dart
class AuthForm extends StatefulWidget {
AuthForm(
this.submitFn,
this.isLoading,
);
final bool isLoading;
final void Function(
String email,
String password,
String userName,
bool isLogin,
BuildContext ctx,
) submitFn;
#override
_AuthFormState createState() => _AuthFormState();
}
class _AuthFormState extends State<AuthForm> {
final _formKey = GlobalKey<FormState>();
var _isLogin = true;
var _userEmail = '';
var _userName = '';
var _userPassword = '';
void _trySubmit() {
final isValid = _formKey.currentState.validate();
FocusScope.of(context).unfocus();
if (isValid) {
_formKey.currentState.save();
widget.submitFn(_userEmail.trim(), _userPassword.trim(), _userName.trim(),
_isLogin, context);
}
}
#override
Widget build(BuildContext context) {
return Center(
child: Card(
margin: EdgeInsets.all(20),
child: SingleChildScrollView(
child: Padding(
padding: EdgeInsets.all(16),
child: Form(
key: _formKey,
child: Column(
mainAxisSize: MainAxisSize.min,
children: <Widget>[
TextFormField(
key: ValueKey('email'),
validator: (value) {
if (value.isEmpty || !value.contains('#')) {
return 'Please enter a valid email address.';
}
return null;
},
keyboardType: TextInputType.emailAddress,
decoration: InputDecoration(
labelText: 'Email address',
),
onSaved: (value) {
_userEmail = value;
},
),
if (!_isLogin)
TextFormField(
key: ValueKey('username'),
validator: (value) {
if (value.isEmpty || value.length < 4) {
return 'Please enter at least 4 characters';
}
return null;
},
decoration: InputDecoration(labelText: 'Username'),
onSaved: (value) {
_userName = value;
},
),
TextFormField(
key: ValueKey('password'),
validator: (value) {
if (value.isEmpty || value.length < 7) {
return 'Password must be at least 7 characters long.';
}
return null;
},
decoration: InputDecoration(labelText: 'Password'),
obscureText: true,
onSaved: (value) {
_userPassword = value;
},
),
SizedBox(height: 12),
if (widget.isLoading) CircularProgressIndicator(),
if (!widget.isLoading)
RaisedButton(
child: Text(_isLogin ? 'Login' : 'Signup'),
onPressed: _trySubmit,
),
if (!widget.isLoading)
FlatButton(
textColor: Theme.of(context).primaryColor,
child: Text(_isLogin
? 'Create new account'
: 'I already have an account'),
onPressed: () {
setState(() {
_isLogin = !_isLogin;
});
},
)
],
),
),
),
),
),
);
}
}
home.dart
class HomePage extends StatefulWidget {
#override
_HomePageState createState() => _HomePageState();
}
class _HomePageState extends State<HomePage> {
#override
Widget build(BuildContext context) {
return Container();
}
}
To show a SnackBar first define a key:
final key = GlobalKey<ScaffoldMessengerState>();
Then, add a ScaffoldMessenger to your widget tree:
ScaffoldMessenger(
key: key, // assign the key property to your previously created key
child: Scaffold(...),
)
Now you can show the SnackBar:
key.currentState.showSnackBar(SnackBar(...))
Please add code for your home page, so we can inspect it and see why it shows a black screen, you probably forgot to wrap it in a Scaffold. You should return a Scaffold in the home page and the black screen will go away.

null an the Display in Flutter but with the right Value in Future

I am pretty new in Flutter and i can not solve this problem.
i have a really simple application. it is just a login with google an a User is created in Firebase, that user have a counter and a button this button increased the counter (int _user.count++).
Then my problem: after the login in the next window, it is not visible the count variable until I click "plus" button. the variable is right and the query with fireStore work great I got the variable but if I do not click the button I got an the display in the place of the variable "null".
Thanks a lot for you Help and Time, I really hope that you can help me. maybe it is a tiny problem I have not found information about it but it is happen when some start to learn.
MyDAO: Hier the Method Future it is the responsable of make the Query to FireStore.
import 'package:cloud_firestore/cloud_firestore.dart';
import 'package:gauth/user_model.dart';
import 'package:rxdart/rxdart.dart';
final UserDAO userDAO = UserDAO();
class UserDAO {
final Firestore _db = Firestore.instance;
PublishSubject loading;
Observable<Future<QuerySnapshot>> profile;
void updateData(UserModel user) async {
DocumentReference documentReference =
_db.collection("users").document(user.uid);
return documentReference.setData({
"uid": user.uid,
"userName": user.name,
"email": user.email,
"photoUrl": user.photoUrl,
"count": user.count,
"lastIn": DateTime.now()
}, merge: true);
}
Future<QuerySnapshot> readDateFutur(String email) async {
// loading.add(true);
QuerySnapshot querySnapshot = await (_db
.collection("users")
.where("email", isEqualTo: email)
.getDocuments());
// loading.add(false);
return querySnapshot;
}
}
hier in the method "void initState()" I hold the variable _user.couner, that works.
class PlusCounter extends StatefulWidget {
UserModel user;
PlusCounter(this.user);
#override
_PlusCounterState createState() => _PlusCounterState();
}
class _PlusCounterState extends State<PlusCounter> {
UserModel _user;
PublishSubject loading;
#override
void initState() {
// TODO: implement initState
super.initState();
setState(() {
_user = widget.user;
//loading.add(false);
userDAO.readDateFutur(_user.email).then((QuerySnapshot docs) {
if (docs.documents.isNotEmpty) {
print("::::::::::NOESTOY VACIO:::::::::::::::::::::");
print(docs.documents.last.data["count"]);
if (docs.documents.last.data["count"] != null) {
_user.count = docs.documents.last.data["count"];
} else {
_user.count = 0;
}
} else {
print(":::::::::::ESTOY VACIO:::::::::::::::::");
_user.count = 0;
}
});
});
}
void _plus() {
setState(() {
_user.count++;
});
}
#override
Widget build(BuildContext context) {
return Column(
children: <Widget>[
Text("Cuantas veces te has \n lavado las manos:"),
Text("${_user.count}"),
MaterialButton(
onPressed: () {
_plus();
},
child: Text("Plus"),
textColor: Colors.white,
color: Colors.blue,
),
MaterialButton(
onPressed: () => userDAO.updateData(_user),
child: Text("Guardar"),
textColor: Colors.white,
color: Colors.blue,
),
],
);
}
}
WelcomePage code is this one.
class userDataWelcome extends StatelessWidget {
UserModel _userModel;
userDataWelcome(this._userModel);
#override
Widget build(BuildContext context) {
return Scaffold(
appBar: AppBar(
title: Text("Welcome"),
),
body: Center(
child: Column(
children: <Widget>[
Center(
child: Container(
height: 100.0,
width: 100.0,
decoration: BoxDecoration(
shape: BoxShape.circle,
image: DecorationImage(
image: NetworkImage(_userModel.photoUrl),
),
),
),
),
Text("${_userModel.name}"),
PlusCounter(_userModel),
MaterialButton(
onPressed: () => authService.SingOut(),
child: Text("Logout"),
textColor: Colors.white,
color: Colors.deepOrange,
)
],
),
),
);
}
}
Then I really do not why I need to click "plus" button before I can see the Value of _user.count, because I just see null in otherwise. just again I want to say Thanks for your help.
Try wrapping this line in initStat() _user.count = docs.documents.last.data["count"]; in setState((){}); like this
setState((){
_user.count = docs.documents.last.data["count"];
)};

Another exception was thrown: NoSuchMethodError: The setter "wastedate=" was called on null

I am received the following error on my form, I am trying to submit a form page to a Firebase database. The error is "Another exception was thrown: NoSuchMethodError: The setter 'wastedate=' was called on null." I am thinking it must relate to the _saveWaste function as the print shows "saveWaste called" but not "form saved".
import 'dart:io';
import 'package:cloud_firestore/cloud_firestore.dart';
import 'package:firebase_storage/firebase_storage.dart';
import 'package:flutter/material.dart';
import 'package:image_picker/image_picker.dart';
import 'dart:async';
import 'package:wasteagram/model/waste.dart';
import 'package:path/path.dart' as path;
import 'package:uuid/uuid.dart';
class CameraScreen extends StatefulWidget {
final bool isUpdating;
CameraScreen({#required this.isUpdating});
#override
_CameraScreenState createState() => _CameraScreenState();
}
class _CameraScreenState extends State<CameraScreen> {
final GlobalKey<FormState> _formKey = GlobalKey<FormState>();
Waste _currentWaste;
Widget _buildDateField() {
return Form(
key: _formKey,
child: TextFormField(
decoration: InputDecoration(labelText: 'Date'),
keyboardType: TextInputType.text,
style: TextStyle(fontSize: 20),
validator: (String value) {
if(value.isEmpty){
return 'Date required';
}
if(value.length < 3 || value.length > 20) {
return 'Name must be more than 3 or less than 20';
}
return null;
},
onSaved: (String value) {
_currentWaste.wastedate = value;
},
),
);
}
Widget _buildWasteNumber() {
return Form(
child: TextFormField(
decoration: InputDecoration(labelText: 'Number'),
keyboardType: TextInputType.number,
style: TextStyle(fontSize: 20),
validator: (value) {
if(value.isEmpty){
return 'Number required';
}
return null;
},
onSaved: (String value) {
String wasteNum = _currentWaste.wastenumber.toString();
wasteNum = value;
},
),
);
}
_saveWaste(context) {
print("saveWaste Called");
if(!_formKey.currentState.validate()) {
return "FALSE";
}
_formKey.currentState.save();
print("form saved");
uploadItems(_currentWaste, widget.isUpdating, image);
print("date ${_currentWaste.wastedate}");
print("number ${_currentWaste.wastenumber.toString()}");
print("_imageFile ${image.toString()}");
}
File image;
void getImage() async {
image = await ImagePicker.pickImage(source: ImageSource.gallery);
setState( () {});
}
#override
Widget build(BuildContext context) {
if (image == null) {
return Scaffold(
appBar: AppBar(
title: Text('Wasteagram')
),
body: Center(
child: RaisedButton(
child: Text('Select Photo'),
onPressed: () {
getImage();
},
),
),
);
} else {
return Scaffold(
appBar: AppBar(
title: Text('Wasteagram')
),
body: Column(
mainAxisAlignment: MainAxisAlignment.center,
children: [
Image.file(image),
SizedBox(height: 40),
RaisedButton(
child: Text('Select Photo'),
onPressed: () {
getImage();
}
),
_buildDateField(),
_buildWasteNumber(),
],
),
floatingActionButton: FloatingActionButton(
onPressed: () => _saveWaste(context),
child: Icon(Icons.save),
foregroundColor: Colors.white,
),
);
}
}
}
uploadItems(Waste waste, bool isUpdating, File localFile) async {
if (localFile != null) {
print("uploading image");
var fileExtension = path.extension(localFile.path);
print(fileExtension);
var uuid = Uuid().v4();
final StorageReference firebaseStorageRef =
FirebaseStorage.instance.ref().child('/$uuid$fileExtension');
await firebaseStorageRef.putFile(localFile).onComplete.catchError(
(onError){
print(onError);
return false;
}
);
String url = await firebaseStorageRef.getDownloadURL();
print("download url: $url");
_uploadWaste(waste, isUpdating, imageUrl: url);
} else {
print("skipping image upload");
_uploadWaste(waste, isUpdating);
}
}
_uploadWaste(Waste waste, bool isUpdating, {String imageUrl}) async {
CollectionReference wasteRef = Firestore.instance.collection('todolist');
if(imageUrl != null) {
waste.image = imageUrl;
}
if(isUpdating) {
waste.updatedAt = Timestamp.now();
await wasteRef.document(waste.id).updateData(waste.toMap());
print("updated waste with id: ${waste.id}");
} else {
DocumentReference documentRef = await wasteRef.add(waste.toMap());
waste.id = documentRef.documentID;
print("uploaded waste successfully: ${waste.toString()}");
await documentRef.setData(waste.toMap(), merge: true);
}
}
You must init _currentWaste , it is null
Please change from
Waste _currentWaste;
To
Waste _currentWaste = Waste();

Resources