I am building a Flutter app where there is a page for creating an account. When I click the button next it is supposed to call the createAccount method that will upload fields to Cloud Firestore. Currently all the fields are uploaded with the exception of the image URL and the image is not uploaded to FirebaseStorage. The imageURL uploads an empty string meaning the file image must be null. Does this mean there is an issue with the uploadProfilePicture method in my AuthRepository class?
import 'package:flutter/material.dart';
import 'package:flutter_riverpod/flutter_riverpod.dart';
import 'package:iinhouse/core/utils/utils.dart';
import 'package:iinhouse/core/widgets/birthdate_picker.dart';
import 'package:iinhouse/core/widgets/gender_picker.dart';
import 'package:iinhouse/core/widgets/pick_image.dart';
import 'package:iinhouse/features/authentication/providers/auth_provider.dart';
import 'package:iinhouse/features/authentication/utils.dart';
import 'package:image_picker/image_picker.dart';
class CreateAccountPage extends ConsumerStatefulWidget {
const CreateAccountPage({super.key});
@override
ConsumerState<CreateAccountPage> createState() => _CreateAccountPageState();
}
class _CreateAccountPageState extends ConsumerState<CreateAccountPage> {
late final TextEditingController _firstNameController;
late final TextEditingController _lastNameController;
late final TextEditingController _emailController;
late final TextEditingController _passwordController;
XFile? image;
DateTime? birthday;
String gender = 'male';
bool isLoading = false;
final _formKey = GlobalKey<FormState>();
@override
void initState() {
_firstNameController = TextEditingController();
_lastNameController = TextEditingController();
_emailController = TextEditingController();
_passwordController = TextEditingController();
super.initState();
}
@override
void dispose() {
_firstNameController.dispose();
_lastNameController.dispose();
_emailController.dispose();
_passwordController.dispose();
super.dispose();
}
Future<void> createAccount() async {
if (_formKey.currentState!.validate()) {
setState(() {
isLoading = true;
});
_formKey.currentState!.save();
await ref
.read(authProvider)
.createAccount(
fullName:
'${_firstNameController.text} ${_lastNameController.text}',
birthDate: birthday ?? DateTime.now(),
gender: gender,
email: _emailController.text,
password: _passwordController.text,
image: image)
.then((credential) {
if (!credential!.user!.emailVerified) {
Navigator.pushNamed(context, '/verify_email');
}
}).catchError((_) {
setState(() {
isLoading = false;
});
});
setState(() {
isLoading = false;
});
}
}
@override
Widget build(BuildContext context) {
return Scaffold(
backgroundColor: Colors.white,
appBar: AppBar(),
body: SingleChildScrollView(
child: Padding(
padding: const EdgeInsets.all(8.0),
child: Form(
key: _formKey,
child: Column(
children: [
GestureDetector(
onTap: () async {
image = await pickImage();
if (image != null) {
print('Image picked: ${image!.path}');
} else {
print('Image picking cancelled');
}
setState(() {});
},
child: PickImageWidget(image: image)),
Padding(
padding: const EdgeInsets.all(8.0),
child: TextFormField(
controller: _firstNameController,
validator: (value) =>
value!.isEmpty ? 'First name cannot be empty' : null,
decoration: const InputDecoration(
filled: true,
fillColor: Colors.white,
labelText: 'First Name',
hintText: 'First Name',
border: OutlineInputBorder(),
),
),
),
Padding(
padding: const EdgeInsets.all(8.0),
child: TextFormField(
controller: _lastNameController,
validator: (value) =>
value!.isEmpty ? 'Location cannot be empty' : null,
decoration: const InputDecoration(
filled: true,
fillColor: Colors.white,
labelText: 'Last Name',
hintText: 'Last Name',
border: OutlineInputBorder(),
),
),
),
SizedBox(
height: 20,
),
BirthdatePicker(
dateTime: birthday ?? DateTime.now(),
onPressed: () async {
birthday = await pickSimpleDate(
context: context, date: birthday);
setState(() {});
}),
SizedBox(
height: 20,
),
GenderPicker(
gender: gender,
onChanged: (value) {
gender = value ?? 'male';
setState(() {});
}),
Padding(
padding: const EdgeInsets.all(8.0),
child: TextFormField(
controller: _emailController,
validator: (value) =>
value!.isEmpty ? 'Email cannot be empty' : null,
decoration: const InputDecoration(
filled: true,
fillColor: Colors.white,
labelText: 'Email',
hintText: 'Email',
border: OutlineInputBorder(),
),
),
),
Padding(
padding: const EdgeInsets.all(8.0),
child: TextFormField(
controller: _passwordController,
validator: (value) =>
value!.isEmpty ? 'Password cannot be empty' : null,
decoration: const InputDecoration(
filled: true,
fillColor: Colors.white,
labelText: 'Password',
hintText: 'Password',
border: OutlineInputBorder(),
),
obscureText: true,
),
),
isLoading
? const Center(
child: CircularProgressIndicator(),
)
: Padding(
padding: const EdgeInsets.all(8.0),
child: ElevatedButton(
onPressed: createAccount,
style: ElevatedButton.styleFrom(
backgroundColor: Colors.black,
fixedSize: const Size(350, 50),
disabledForegroundColor:
Colors.black.withOpacity(0.38),
disabledBackgroundColor:
Colors.black.withOpacity(0.12),
shape: const RoundedRectangleBorder(
borderRadius:
BorderRadius.all(Radius.circular(25.0)),
),
),
child: const Text(
'Next',
style: TextStyle(color: Colors.white),
),
),
),
],
)),
),
),
);
}
}
AuthRepository:
import 'dart:io';
import 'package:cloud_firestore/cloud_firestore.dart';
import 'package:firebase_auth/firebase_auth.dart';
import 'package:fluttertoast/fluttertoast.dart';
import 'package:iinhouse/core/constants/firebase_collection_names.dart';
import 'package:iinhouse/core/constants/storage_folder_names.dart';
import 'package:iinhouse/features/authentication/models/users.dart';
import 'package:firebase_storage/firebase_storage.dart' as firebase_storage;
import 'package:image_picker/image_picker.dart';
class AuthRepository {
final _auth = FirebaseAuth.instance;
final _firestore = FirebaseFirestore.instance;
Future<UserCredential?> createAccount({
required String fullName,
required DateTime birthDate,
required String gender,
required String email,
required String password,
XFile? image, // Change parameter type to XFile?
}) async {
try {
final credential = await FirebaseAuth.instance
.createUserWithEmailAndPassword(email: email, password: password);
String? downloadUrl;
if (image != null) {
downloadUrl = await uploadProfilePicture(image);
}
UserModel user = UserModel(
fullName: fullName,
birthday: birthDate,
gender: gender,
email: email,
password: password,
profilePicUrl:
downloadUrl ?? "", // Use downloadUrl, or empty string if null
uid: FirebaseAuth.instance.currentUser!.uid,
followers: [],
sentRequests: [],
receivedRequests: [],
);
await FirebaseFirestore.instance
.collection(FirebaseCollectionNames.users)
.doc(FirebaseAuth.instance.currentUser!.uid)
.set(user.toMap());
return credential;
} catch (e) {
Fluttertoast.showToast(msg: e.toString());
print(e.toString());
return null;
}
}
Future<String?> uploadProfilePicture(XFile? imageFile) async {
try {
User? user = FirebaseAuth.instance.currentUser;
if (user == null) {
print('User not authenticated.');
return null;
}
print("image path: ${imageFile!.path}");
firebase_storage.Reference storageRef = firebase_storage
.FirebaseStorage.instance
.ref(StorageFolderNames.profilePics)
.child(FirebaseAuth.instance.currentUser!.uid);
await storageRef.putFile(File(imageFile.path));
String downloadURL = await storageRef.getDownloadURL();
print('Image uploaded. Download URL: $downloadURL');
return downloadURL;
} catch (e) {
print('Error uploading image: $e');
return null;
}
}
}
pickImage:
import 'dart:io';
import 'package:image_picker/image_picker.dart';
Future<XFile?> pickImage() async {
final picker = ImagePicker();
try {
final file = await picker.pickImage(
source: ImageSource.gallery, maxHeight: 720, maxWidth: 720);
return file;
} catch (e) {
print('Error picking image: $e');
return null;
}
}
Code for the UserModel class:
import 'package:flutter/material.dart';
import 'package:iinhouse/core/constants/firebase_field_names.dart';
@immutable
class UserModel {
final String fullName;
final DateTime birthday;
final String gender;
final String email;
final String password;
final String profilePicUrl;
final String uid;
final List<String> followers;
final List<String> sentRequests;
final List<String> receivedRequests;
UserModel(
{required this.fullName,
required this.birthday,
required this.gender,
required this.email,
required this.password,
required this.profilePicUrl,
required this.uid,
required this.followers,
required this.sentRequests,
required this.receivedRequests});
Map<String, dynamic> toMap() {
return <String, dynamic>{
FirebaseFieldNames.fullName: fullName,
FirebaseFieldNames.birthDay: birthday.millisecondsSinceEpoch,
FirebaseFieldNames.gender: gender,
FirebaseFieldNames.email: email,
FirebaseFieldNames.password: password,
FirebaseFieldNames.profilePicUrl: profilePicUrl,
FirebaseFieldNames.uid: uid,
FirebaseFieldNames.followers: followers,
FirebaseFieldNames.sentRequests: sentRequests,
FirebaseFieldNames.receivedRequests: receivedRequests,
};
}
factory UserModel.fromMap(Map<String, dynamic> map) {
return UserModel(
fullName: map[FirebaseFieldNames.fullName] as String,
birthday: DateTime.fromMillisecondsSinceEpoch(
map[FirebaseFieldNames.birthDay] as int),
gender: map[FirebaseFieldNames.gender] as String,
email: map[FirebaseFieldNames.email] as String,
password: map[FirebaseFieldNames.password] as String,
profilePicUrl: map[FirebaseFieldNames.profilePicUrl] as String,
uid: map[FirebaseFieldNames.uid] as String,
followers: List<String>.from((map[FirebaseFieldNames.followers] ?? [])),
sentRequests:
List<String>.from((map[FirebaseFieldNames.sentRequests] ?? [])),
receivedRequests:
List<String>.from((map[FirebaseFieldNames.receivedRequests] ?? [])),
);
}
}
//Code for the FirebaseFieldNames
class FirebaseFieldNames {
static const String fullName = 'full_name';
static const String birthDay = 'birth_day';
static const String gender = 'gender';
static const String email = 'email';
static const String password = 'password';
static const String followers = 'followers';
static const String sentRequests = 'sent_requests';
static const String receivedRequests = 'receivedRequests';
static const String uid = 'uid';
static const String datePublished = 'date_published';
static const String postId = 'post_id';
static const String posterId = 'poster_id';
static const String content = 'content';
static const String fileUrl = 'file_url';
static const String postType = 'post_type';
static const String likes = 'likes';
static const String profilePicUrl = 'profile_pic_url';
static const String createdAt = 'created_at';
static const String authorId = 'author_id';
static const String commentId = 'comment_id';
static const String text = 'text';
// story specific
static const String imageUrl = 'image_url';
static const String storyId = 'story_id';
static const String views = 'views';
// video related
static const String videoUrl = 'video_url';
static const String videoId = 'video_id';
// Chat Feature
static const members = 'members';
static const chatroomId = 'chatroom_id';
static const lastMessage = 'last_message';
static const lastMessageTs = 'last_message_ts';
static const message = 'message';
static const senderId = 'sender_id';
static const receiverId = 'receiver_id';
static const seen = 'seen';
static const timestamp = 'timestamp';
static const messageId = 'message_id';
static const messageType = 'message_type';
FirebaseFieldNames._();
}
I am building a Flutter app where there is a page for creating an account. When I click the button next it is supposed to call the createAccount method that will upload fields to Cloud Firestore. Currently all the fields are uploaded with the exception of the image URL and the image is not uploaded to FirebaseStorage. The imageURL uploads an empty string meaning the file image must be null. Does this mean there is an issue with the uploadProfilePicture method in my AuthRepository class?
import 'package:flutter/material.dart';
import 'package:flutter_riverpod/flutter_riverpod.dart';
import 'package:iinhouse/core/utils/utils.dart';
import 'package:iinhouse/core/widgets/birthdate_picker.dart';
import 'package:iinhouse/core/widgets/gender_picker.dart';
import 'package:iinhouse/core/widgets/pick_image.dart';
import 'package:iinhouse/features/authentication/providers/auth_provider.dart';
import 'package:iinhouse/features/authentication/utils.dart';
import 'package:image_picker/image_picker.dart';
class CreateAccountPage extends ConsumerStatefulWidget {
const CreateAccountPage({super.key});
@override
ConsumerState<CreateAccountPage> createState() => _CreateAccountPageState();
}
class _CreateAccountPageState extends ConsumerState<CreateAccountPage> {
late final TextEditingController _firstNameController;
late final TextEditingController _lastNameController;
late final TextEditingController _emailController;
late final TextEditingController _passwordController;
XFile? image;
DateTime? birthday;
String gender = 'male';
bool isLoading = false;
final _formKey = GlobalKey<FormState>();
@override
void initState() {
_firstNameController = TextEditingController();
_lastNameController = TextEditingController();
_emailController = TextEditingController();
_passwordController = TextEditingController();
super.initState();
}
@override
void dispose() {
_firstNameController.dispose();
_lastNameController.dispose();
_emailController.dispose();
_passwordController.dispose();
super.dispose();
}
Future<void> createAccount() async {
if (_formKey.currentState!.validate()) {
setState(() {
isLoading = true;
});
_formKey.currentState!.save();
await ref
.read(authProvider)
.createAccount(
fullName:
'${_firstNameController.text} ${_lastNameController.text}',
birthDate: birthday ?? DateTime.now(),
gender: gender,
email: _emailController.text,
password: _passwordController.text,
image: image)
.then((credential) {
if (!credential!.user!.emailVerified) {
Navigator.pushNamed(context, '/verify_email');
}
}).catchError((_) {
setState(() {
isLoading = false;
});
});
setState(() {
isLoading = false;
});
}
}
@override
Widget build(BuildContext context) {
return Scaffold(
backgroundColor: Colors.white,
appBar: AppBar(),
body: SingleChildScrollView(
child: Padding(
padding: const EdgeInsets.all(8.0),
child: Form(
key: _formKey,
child: Column(
children: [
GestureDetector(
onTap: () async {
image = await pickImage();
if (image != null) {
print('Image picked: ${image!.path}');
} else {
print('Image picking cancelled');
}
setState(() {});
},
child: PickImageWidget(image: image)),
Padding(
padding: const EdgeInsets.all(8.0),
child: TextFormField(
controller: _firstNameController,
validator: (value) =>
value!.isEmpty ? 'First name cannot be empty' : null,
decoration: const InputDecoration(
filled: true,
fillColor: Colors.white,
labelText: 'First Name',
hintText: 'First Name',
border: OutlineInputBorder(),
),
),
),
Padding(
padding: const EdgeInsets.all(8.0),
child: TextFormField(
controller: _lastNameController,
validator: (value) =>
value!.isEmpty ? 'Location cannot be empty' : null,
decoration: const InputDecoration(
filled: true,
fillColor: Colors.white,
labelText: 'Last Name',
hintText: 'Last Name',
border: OutlineInputBorder(),
),
),
),
SizedBox(
height: 20,
),
BirthdatePicker(
dateTime: birthday ?? DateTime.now(),
onPressed: () async {
birthday = await pickSimpleDate(
context: context, date: birthday);
setState(() {});
}),
SizedBox(
height: 20,
),
GenderPicker(
gender: gender,
onChanged: (value) {
gender = value ?? 'male';
setState(() {});
}),
Padding(
padding: const EdgeInsets.all(8.0),
child: TextFormField(
controller: _emailController,
validator: (value) =>
value!.isEmpty ? 'Email cannot be empty' : null,
decoration: const InputDecoration(
filled: true,
fillColor: Colors.white,
labelText: 'Email',
hintText: 'Email',
border: OutlineInputBorder(),
),
),
),
Padding(
padding: const EdgeInsets.all(8.0),
child: TextFormField(
controller: _passwordController,
validator: (value) =>
value!.isEmpty ? 'Password cannot be empty' : null,
decoration: const InputDecoration(
filled: true,
fillColor: Colors.white,
labelText: 'Password',
hintText: 'Password',
border: OutlineInputBorder(),
),
obscureText: true,
),
),
isLoading
? const Center(
child: CircularProgressIndicator(),
)
: Padding(
padding: const EdgeInsets.all(8.0),
child: ElevatedButton(
onPressed: createAccount,
style: ElevatedButton.styleFrom(
backgroundColor: Colors.black,
fixedSize: const Size(350, 50),
disabledForegroundColor:
Colors.black.withOpacity(0.38),
disabledBackgroundColor:
Colors.black.withOpacity(0.12),
shape: const RoundedRectangleBorder(
borderRadius:
BorderRadius.all(Radius.circular(25.0)),
),
),
child: const Text(
'Next',
style: TextStyle(color: Colors.white),
),
),
),
],
)),
),
),
);
}
}
AuthRepository:
import 'dart:io';
import 'package:cloud_firestore/cloud_firestore.dart';
import 'package:firebase_auth/firebase_auth.dart';
import 'package:fluttertoast/fluttertoast.dart';
import 'package:iinhouse/core/constants/firebase_collection_names.dart';
import 'package:iinhouse/core/constants/storage_folder_names.dart';
import 'package:iinhouse/features/authentication/models/users.dart';
import 'package:firebase_storage/firebase_storage.dart' as firebase_storage;
import 'package:image_picker/image_picker.dart';
class AuthRepository {
final _auth = FirebaseAuth.instance;
final _firestore = FirebaseFirestore.instance;
Future<UserCredential?> createAccount({
required String fullName,
required DateTime birthDate,
required String gender,
required String email,
required String password,
XFile? image, // Change parameter type to XFile?
}) async {
try {
final credential = await FirebaseAuth.instance
.createUserWithEmailAndPassword(email: email, password: password);
String? downloadUrl;
if (image != null) {
downloadUrl = await uploadProfilePicture(image);
}
UserModel user = UserModel(
fullName: fullName,
birthday: birthDate,
gender: gender,
email: email,
password: password,
profilePicUrl:
downloadUrl ?? "", // Use downloadUrl, or empty string if null
uid: FirebaseAuth.instance.currentUser!.uid,
followers: [],
sentRequests: [],
receivedRequests: [],
);
await FirebaseFirestore.instance
.collection(FirebaseCollectionNames.users)
.doc(FirebaseAuth.instance.currentUser!.uid)
.set(user.toMap());
return credential;
} catch (e) {
Fluttertoast.showToast(msg: e.toString());
print(e.toString());
return null;
}
}
Future<String?> uploadProfilePicture(XFile? imageFile) async {
try {
User? user = FirebaseAuth.instance.currentUser;
if (user == null) {
print('User not authenticated.');
return null;
}
print("image path: ${imageFile!.path}");
firebase_storage.Reference storageRef = firebase_storage
.FirebaseStorage.instance
.ref(StorageFolderNames.profilePics)
.child(FirebaseAuth.instance.currentUser!.uid);
await storageRef.putFile(File(imageFile.path));
String downloadURL = await storageRef.getDownloadURL();
print('Image uploaded. Download URL: $downloadURL');
return downloadURL;
} catch (e) {
print('Error uploading image: $e');
return null;
}
}
}
pickImage:
import 'dart:io';
import 'package:image_picker/image_picker.dart';
Future<XFile?> pickImage() async {
final picker = ImagePicker();
try {
final file = await picker.pickImage(
source: ImageSource.gallery, maxHeight: 720, maxWidth: 720);
return file;
} catch (e) {
print('Error picking image: $e');
return null;
}
}
Code for the UserModel class:
import 'package:flutter/material.dart';
import 'package:iinhouse/core/constants/firebase_field_names.dart';
@immutable
class UserModel {
final String fullName;
final DateTime birthday;
final String gender;
final String email;
final String password;
final String profilePicUrl;
final String uid;
final List<String> followers;
final List<String> sentRequests;
final List<String> receivedRequests;
UserModel(
{required this.fullName,
required this.birthday,
required this.gender,
required this.email,
required this.password,
required this.profilePicUrl,
required this.uid,
required this.followers,
required this.sentRequests,
required this.receivedRequests});
Map<String, dynamic> toMap() {
return <String, dynamic>{
FirebaseFieldNames.fullName: fullName,
FirebaseFieldNames.birthDay: birthday.millisecondsSinceEpoch,
FirebaseFieldNames.gender: gender,
FirebaseFieldNames.email: email,
FirebaseFieldNames.password: password,
FirebaseFieldNames.profilePicUrl: profilePicUrl,
FirebaseFieldNames.uid: uid,
FirebaseFieldNames.followers: followers,
FirebaseFieldNames.sentRequests: sentRequests,
FirebaseFieldNames.receivedRequests: receivedRequests,
};
}
factory UserModel.fromMap(Map<String, dynamic> map) {
return UserModel(
fullName: map[FirebaseFieldNames.fullName] as String,
birthday: DateTime.fromMillisecondsSinceEpoch(
map[FirebaseFieldNames.birthDay] as int),
gender: map[FirebaseFieldNames.gender] as String,
email: map[FirebaseFieldNames.email] as String,
password: map[FirebaseFieldNames.password] as String,
profilePicUrl: map[FirebaseFieldNames.profilePicUrl] as String,
uid: map[FirebaseFieldNames.uid] as String,
followers: List<String>.from((map[FirebaseFieldNames.followers] ?? [])),
sentRequests:
List<String>.from((map[FirebaseFieldNames.sentRequests] ?? [])),
receivedRequests:
List<String>.from((map[FirebaseFieldNames.receivedRequests] ?? [])),
);
}
}
//Code for the FirebaseFieldNames
class FirebaseFieldNames {
static const String fullName = 'full_name';
static const String birthDay = 'birth_day';
static const String gender = 'gender';
static const String email = 'email';
static const String password = 'password';
static const String followers = 'followers';
static const String sentRequests = 'sent_requests';
static const String receivedRequests = 'receivedRequests';
static const String uid = 'uid';
static const String datePublished = 'date_published';
static const String postId = 'post_id';
static const String posterId = 'poster_id';
static const String content = 'content';
static const String fileUrl = 'file_url';
static const String postType = 'post_type';
static const String likes = 'likes';
static const String profilePicUrl = 'profile_pic_url';
static const String createdAt = 'created_at';
static const String authorId = 'author_id';
static const String commentId = 'comment_id';
static const String text = 'text';
// story specific
static const String imageUrl = 'image_url';
static const String storyId = 'story_id';
static const String views = 'views';
// video related
static const String videoUrl = 'video_url';
static const String videoId = 'video_id';
// Chat Feature
static const members = 'members';
static const chatroomId = 'chatroom_id';
static const lastMessage = 'last_message';
static const lastMessageTs = 'last_message_ts';
static const message = 'message';
static const senderId = 'sender_id';
static const receiverId = 'receiver_id';
static const seen = 'seen';
static const timestamp = 'timestamp';
static const messageId = 'message_id';
static const messageType = 'message_type';
FirebaseFieldNames._();
}
Share
Improve this question
edited Mar 13 at 13:12
Frank van Puffelen
601k85 gold badges890 silver badges860 bronze badges
Recognized by Google Cloud Collective
asked Mar 13 at 10:03
Anesu MazvimaviAnesu Mazvimavi
1671 silver badge11 bronze badges
2
- 2 If there is a problem in uploadProfilePicture, it would log an error, right? What is the error? Please edit the question to show all relevant details. – Doug Stevenson Commented Mar 13 at 12:36
- @DougStevenson so the uploadProfilePicture method doesn't return any error however the createAccout method doesn't upload any imageURL to Cloud Firestore meaning the File of the image must be now. I have edited the code to include the UserModel class as well the FirebaseFieldNames class – Anesu Mazvimavi Commented Mar 13 at 13:13
1 Answer
Reset to default 0Try a different method than putFile()
to save your file.
I use putData()
like this:
await imageFile.readAsBytes().then((value) async {
await storageRef.putData(value, SettableMetadata(contentType: imageFile.mimeType));
});
发布者:admin,转转请注明出处:http://www.yc00.com/questions/1744708922a4589223.html
评论列表(0条)