Related
So I made a CRUD app with Firebase Firestore in Flutter. I have this error where it says
Exception caught by gesture
═══════════════════════
a document path must be a non-empty string
'package:cloud_firestore/src/collection_reference.dart':
package:cloud_firestore/src/collection_reference.dart:1
Failed assertion: line 116 pos 14: 'path.isNotEmpty'
I build this app with various tutorial videos in Youtube. I can make the Create, Read, and Delete features but I face this problem with Update features. Here's the code ...or check this Github https://github.com/rayhanyovi/Dapurku
import 'package:cloud_firestore/cloud_firestore.dart';
import 'package:firebase_core/firebase_core.dart';
import 'package:flutter/foundation.dart';
import 'package:flutter/material.dart';
import 'package:flutter/services.dart';
import 'package:intl/intl.dart';
import 'package:dapurkuu/warna.dart';
import 'package:dapurkuu/widget.dart';
Future main() async {
WidgetsFlutterBinding.ensureInitialized();
await Firebase.initializeApp();
runApp(MyApp());
}
//=====================================
const Color Red = Color(0xFFDA4040);
const Color Blue = Color(0xFF5F52EE);
const Color Black = Color(0xFF3A3A3A);
const Color Grey = Color(0xFF717171);
const Color BGColor = Color(0xFFEEEFF5);
final controllerName = TextEditingController();
final controllerAge = TextEditingController();
final controllerBirthday = TextEditingController();
final updateName = TextEditingController();
final updateAge = TextEditingController();
final updateBirthday = TextEditingController();
//=====================================
class User {
String id;
final String name;
final int age;
final DateTime birthday;
User({
this.id = '',
required this.name,
required this.age,
required this.birthday,
});
Map<String, dynamic> toJson() => {
'id': id,
'name': name,
'age': age,
'birthday': birthday,
};
static User fromJson(Map<String, dynamic> json) => User(
id: json['id'],
name: json['name'],
age: json['age'],
birthday: (json['birthday'] as Timestamp).toDate(),
);
}
//=====================================
class MyApp extends StatelessWidget {
const MyApp({Key? key}) : super(key: key);
#override
Widget build(BuildContext context) {
SystemChrome.setSystemUIOverlayStyle(
SystemUiOverlayStyle(statusBarColor: Colors.transparent));
return MaterialApp(
debugShowCheckedModeBanner: false,
title: "Test",
home: Home(),
);
}
}
//=====================================
class Home extends StatefulWidget {
#override
_HomeState createState() => _HomeState();
}
class _HomeState extends State<Home> {
final CollectionReference _users =
FirebaseFirestore.instance.collection('users');
#override
Widget build(BuildContext context) {
Future createUser(User user) async {
final docUser = FirebaseFirestore.instance.collection('users').doc();
user.id = docUser.id;
final json = user.toJson();
await docUser.set(json);
Future updateUser(User user) async {
final docUser = FirebaseFirestore.instance.collection('users').doc();
user.id = docUser.id;
final json = user.toJson();
await docUser.update(json);
}
}
Widget buildUser(User user) {
return Container(
margin: EdgeInsets.only(
right: 20,
left: 20,
bottom: 15,
),
child: Material(
child: ListTile(
onTap: () {
print("card");
},
contentPadding:
EdgeInsets.only(top: 10, bottom: 10, left: 20, right: 15),
shape:
RoundedRectangleBorder(borderRadius: BorderRadius.circular(20)),
tileColor: Colors.white,
title: Padding(
padding: const EdgeInsets.only(bottom: 5),
child: Text(
user.name,
style: TextStyle(
fontSize: 18,
fontWeight: FontWeight.w600,
),
),
),
subtitle: Column(
crossAxisAlignment: CrossAxisAlignment.start,
children: [
Text(
'Jumlah: ${user.age}',
),
Text(
'Kadaluarsa: ${DateFormat('dd MMMM yyyy').format(user.birthday)}')
],
),
trailing: Wrap(spacing: 0, children: [
IconButton(
icon: Icon(Icons.edit),
iconSize: 24,
color: Colors.black,
onPressed: () async {
await Edit(context, createUser);
},
),
IconButton(
icon: Icon(Icons.delete),
iconSize: 24,
color: Colors.red,
onPressed: () {
final docUser = FirebaseFirestore.instance
.collection('users')
.doc(user.id);
docUser.delete();
},
),
]),
),
),
);
}
return Scaffold(
backgroundColor: BGColor,
appBar: _AppBar(),
body: Column(
children: [
/* JUDUL */
Column(
children: [
Container(
margin: EdgeInsets.only(left: 20),
alignment: Alignment.centerLeft,
child: SearchBox()),
Container(
margin: EdgeInsets.only(left: 20),
alignment: Alignment.centerLeft,
child: Text(
'Bahan Dapurmu',
style: TextStyle(
fontSize: 28,
fontWeight: FontWeight.bold,
color: Black,
),
),
)
],
),
/* STREAM BUILDER */
StreamBuilder(
stream: readUsers(),
builder: (context, snapshot) {
if (snapshot.hasData) {
final users = snapshot.data!;
return Expanded(
child: ListView(
scrollDirection: Axis.vertical,
shrinkWrap: true,
children: users.map(buildUser).toList(),
),
);
} else if (snapshot.hasError) {
return Container(
child: Text("data kosong"),
);
} else {
return Center(
child: CircularProgressIndicator(),
);
}
}),
],
),
floatingActionButton: FloatingActionButton(
onPressed: () async {
await Create(context, createUser);
},
child: Icon(Icons.add),
),
);
}
Edit(BuildContext context, Future<dynamic> updateUser(User user)) async {
showDialog(
context: context,
builder: (BuildContext context) {
return AlertDialog(
title: Text("Tambahkan bahan"),
content: Column(
children: [
TextField(
decoration: const InputDecoration(
labelText: 'Nama',
),
controller: updateName,
),
TextField(
decoration: const InputDecoration(
labelText: 'Umur',
),
controller: updateAge,
keyboardType: TextInputType.number,
),
TextField(
controller: updateBirthday,
//editing controller of this TextField
decoration: InputDecoration(
labelText: "Enter Date" //label text of field
),
readOnly: true,
//set it true, so that user will not able to edit text
onTap: () async {
DateTime? pickedDate = await showDatePicker(
context: context,
initialDate: DateTime.now(),
firstDate: DateTime(1950),
//DateTime.now() - not to allow to choose before today.
lastDate: DateTime(2100));
if (pickedDate != null) {
print(
pickedDate);
//pickedDate output format => 2021-03-10 00:00:00.000
//formatted date output using intl package => 2021-03-16
setState(() {
updateBirthday.text = pickedDate
.toString(); //set output date to TextField value.
});
} else {}
},
),
],
),
actions: <Widget>[
MaterialButton(
elevation: 5.0,
child: Text("Ubah Data"),
onPressed: () {
final user = User(
name: updateName.text,
age: int.parse(updateAge.text),
birthday: DateTime.parse(updateBirthday.text),
);
final docUser = FirebaseFirestore.instance
.collection('users')
.doc(user.id);
updateUser(user);
}),
],
);
});
}
Create(BuildContext context, Future<dynamic> createUser(User user)) async {
showDialog(
context: context,
builder: (BuildContext context) {
return AlertDialog(
title: Text("Tambahkan bahan"),
content: Column(
children: [
TextField(
decoration: const InputDecoration(
labelText: 'Nama',
),
controller: controllerName,
),
TextField(
decoration: const InputDecoration(
labelText: 'Umur',
),
controller: controllerAge,
keyboardType: TextInputType.number,
),
TextField(
controller: controllerBirthday,
//editing controller of this TextField
decoration: InputDecoration(
labelText: "Enter Date" //label text of field
),
readOnly: true,
//set it true, so that user will not able to edit text
onTap: () async {
DateTime? pickedDate = await showDatePicker(
context: context,
initialDate: DateTime.now(),
firstDate: DateTime(1950),
//DateTime.now() - not to allow to choose before today.
lastDate: DateTime(2100));
if (pickedDate != null) {
print(
pickedDate);
//pickedDate output format => 2021-03-10 00:00:00.000
//formatted date output using intl package => 2021-03-16
setState(() {
controllerBirthday.text = pickedDate
.toString(); //set output date to TextField value.
});
} else {}
},
),
],
),
actions: <Widget>[
MaterialButton(
elevation: 5.0,
child: Text("Tambahkan"),
onPressed: () {
final user = User(
name: controllerName.text,
age: int.parse(controllerAge.text),
birthday: DateTime.parse(controllerBirthday.text),
);
createUser(user);
}),
],
);
});
}
Stream<List<User>> readUsers() => FirebaseFirestore.instance
.collection('users')
.snapshots()
.map((snapshot) =>
snapshot.docs.map((doc) => User.fromJson(doc.data())).toList());
}
//=====================================
AppBar _AppBar() {
return AppBar(
elevation: 0,
backgroundColor: BGColor,
title: Center(
child: Text(
"Dapurku",
style: TextStyle(
fontSize: 20,
fontWeight: FontWeight.bold,
color: Black,
),
),
),
);
}
//=====================================
class UpdateButton extends StatelessWidget {
const UpdateButton({Key? key}) : super(key: key);
#override
Widget build(BuildContext context) {
return Container(
child: IconButton(
icon: Icon(Icons.edit),
iconSize: 24,
color: Colors.black,
onPressed: () {},
),
);
}
}
//=====================================
class SearchBox extends StatelessWidget {
const SearchBox({
Key? key,
}) : super(key: key);
#override
Widget build(BuildContext context) {
return Container(
padding: const EdgeInsets.only(left: 10),
child: const TextField(
decoration: InputDecoration(
contentPadding: EdgeInsets.all(0),
prefixIcon: Icon(
Icons.search,
color: Black,
size: 20,
),
prefixIconConstraints: BoxConstraints(
maxHeight: 20,
minWidth: 25,
),
border: InputBorder.none,
hintText: "Cari Bahan...",
hintStyle: TextStyle(
color: Grey,
)),
),
decoration: BoxDecoration(
color: Colors.white,
borderRadius: BorderRadius.circular(20),
),
);
}
}
Can you tell me what I did wrong or help me solve the problem? I've been looking for it anywhere and solving this problem for days. It is for my school assignment :/
Basically my app has a AuthWrapper where it either goes loginPage or homePage.
class Wrapper extends ConsumerWidget {
#override
Widget build(BuildContext context, ScopedReader watch) {
final res = watch(authControllerProvider);
if (res != null) {
return HomePage();
} else {
return LoginPage();
}
}
}
On App start, it logins fine if logged in or goes loginpage if not, but for example:
if not logged in, goes login page, and if user goes register screen and registers it doesnt login, basically after pushing to pages, the AuthWrapper doesnt work, is there a way to resolve this.
registerpage.dart
import 'package:flutter/material.dart';
import 'package:fluttertoast/fluttertoast.dart';
import 'package:font_awesome_flutter/font_awesome_flutter.dart';
import 'package:hubx/screens/HomePage/homepage.dart';
import 'package:hubx/screens/authentication/loginPage.dart';
import 'package:hubx/services/auth.dart';
import 'package:flutter_riverpod/flutter_riverpod.dart';
import 'package:hubx/shared/theme/theme_colors.dart';
import 'package:hubx/shared/widgets/loading_widget.dart';
import 'package:hubx/shared/widgets/theme_widgets.dart';
import 'package:hubx/shared/validator.dart';
import 'package:theme_provider/theme_provider.dart';
class RegisterPage extends ConsumerWidget {
#override
Widget build(BuildContext context, ScopedReader watch) {
final GlobalKey<FormState> _registerFormKey = GlobalKey<FormState>();
final TextEditingController _displayNameController =
TextEditingController();
final TextEditingController _emailController = TextEditingController();
final TextEditingController _passwordController = TextEditingController();
final FocusNode _displayNameFocusNode = FocusNode();
final FocusNode _emailFocusNode = FocusNode();
final FocusNode _passwordFocusNode = FocusNode();
return GestureDetector(
onTap: () {
_displayNameFocusNode.unfocus();
_emailFocusNode.unfocus();
_passwordFocusNode.unfocus();
},
child: Scaffold(
appBar: SAppBar(context, 'Register'),
body: SafeArea(
child: Scrollbar(
child: Center(
child: SingleChildScrollView(
padding: EdgeInsets.all(16),
child: Column(
mainAxisSize: MainAxisSize.min,
children: [
Card(
color:
(ThemeProvider.controllerOf(context).currentThemeId ==
'dark')
? MyThemesColor.darkBG
: MyThemesColor.lightBG,
shape: RoundedRectangleBorder(
borderRadius: BorderRadius.all(Radius.circular(16))),
child: Form(
key: _registerFormKey,
child: Padding(
padding: const EdgeInsets.all(16.0),
child: Column(
mainAxisSize: MainAxisSize.min,
children: [
Column(
children: [
TextFormField(
controller: _displayNameController,
focusNode: _displayNameFocusNode,
keyboardType: TextInputType.text,
textInputAction: TextInputAction.next,
autovalidateMode:
AutovalidateMode.onUserInteraction,
validator: (value) =>
Validator.validateField(
value: value!,
fieldName: 'Display Name'),
decoration: InputDecoration(
labelText: 'Display Name',
prefixIcon: Icon(
Icons.format_color_text_outlined)),
),
SizedBox(height: 8),
TextFormField(
controller: _emailController,
focusNode: _emailFocusNode,
keyboardType: TextInputType.emailAddress,
textInputAction: TextInputAction.next,
autovalidateMode:
AutovalidateMode.onUserInteraction,
validator: (value) =>
Validator.validateEmail(email: value!),
decoration: InputDecoration(
labelText: 'Email',
prefixIcon: Icon(Icons.email_outlined)),
),
SizedBox(height: 8),
TextFormField(
controller: _passwordController,
focusNode: _passwordFocusNode,
keyboardType: TextInputType.text,
textInputAction: TextInputAction.go,
autovalidateMode:
AutovalidateMode.onUserInteraction,
validator: (value) =>
Validator.validatePassword(
password: value!,
),
obscureText: true,
decoration: InputDecoration(
labelText: 'Password',
prefixIcon: Icon(Icons.password_outlined),
),
),
SizedBox(height: 32),
],
),
Consumer(
builder: (context, ref, child) {
final authService = ref(authServiceProvider);
if (!authService.isLoading) {
return Container(
width: double.maxFinite,
child: ElevatedButton.icon(
onPressed: () async {
_displayNameFocusNode.unfocus();
_emailFocusNode.unfocus();
_passwordFocusNode.unfocus();
if (_registerFormKey.currentState!
.validate()) {
final authService = context
.read(authServiceProvider);
await authService
.registerWithEmailAndPassword(
_emailController.text,
_passwordController.text,
_displayNameController.text,
'',
)
.then((value) {
if (value != 'Success') {
Fluttertoast.showToast(
msg: value,
);
}
});
}
},
icon: FaIcon(FontAwesomeIcons.userEdit),
label: Padding(
padding: const EdgeInsets.all(16.0),
child: Text(
'REGISTER',
style: TextStyle(
fontSize: 20,
fontWeight: FontWeight.w500,
letterSpacing: 2,
),
),
),
),
);
} else {
return LoadingWidget(
loadingSize: 30,
loadingColor: MyThemesColor.theme,
title: '',
);
}
},
),
],
),
),
),
),
SizedBox(height: 16.0),
Consumer(
builder: (context, ref, child) {
final authService = ref(authServiceProvider);
if (!authService.isLoading) {
return InkWell(
onTap: () {
Navigator.of(context)
.pushReplacement(MaterialPageRoute(
builder: (context) => LoginPage(),
));
},
child: Row(
mainAxisSize: MainAxisSize.min,
children: [
Text(
'Already have an account? ',
style: TextStyle(letterSpacing: 0.5),
),
Text(
'Login',
style: TextStyle(
letterSpacing: 0.5,
color: MyThemesColor.theme,
fontWeight: FontWeight.w500,
),
),
],
),
);
}
return SizedBox.shrink();
},
),
],
),
),
),
),
),
),
);
}
}
authControllerProvider:
import 'dart:async';
import 'package:firebase_auth/firebase_auth.dart';
import 'package:flutter_riverpod/flutter_riverpod.dart';
import 'package:fluttertoast/fluttertoast.dart';
import 'package:hubx/repositories/auth_repository.dart';
final authControllerProvider = StateNotifierProvider<AuthController, User?>(
(ref) => AuthController(ref.read)..appStarted(),
);
class AuthController extends StateNotifier<User?> {
final Reader _read;
StreamSubscription<User?>? _authStateChangesSubscription;
AuthController(this._read) : super(null) {
_authStateChangesSubscription?.cancel();
_authStateChangesSubscription = _read(authRepositoryProvider)
.authStateChanges
.listen((user) => state = user);
}
#override
void dispose() {
_authStateChangesSubscription?.cancel();
super.dispose();
}
void appStarted() async {
final user = _read(authRepositoryProvider).getCurrentUser();
if (user != null) {
Fluttertoast.showToast(msg: '######### SIGNED IN');
print('######### SIGNED IN');
} else {
Fluttertoast.showToast(msg: '######### NOT SIGNED IN');
print('######### NOT SIGNED IN');
}
}
void signOut() async {
await _read(authRepositoryProvider).signOut();
}
}
You should navigate to the wrapper after registration. And then the provider will take care of where to navigate to based on authentication state.
final authService = context.read(authServiceProvider);
var value = await authService.registerWithEmailAndPassword(
_emailController.text,
_passwordController.text,
_displayNameController.text,
);
if (value != 'Success') {
Fluttertoast.showToast(
msg: value,
);
Navigator.of(context).push(MaterialPageRoute(builder: (context) => Wrapper(),));
}
I hope you all are doing well today. I have another flutter issue that I have been stuck on for the past few days now. I'm attempting to upload this data to my firestore instance, but my post button never seems to be triggering. I have attempted to print a statement from the method that it evokes, but I can't seem to get that to work either. I'm attempting to create a social media app, and any and all help would be appreciated.
My main goal is to get the post button to execute in upload.dart.
I have also included home.dart since the two classes are connected in terms of performance.
upload.dart
import 'dart:io';
import 'package:cached_network_image/cached_network_image.dart';
import 'package:firebase_storage/firebase_storage.dart';
import 'package:flutter/material.dart';
import 'package:flutter_svg/flutter_svg.dart';
import 'package:fluttermedia/models/user.dart';
import 'package:fluttermedia/pages/home.dart';
import 'package:fluttermedia/widgets/progress.dart';
import 'package:image_picker/image_picker.dart';
import 'package:path_provider/path_provider.dart';
import 'package:image/image.dart' as Im;
import 'package:uuid/uuid.dart';
class Upload extends StatefulWidget {
final User currentUser;
Upload({this.currentUser});
#override
_UploadState createState() => _UploadState();
}
class _UploadState extends State<Upload> {
TextEditingController locationController = TextEditingController();
TextEditingController captionController = TextEditingController();
File file;
bool isUploading = false;
String postId = Uuid().v4();
handleChooseFromGallery() async{
Navigator.pop(context);
File file = await ImagePicker.pickImage(source: ImageSource.gallery);
setState(() {
this.file = file;
});
}
handleTakePhoto() async {
Navigator.pop(context);
File file = await ImagePicker.pickImage(source: ImageSource.camera,maxHeight: 675,maxWidth: 960);
setState(() {
this.file = file;
});
}
selectImage(parentContext){
return showDialog(
context: parentContext,
builder: (context) {
return SimpleDialog(
title: Text("Create Post"),
children: <Widget>[
SimpleDialogOption(
child: Text("Photo With Camera"),
onPressed: handleTakePhoto,
),
SimpleDialogOption(
child: Text("Image from Gallery"),
onPressed: handleChooseFromGallery,
),
SimpleDialogOption(
child: Text("Cancel"),
onPressed: () => Navigator.pop(context),
),
],
);
}
);
}
Container buildSplashScreen(){
return Container(
color: Theme.of(context).accentColor.withOpacity(0.6),
child: Column(
mainAxisAlignment: MainAxisAlignment.center,
children: <Widget>[
SvgPicture.asset('assets/images/upload.svg',height: 260.0,),
Padding(
padding: EdgeInsets.only(top:20.0),
child: RaisedButton(
shape: RoundedRectangleBorder(
borderRadius: BorderRadius.circular(8.0),
),
child: Text(
"Upload Image",
style: TextStyle(
color: Colors.white,
fontSize: 22.0,
),
),
color: Colors.deepOrange,
onPressed: () => selectImage(context),
),
)
],
),
);
}
clearImage(){
setState(() {
file = null;
});
}
//This compresses images for firebase
compressImage() async{
final tempDir = await getTemporaryDirectory();
final path = tempDir.path;
Im.Image imageFile = Im.decodeImage(file.readAsBytesSync());
final compressedImageFile = File('$path/img_$postId.jpg')..writeAsBytesSync(Im.encodeJpg(imageFile,quality: 85));
setState(() {
file = compressedImageFile;
});
}
Future<String> uploadImage(imageFile) async{
StorageUploadTask uploadTask = storageRef.child("post_$postId.jpg").putFile(imageFile);
StorageTaskSnapshot storageSnap = await uploadTask.onComplete;
String downloadUrl = await storageSnap.ref.getDownloadURL();
return downloadUrl;
}
//upload new info to firestore that creates a new collection
createPostInFirestore({String mediaUrl, String location, String description}){
postsRef.document(widget.currentUser.id)
.collection("userPosts")
.document(postId)
.setData({
"postId": postId,
"ownerId": widget.currentUser.id,
"username": widget.currentUser.username,
"mediaUrl": mediaUrl,
"description": description,
"location": location,
"timestamp": timeStamp,
"likes":{}
});
}
//Getting the info from the caption, location and pic
handleSubmit() async{
setState(() {
isUploading = true;
});
await compressImage();
String mediaUrl = await uploadImage(file);
createPostInFirestore(
mediaUrl: mediaUrl,
location: locationController.text,
description: captionController.text,
);
captionController.clear();
locationController.clear();
setState(() {
file = null;
isUploading = false;
});
}
Scaffold buildUploadForm(){
return Scaffold(
appBar: AppBar(
backgroundColor: Colors.white70,
leading: IconButton(
icon: Icon(Icons.arrow_back,color: Colors.black,),
onPressed: clearImage,
),
title: Text(
"Caption Post",
style: TextStyle(color: Colors.black),
),
actions: <Widget>[
FlatButton(
onPressed: () => isUploading ? null : () => handleSubmit(),
child: Text(
"Post",
style: TextStyle(
color: Colors.blueAccent,
fontWeight: FontWeight.bold,
fontSize: 20.0,
),
),
)
],
),
body: ListView(
children: <Widget>[
isUploading ? linearProgress(context):Text(""),
Container(
height: 220.0,
width: MediaQuery.of(context).size.width*0.8,
child: Center(
child: AspectRatio(
aspectRatio: 16/9,
child: Container(
decoration: BoxDecoration(
image: DecorationImage(
fit: BoxFit.cover,
image: FileImage(file),
)
),
),
),
),
),
Padding(
padding: EdgeInsets.only(top:10),
),
ListTile(
leading: CircleAvatar(
backgroundImage: CachedNetworkImageProvider(widget.currentUser.photoUrl),
),
title: Container(
width: 250.0,
child: TextField(
controller: captionController,
decoration: InputDecoration(
hintText: "Write a Caption...",
border: InputBorder.none,
),
),
),
),
Divider(),
ListTile(
leading: Icon(Icons.pin_drop,color: Colors.orange,size: 35.0),
title: Container(
width: 250.0,
child: TextField(
controller: locationController,
decoration: InputDecoration(
hintText: "Where was this photo taken",
border: InputBorder.none,
),
),
),
),
Container(
width: 200.0,
height: 100.0,
alignment: Alignment.center,
child: RaisedButton.icon(
label: Text(
"Use Current Location",
style: TextStyle(color: Colors.white),
),
shape: RoundedRectangleBorder(
borderRadius: BorderRadius.circular(30.0),
),
color: Colors.blue,
onPressed: () => print("Get user location"),
icon: Icon(
Icons.my_location,
color: Colors.white,
),
),
)
],
),
);
}
#override
Widget build(BuildContext context) {
return file == null ? buildSplashScreen() : buildUploadForm();
}
}
home.dart
import 'package:cloud_firestore/cloud_firestore.dart';
import 'package:firebase_storage/firebase_storage.dart';
import 'package:flutter/cupertino.dart';
import 'package:flutter/material.dart';
import 'package:fluttermedia/models/user.dart';
import 'package:fluttermedia/pages/activity_feed.dart';
import 'package:fluttermedia/pages/create_account.dart';
import 'package:fluttermedia/pages/profile.dart';
import 'package:fluttermedia/pages/search.dart';
import 'package:fluttermedia/pages/upload.dart';
import 'package:google_sign_in/google_sign_in.dart';
final GoogleSignIn googleSignIn = GoogleSignIn();
final StorageReference storageRef = FirebaseStorage.instance.ref();
final usersRef = Firestore.instance.collection('users');
final postsRef = Firestore.instance.collection('posts');
final DateTime timeStamp = DateTime.now();
User currentUser;
class Home extends StatefulWidget {
#override
_HomeState createState() => _HomeState();
}
class _HomeState extends State<Home> {
bool isAuth = false;
PageController pageController;
int pageIndex = 0;
#override
void initState() {
super.initState();
pageController = PageController();
// Detects if user signs in
googleSignIn.onCurrentUserChanged.listen((account) {
handleSignIn(account);
}, onError: (err){
print('Error sigining in: $err');
});
//Reauthenticate user when app is opened
googleSignIn.signInSilently(suppressErrors: false)
.then((account) =>
handleSignIn(account)).catchError((err){
print('Error signing in on retry: $err');
});
}
#override
Widget build(BuildContext context) {
return isAuth ? buildAuthScreen() : buildUnAuthScreen();
}
#override
void dispose(){
pageController.dispose();
super.dispose();
}
//Helper Functions
//The sign in section of the code
handleSignIn(GoogleSignInAccount account){
if(account != null){
createUserInFirestore();
setState(() {
isAuth = true;
});
}else{
setState(() {
isAuth = false;
});
}
}
login(){
googleSignIn.signIn();
}
logout(){
googleSignIn.signOut();
}
onPageChanged(int pageIndex){
setState(() {
this.pageIndex = pageIndex;
});
}
createUserInFirestore() async{
// 1) Check if user exists in users collection in database (According to id)
final GoogleSignInAccount user = googleSignIn.currentUser;
DocumentSnapshot doc = await usersRef.document(user.id).get();
if(!doc.exists){
// 2) If the user doesn't exist, take them to create account page
final username = await Navigator.push(context, MaterialPageRoute(builder: (context) => CreateAccount()));
// 3) get username from create account, use it to make new user document in users collection
usersRef.document(user.id).setData({
"id":user.id,
"username":username,
"photoUrl": user.photoUrl,
"email":user.email,
"displayName": user.displayName,
"bio":"",
"timeStamp": timeStamp,
});
doc = await usersRef.document(user.id).get();
}
currentUser = User.fromDocument(doc);
//print(currentUser);
//print(currentUser.username);
}
onTap(int pageIndex){
//This what you would use to animate in between the different screens
pageController.animateToPage(
pageIndex,
duration: Duration(milliseconds: 300),
curve: Curves.easeInOut
);
}
//UI Code
Widget buildAuthScreen() {
return Scaffold(
body: PageView(
children: <Widget>[
//Timeline(),
RaisedButton(
child: Text('Logout'),
onPressed: logout,
),
ActivityFeed(),
Upload(currentUser: currentUser),
Search(),
Profile(),
],
controller: pageController,
onPageChanged: onPageChanged,
physics: NeverScrollableScrollPhysics(),
),
bottomNavigationBar: CupertinoTabBar(
currentIndex: pageIndex,
onTap: onTap,
activeColor: Theme.of(context).primaryColor,
items: [
BottomNavigationBarItem(icon: Icon(Icons.whatshot),),
BottomNavigationBarItem(icon: Icon(Icons.notifications_active),),
BottomNavigationBarItem(icon: Icon(Icons.photo_camera, size: 34.0,),),
BottomNavigationBarItem(icon: Icon(Icons.search),),
BottomNavigationBarItem(icon: Icon(Icons.account_circle),),
],
),
);
/*return RaisedButton(
child: Text('Logout'),
onPressed: logout,
);*/
}
Scaffold buildUnAuthScreen() {
return Scaffold(
body: Container(
width: MediaQuery.of(context).size.width,
height: MediaQuery.of(context).size.height,
decoration: BoxDecoration(
gradient: LinearGradient(
begin: Alignment.topRight,
end: Alignment.bottomLeft,
colors: [
Theme.of(context).primaryColor,
Theme.of(context).accentColor,
]
)
),
child: Column(
mainAxisAlignment: MainAxisAlignment.center,
crossAxisAlignment: CrossAxisAlignment.center,
children: <Widget>[
Text('FlutterMedia',
style: TextStyle(
fontFamily: "Signatra",
fontSize: 90.0,
color: Colors.white
),
),
GestureDetector(
onTap:() => login(),
child: Container(
width: 260,
height: 60,
decoration: BoxDecoration(
image: DecorationImage(
image: AssetImage('assets/images/google_signin_button.png'),
fit: BoxFit.cover,
),
),
),
)
],
),
),
);
}
}
onPressed: () => isUploading ? null : () => handleSubmit(),
Well, there's your problem. You meant to have a tertiary condition that makes onPressed call handleSubmit when isUploading is false. Instead, you have made onPressed into a function that returns a function.
To hopefully make that more clear, let's blow this function up into proper non-lambda functions and if/else blocks:
onPressed: () {
if (isUploading) {
return null;
} else {
return () {
handleUpload();
}
}
}
So consider what happens when the button is pressed. It calls the outer function, which checks isUploading. If true, the function returns null, and if false, it returns another function that, if called, calls handleUpload. So how this plays out is that onPressed will never be null (it just returns null sometimes) and handleUpload never gets called (since the inner function that is returned is never then called itself).
Remove the outer lambda and it will work:
onPressed: isUploading ? null : () => handleSubmit(),
Everyone I am new in flutter. How can create loading screen on login page. when i click on login button then it should be redirect on Dashboard with loading screen. I am trying to create loading screen in flutter. When I click on login button then loading screen show be show and after loading screen it should be redirect on Dashboard.....
import 'dart:convert';
import 'package:flutter/foundation.dart';
import 'package:flutter/material.dart';
import 'package:flutter/widgets.dart';
import 'package:flutter_spinkit/flutter_spinkit.dart';
import 'package:flutternew/dashboard.dart';
import 'package:flutternew/forget_password.dart';
import 'package:http/http.dart' as http;
import 'package:shared_preferences/shared_preferences.dart';
import 'bezierContainer.dart';
class Home extends StatefulWidget {
Home({Key key, this.title}) : super(key: key);
final String title;
#override
_HomeState createState() => _HomeState();
}
class ShowLoading extends StatelessWidget {
#override
Widget build(BuildContext context) {
return new Scaffold(
appBar: AppBar(
title: Text('Loading View'),
),
body: Center(
child: _circularProgressIndicator(),
));
}
Widget _circularProgressIndicator() {
return CircularProgressIndicator();
}
}
class _HomeState extends State<Home> {
bool _isLoading = false;
GlobalKey<FormState> _formKey = GlobalKey<FormState>(debugLabel: '_homekey');
final _scaffoldKey = GlobalKey<ScaffoldState>();
String _email;
String _password;
final TextEditingController emailController = new TextEditingController();
final TextEditingController passwordController = new TextEditingController();
var modal = Container();
showAlertDialog(BuildContext context, String message) {
Widget okButton = FlatButton(
child: Text("OK"),
onPressed: () {
Navigator.of(context).pop();
},
);
AlertDialog alert = AlertDialog(
title: Text("Error"),
content: Text(message),
actions: [
okButton,
],
);
// show the dialog
showDialog(
context: context,
builder: (BuildContext context) {
return alert;
},
);
}
Widget _formSetupWidget(BuildContext context) {
return Form(
key: _formKey,
child: Column(
crossAxisAlignment: CrossAxisAlignment.start,
children: <Widget>[
TextFormField(
controller: emailController,
decoration: InputDecoration(
border: InputBorder.none,
hintText: "Username",
hintStyle: TextStyle(color: Colors.grey, fontSize: 25),
fillColor: Color(0xFFFAFAfA),
filled: true),
keyboardType: TextInputType.emailAddress,
validator: (val) {
if (val.length == 0)
return "Please enter email";
else if (!val.contains("#"))
return "Please enter valid email";
else
return null;
},
onSaved: (val) => _email = val,
),
SizedBox(
height: 15,
),
TextFormField(
controller: passwordController,
decoration: InputDecoration(
border: InputBorder.none,
hintText: "Password",
hintStyle: TextStyle(color: Colors.grey, fontSize: 25),
fillColor: Color(0xFFFAFAfA),
filled: true),
obscureText: true,
validator: (val) {
if (val.length == 0)
return "Please enter password";
else if (val.length <= 5)
return "Your password should be more then 6 char long";
else
return null;
},
onSaved: (val) => _password = val,
),
Padding(
padding: const EdgeInsets.only(top: 20.0),
),
ButtonTheme(
minWidth: 500.0,
height: 60.0,
child: RaisedButton(
child: new Text("Login",
style: TextStyle(color: Colors.white, fontSize: 23.0)),
color: Colors.blueAccent,
highlightColor: Colors.blueAccent,
onPressed: () {
if (emailController.text != " " ||
passwordController.text != " ") {
signIn(emailController.text, passwordController.text);
}
},
),
),
],
),
);
}
signIn(String email, pass) async {
int visible = 0;
final sharedPreferences = await SharedPreferences.getInstance();
Map data = {'email': email, 'password': pass};
var jsonResponse = null;
var response = await http
.post("https://abcdef.com/iot/api/login", body: data);
if (response.statusCode == 200) {
jsonResponse = json.decode(response.body);
if (jsonResponse != null) {
if (jsonResponse['success'] == 1) {
sharedPreferences.setString("token", jsonResponse['data']['token']);
Navigator.of(context).pushAndRemoveUntil(
MaterialPageRoute(builder: (BuildContext context) => Dashboard()),
(Route<dynamic> route) => false);
} else {
String message = jsonResponse['message'];
showAlertDialog(context, message);
}
}
} else {
setState(() {
_isLoading = false;
});
print(response.body);
}
}
#override
Widget build(BuildContext context) {
Center(
child: SpinKitWave(color: Colors.white, type: SpinKitWaveType.start),
);
var assetsImage = new AssetImage('assets/logo.png');
var image = new Image(image: assetsImage, width: 150.0, height: 150.0);
final height = MediaQuery.of(context).size.height;
return Scaffold(
body: Container(
height: height,
color: Colors.white,
child: Stack(
children: <Widget>[
Positioned(
top: -height * .15,
right: -MediaQuery.of(context).size.width * .4,
child: BezierContainer()),
Container(
padding: EdgeInsets.symmetric(horizontal: 20),
child: SingleChildScrollView(
child: Column(
crossAxisAlignment: CrossAxisAlignment.center,
mainAxisAlignment: MainAxisAlignment.center,
children: <Widget>[
SizedBox(height: 70),
new Center(
child: image,
),
SizedBox(height: 20),
_formSetupWidget(context),
Container(
padding: EdgeInsets.symmetric(vertical: 10),
alignment: Alignment.centerRight,
child: FlatButton(
child: Text("Forgot Password?"),
onPressed: () {
Navigator.of(context).pushAndRemoveUntil(
MaterialPageRoute(
builder: (BuildContext context) =>
Forget_password()),
(Route<dynamic> route) => false);
},
),
),
SizedBox(height: height * .055),
],
),
),
),
],
),
));
}
}
Create class
class LoaderDialog {
static Future<void> showLoadingDialog(BuildContext context, GlobalKey key) async {
var wid = MediaQuery.of(context).size.width / 2;
return showDialog<void>(
context: context,
barrierDismissible: false,
builder: (BuildContext context) {
return Padding(
padding: EdgeInsets.only(left: 130 , right: 130),
child: Dialog(
key: key,
backgroundColor: Colors.white,
child: Container(
width: 60.0,
height: 60.0,
child: Image.asset(
'images/loaderOld.gif',
height: 60,
width: 60,
),
)
),
);
},
);
}
}
How to Call:
In your Class(Where you want to show the loader).
final GlobalKey<State> _LoaderDialog = new GlobalKey<State>();
// Show
LoaderDialog.showLoadingDialog(context, _LoaderDialog);
// Hide
Navigator.of(_LoaderDialog.currentContext,rootNavigator: true).pop();
This is a code:
import 'package:flutter/material.dart';
import 'package:flutterapp/ui/pages/notes_home.dart';
import 'package:provider/provider.dart';
import 'package:flutterapp/ui/pages/splash.dart';
import 'package:flutterapp/ui/pages/user_info.dart';
import 'package:flutterapp/ui/pages/auth/login.dart';
import 'package:flutterapp/model/user_repository.dart';
import 'package:path/path.dart';
class HomePage extends StatelessWidget {
#override
Widget build(BuildContext context) {
return ChangeNotifierProvider(
builder: (_) => UserRepository.instance(),
child: Consumer
// ignore: missing_return
(builder: (context, UserRepository user, _) {
// ignore: missing_return
switch (user.status){
case Status.Uninitialized:
return Splash();
case Status.Unauthenticated:
case Status.Authenticating:
return LoginPage();
case Status.Authenticated:
return NotesHomePage();
}
}),
);
}
}
The line "builder: (_) => UserRepository.instance()," in above code shows a error
The argument type 'Widget Function(BuildContext)' cant be assigned to the parameter type 'Widget Function(BuildContext, Widget)'
and whenever I run the program it shows that
Could not find the correct Providerabove this LoginPage Widget
UserRepository code:
import 'package:flutter/material.dart';
import 'package:firebase_auth/firebase_auth.dart';
import 'package:google_sign_in/google_sign_in.dart';
enum Status { Uninitialized, Authenticated, Authenticating, Unauthenticated }
class UserRepository with ChangeNotifier {
FirebaseAuth _auth;
FirebaseUser _user;
GoogleSignIn _googleSignIn;
Status _status = Status.Uninitialized;
UserRepository.instance()
: _auth = FirebaseAuth.instance,
_googleSignIn = GoogleSignIn() {
_auth.onAuthStateChanged.listen(_onAuthStateChanged);
}
Status get status => _status;
FirebaseUser get user => _user;
Future<bool> signIn(String email, String password) async{
try {
_status = Status.Authenticating;
notifyListeners();
await _auth.signInWithEmailAndPassword(email: email, password: password);
return true;
}catch(e){
_status = Status.Unauthenticated;
notifyListeners();
return false;
}
}
Future<bool> signUp(String email, String password) async{
try {
_status = Status.Authenticating;
notifyListeners();
await _auth.createUserWithEmailAndPassword(email: email, password: password);
return true;
}catch(e){
_status = Status.Unauthenticated;
notifyListeners();
return false;
}
}
Future<bool> signInWithGoogle() async{
try{
_status =Status.Authenticating;
notifyListeners();
final GoogleSignInAccount googleUser = await _googleSignIn.signIn();
final GoogleSignInAuthentication googleAuth =
await googleUser.authentication;
final AuthCredential credential = GoogleAuthProvider.getCredential(idToken: googleAuth.idToken, accessToken: googleAuth.accessToken);
await _auth.signInWithCredential(credential);
return true;
}catch(e) {
print(e);
_status = Status.Unauthenticated;
notifyListeners();
return false;
}
}
Future signOut() async {
_auth.signOut();
_googleSignIn.signOut();
_status = Status.Unauthenticated;
notifyListeners();
return Future.delayed(Duration.zero);
}
Future<void> _onAuthStateChanged(FirebaseUser firebaseUser) async{
if(firebaseUser == null) {
_status = Status.Unauthenticated;
}else{
_user = firebaseUser;
_status = Status.Authenticated;
}
notifyListeners();
}
}
Please help
Here is a login page code:
import 'package:flutter/material.dart';
import 'package:flutterapp/model/user_repository.dart';
import 'package:provider/provider.dart';
class LoginPage extends StatefulWidget {
#override
_LoginPageState createState() => _LoginPageState();
}
class _LoginPageState extends State<LoginPage> {
final GlobalKey<ScaffoldState> _key = GlobalKey<ScaffoldState>();
bool signInForm;
#override
void initState() {
// TODO: implement initState
super.initState();
signInForm = true;
}
#override
Widget build(BuildContext context) {
final user = Provider.of<UserRepository>(context);
return WillPopScope(
onWillPop: () async{
if(!signInForm) {
setState(() {
signInForm = true;
});
return false;
}else{
return true;
}
},
child: Scaffold(
key: _key,
backgroundColor: Colors.red,
body: SingleChildScrollView(
padding: const EdgeInsets.all(16.0),
child: SizedBox(
width: double.infinity,
child: Column(
children: <Widget>[
const SizedBox(height: kToolbarHeight),
Container(
decoration: BoxDecoration(
color: Colors.white,
shape: BoxShape.circle,
),
width: 60.0,
height: 60.0,
),
const SizedBox(height: 30.0),
RaisedButton(
textColor: Colors.red,
color: Colors.white,
child: Text('Google'),
onPressed: () async{
if(!await user.signInWithGoogle())
showmessage();
},
),
const SizedBox(height: 30.0),
AnimatedSwitcher(
child: signInForm ? LoginForm() : SignupForm(),
duration: Duration(milliseconds: 200),
),
const SizedBox(height: 20.0,),
OutlineButton(
textColor: Colors.white,
child: signInForm ? Text("Sign Up", style: TextStyle(fontWeight: FontWeight.bold, fontSize: 16.0),) : Icon(Icons.arrow_back),
onPressed: () {
setState(() {
signInForm = !signInForm;
});
},
color: Colors.white,
borderSide: BorderSide(color: Colors.white),
highlightColor: Colors.white,
)
],
),
)
),
),
);
}
void showmessage(){
_key.currentState.showSnackBar(SnackBar(
content: Text("Somethimg is wrong"),
));
}
}
class LoginForm extends StatefulWidget {
final Function showError;
const LoginForm({Key key, this.showError}) : super(key: key);
#override
_LoginFormState createState() => _LoginFormState();
}
class _LoginFormState extends State<LoginForm> {
final GlobalKey<FormState> _formKey = GlobalKey<FormState>();
final FocusNode passwordField = FocusNode();
TextEditingController _email;
TextEditingController _password;
#override
void initState() {
_email = TextEditingController();
_password = TextEditingController();
super.initState();
}
#override
Widget build(BuildContext context) {
final user = Provider.of<UserRepository>(context);
return Container(
padding: const EdgeInsets.all(16.0),
decoration: BoxDecoration(
color: Colors.white,
borderRadius: BorderRadius.circular(10.0),
),
child: Form(
key: _formKey,
child: Column(
children: <Widget>[
Text("Login", style: Theme.of(context).textTheme.display1,),
const SizedBox(height: 20.0),
TextFormField(
controller: _email,
textInputAction: TextInputAction.next,
decoration: InputDecoration(
labelText: "Email"
),
onEditingComplete: (){
FocusScope.of(context).requestFocus(passwordField);
},
),
const SizedBox(height: 16.0,),
TextFormField(
controller: _password,
focusNode: passwordField,
obscureText: true,
decoration: InputDecoration(
labelText: "Password"
),
),
const SizedBox(height: 20.0),
RaisedButton(
textColor: Colors.red,
child: Text("Login"),
onPressed: () async{
if(_formKey.currentState.validate()){
if(!await user.signIn(
_email.text, _password.text))
widget.showError();
}
},
)
],
),
),
);
}
}
class SignupForm extends StatefulWidget {
#override
_SignupFormState createState() => _SignupFormState();
}
class _SignupFormState extends State<SignupForm> {
final FocusNode passwordField = FocusNode();
final FocusNode confirmPasswordField = FocusNode();
TextEditingController _email;
TextEditingController _password;
TextEditingController _confirmpassword;
final GlobalKey<FormState> _formKey = GlobalKey<FormState>();
#override
void initState() {
_email = TextEditingController();
_password = TextEditingController();
_confirmpassword = TextEditingController();
super.initState();
}
#override
Widget build(BuildContext context) {
final user = Provider.of<UserRepository>(context);
return Container(
padding: const EdgeInsets.all(16.0),
decoration: BoxDecoration(
color: Colors.white,
borderRadius: BorderRadius.circular(10.0),
),
child: Form(
key: _formKey,
child: Column(
children: <Widget>[
Text("Sign Up", style: Theme.of(context).textTheme.display1,),
const SizedBox(height: 20.0),
TextFormField(
controller: _email,
textInputAction: TextInputAction.next,
decoration: InputDecoration(
labelText: "Email"
),
onEditingComplete: (){
FocusScope.of(context).requestFocus(passwordField);
},
),
const SizedBox(height: 16.0,),
TextFormField(
obscureText: true,
controller: _password,
focusNode: passwordField,
decoration: InputDecoration(
labelText: "Password"
),
onEditingComplete: ()=> FocusScope.of(context).requestFocus(confirmPasswordField),
),
const SizedBox(height: 16.0,),
TextFormField(
obscureText: true,
controller: _confirmpassword,
focusNode: confirmPasswordField,
decoration: InputDecoration(
labelText: "Confirm Password"
),
onEditingComplete: (){
FocusScope.of(context).requestFocus(passwordField);
},
),
const SizedBox(height: 20.0),
RaisedButton(
textColor: Colors.red,
child: Text("Create Account"),
onPressed: () async{
if(_formKey.currentState.validate()){
if(_confirmpassword.text == _password.text)
if(!await user.signUp(
_email.text, _password.text))
print("Failed to Signup");
}
},
)
],
),
),
);
}
}
In your code, simply change
builder: (_) => UserRepository.instance(),
to
create: (_) => UserRepository.instance(),
and everything will work just fine!
I am very new to flutter and I had same issue, then I solved with this solution..
I replaced builder with create as shown in image.
for provider 3.2 and up you should use create instead of builder
from the version 5.0.0 of provider package, we should use 'create' instead of 'builder' in ChangeNotifierProvider .
Use create: instead builder: in ChangeNotifiereProvider()
Try with this:
class HomePage extends StatelessWidget {
#override
Widget build(BuildContext context) {
return ChangeNotifierProvider<UserRepository>(
create: (context) => UserRepository.instance(),
child: Consumer
// ignore: missing_return
(builder: (context, UserRepository user, child) {
// ignore: missing_return
switch (user.status){
case Status.Uninitialized:
return Splash();
case Status.Unauthenticated:
case Status.Authenticating:
return LoginPage();
case Status.Authenticated:
return NotesHomePage();
}
}),
);
}
}
I'm a little late but I would like to specify that we can use both create, build and they work too! Maybe I'm missing something but if docs still says that builder can be used I think we should.
By the way this is how you should use it to fix the error :
ChangeNotifierProvider(
create: (_) => UserRepository.instance(),
builder : (newContext,child){ //You will use this context here
return Consumer....
}
child : CircularProgressIndicator(),
Be careful when using contexts, is easy to pass the wrong one. In this case you need to use newContext below.
I used CircularProgressIndicator as child but you can use whatever you prefer.
you can put "BuildContext context, Widget? child"
inside the round brackets(Parameter) of builder