当我尝试使用提供的表单登录或注册时,我希望在身份验证成功后重定向到应用程序的主页视图。但是,目前,在输入有效凭据并提交表单后,即使我收到令牌并在调试时登录成功,我仍保留在登录或注册页面上,而不会被定向到主页视图
我登录后得到了这个
D/FirebaseAuth(16316):通知 id 令牌侦听器有关用户的信息 ( mvq79gN8zIVSyDZlHYZnQzbg6yb2 )。 我/颤振(16316):登录:mvq79gN8zIVSyDZlHYZnQzbg6yb2
但是此后他们不会将我重定向到主页
这是我的授权
This is my root
import 'package:flutter/material.dart';
import 'package:churchapp/services/auth_service.dart';
import 'package:churchapp/views/home/home.dart';
import 'package:churchapp/views/login.dart';
class Root extends StatefulWidget {
const Root({super.key, required this.auth});
final BaseAuth auth;
@override
State<StatefulWidget> createState() => _RootState();
}
enum AuthStatus {
notDetermined,
notLoggedIn,
loggedIn,
}
class _RootState extends State<Root> {
AuthStatus _authStatus = AuthStatus.notDetermined;
late String _currentUserId;
@override
void initState() {
super.initState();
_checkLoginStatus();
}
void _checkLoginStatus() async {
bool isLoggedIn = await widget.auth.isLoggedIn();
setState(() {
_authStatus = isLoggedIn ? AuthStatus.loggedIn : AuthStatus.notLoggedIn;
});
}
void _updateAuthStatus(AuthStatus status, String userId) {
setState(() {
_authStatus = status;
_currentUserId = userId;
});
}
@override
Widget build(BuildContext context) {
switch (_authStatus) {
case AuthStatus.notDetermined:
return _buildLoadingScreen();
case AuthStatus.notLoggedIn:
return Login(
auth: widget.auth,
onSignedIn: () {
_updateAuthStatus(AuthStatus.loggedIn, _currentUserId);
},
);
case AuthStatus.loggedIn:
return Home(
auth: widget.auth,
userId: _currentUserId,
onSignedOut: () {
_updateAuthStatus(AuthStatus.notLoggedIn, '');
// Navigate to the login screen
Navigator.of(context).pushReplacement(MaterialPageRoute(
builder: (context) => Login(
auth: widget.auth,
onSignedIn: () {}, // No need to handle onSignedIn here
),
));
},
);
}
}
Widget _buildLoadingScreen() {
return const Scaffold(
body: Center(
child: CircularProgressIndicator(),
),
);
}
}
This is my login
import 'package:churchapp/services/auth_service.dart';
import 'package:firebase_auth/firebase_auth.dart';
import 'package:flutter/foundation.dart';
import 'package:flutter/material.dart';
class Login extends StatefulWidget {
const Login({super.key, required this.auth, required this.onSignedIn});
final BaseAuth auth;
final VoidCallback onSignedIn;
@override
State<Login> createState() => _LoginState();
}
class _LoginState extends State<Login> {
late TextEditingController _emailController;
late TextEditingController _passwordController;
final GlobalKey<FormState> _formKey = GlobalKey<FormState>();
@override
void initState() {
super.initState();
_emailController = TextEditingController();
_passwordController = TextEditingController();
}
@override
void dispose() {
_emailController.dispose();
_passwordController.dispose();
super.dispose();
}
String? _validateEmail(String? value) {
if (value == null || value.isEmpty) {
return 'Email cannot be empty';
}
if (!RegExp(r'^[\w-\.]+@([\w-]+\.)+[\w-]{2,4}$').hasMatch(value)) {
return 'Invalid email';
}
return null;
}
String? _validatePassword(String? value) {
if (value == null || value.isEmpty) {
return 'Password cannot be empty';
}
if (value.length < 6) {
return 'Password must be at least 6 characters';
}
return null;
}
Future<void> validateAndSubmit() async {
final form = _formKey.currentState;
if (form != null && form.validate()) {
// Form is valid, process login here.
String email = _emailController.text.trim();
String password = _passwordController.text;
try {
UserCredential userCredential =
await widget.auth.signInWithEmailAndPassword(
email: email,
password: password,
);
if (kDebugMode) {
print('Signed in: ${userCredential.user!.uid}');
}
// Trigger the onSignedIn callback to navigate to the home page
widget.onSignedIn(); // This callback should update the _authStatus
} catch (e) {
if (kDebugMode) {
print('Error: $e');
}
}
}
}
@override
Widget build(BuildContext context) {
return Scaffold(
appBar: AppBar(
title: const Text('Login'),
),
body: Center(
child: SingleChildScrollView(
child: Padding(
padding: const EdgeInsets.all(16.0),
child: Form(
key: _formKey,
child: Column(
mainAxisAlignment: MainAxisAlignment.center,
children: buildInputs() + buildLoginButton(),
),
),
),
),
),
);
}
List<Widget> buildInputs() {
return <Widget>[
TextFormField(
controller: _emailController,
decoration: const InputDecoration(
labelText: 'Email',
),
validator: _validateEmail,
),
const SizedBox(height: 20.0),
TextFormField(
controller: _passwordController,
obscureText: true,
decoration: const InputDecoration(
labelText: 'Password',
),
validator: _validatePassword,
),
const SizedBox(height: 20.0),
];
}
List<Widget> buildLoginButton() {
return [
ElevatedButton(
onPressed: () {
validateAndSubmit(); // Calling validateAndSubmit method
},
style: ElevatedButton.styleFrom(
foregroundColor: Colors.white,
backgroundColor: const Color.fromARGB(255, 90, 175, 249),
shape: RoundedRectangleBorder(
borderRadius: BorderRadius.circular(20.0),
),
),
child: const Text('Login'),
),
const SizedBox(height: 20.0),
];
}
}
This si my SignUp
import 'package:churchapp/services/auth_service.dart';
import 'package:flutter/material.dart';
import 'package:firebase_auth/firebase_auth.dart';
import 'package:flutter/foundation.dart';
class SignUpPage extends StatefulWidget {
const SignUpPage({super.key, required this.auth, required this.onSignedIn});
final BaseAuth auth;
final VoidCallback onSignedIn;
@override
State<SignUpPage> createState() => _SignUpPageState();
}
class _SignUpPageState extends State<SignUpPage> {
late TextEditingController _firstNameController;
late TextEditingController _lastNameController;
late TextEditingController _emailController;
late TextEditingController _confirmEmailController;
late TextEditingController _passwordController;
late TextEditingController _confirmPasswordController;
late TextEditingController _phoneNumberController;
late TextEditingController _dddController;
final GlobalKey<FormState> _formKey = GlobalKey<FormState>();
int? selectedDay;
int? selectedMonth;
int? selectedYear;
String selectedGender = 'Male';
@override
void initState() {
super.initState();
_firstNameController = TextEditingController();
_lastNameController = TextEditingController();
_emailController = TextEditingController();
_confirmEmailController = TextEditingController();
_passwordController = TextEditingController();
_confirmPasswordController = TextEditingController();
_phoneNumberController = TextEditingController();
_dddController = TextEditingController();
}
@override
void dispose() {
_firstNameController.dispose();
_lastNameController.dispose();
_emailController.dispose();
_confirmEmailController.dispose();
_passwordController.dispose();
_confirmPasswordController.dispose();
_phoneNumberController.dispose();
_dddController.dispose();
super.dispose();
}
@override
Widget build(BuildContext context) {
return Scaffold(
appBar: AppBar(
title: const Text('Sign Up'),
),
body: SingleChildScrollView(
child: Form(
key: _formKey,
child: Center(
child: Padding(
padding: const EdgeInsets.all(16.0),
child: Column(
mainAxisAlignment: MainAxisAlignment.center,
crossAxisAlignment: CrossAxisAlignment.stretch,
children: [
_buildNameSection(),
const SizedBox(height: 20.0),
_buildDateOfBirthSection(),
const SizedBox(height: 20.0),
_buildGenderSection(),
const SizedBox(height: 20.0),
_buildEmailSection(),
const SizedBox(height: 20.0),
_buildPasswordSection(),
const SizedBox(height: 20.0),
_buildPhoneNumberSection(),
const SizedBox(height: 20.0),
_buildSignUpButton(),
],
),
),
),
),
),
);
}
Widget _buildNameSection() {
return Column(
crossAxisAlignment: CrossAxisAlignment.start,
children: [
TextFieldWidget(
labelText: 'First Name',
controller: _firstNameController,
),
const SizedBox(height: 20.0),
TextFieldWidget(
labelText: 'Last Name',
controller: _lastNameController,
),
],
);
}
Widget _buildPhoneNumberSection() {
return Column(
crossAxisAlignment: CrossAxisAlignment.start,
children: [
TextFieldWidget(
labelText: 'DDD',
controller: _dddController,
),
const SizedBox(height: 20.0),
TextFieldWidget(
labelText: 'Cellphone Number',
controller: _phoneNumberController,
),
],
);
}
Widget _buildDateOfBirthSection() {
return DateOfBirthDropdowns(
selectedDay: selectedDay,
selectedMonth: selectedMonth,
selectedYear: selectedYear,
onChangedDay: (value) {
setState(() {
selectedDay = value;
});
},
onChangedMonth: (value) {
setState(() {
selectedMonth = value;
});
},
onChangedYear: (value) {
setState(() {
selectedYear = value;
});
},
);
}
Widget _buildGenderSection() {
return GenderDropdown(
selectedGender: selectedGender,
onChangedGender: (value) {
setState(() {
selectedGender = value!;
});
},
);
}
Widget _buildEmailSection() {
return Column(
crossAxisAlignment: CrossAxisAlignment.start,
children: [
TextFieldWidget(
labelText: 'Email',
controller: _emailController,
validator: _validateEmail,
),
const SizedBox(height: 20.0),
TextFieldWidget(
labelText: 'Confirm Email',
controller: _confirmEmailController,
),
],
);
}
Widget _buildPasswordSection() {
return Column(
crossAxisAlignment: CrossAxisAlignment.start,
children: [
TextFieldWidget(
labelText: 'Password',
controller: _passwordController,
validator: _validatePassword,
obscureText: true,
),
const SizedBox(height: 20.0),
TextFieldWidget(
labelText: 'Confirm Password',
controller: _confirmPasswordController,
obscureText: true,
),
],
);
}
Widget _buildSignUpButton() {
return ElevatedButton(
onPressed: validateAndSubmit,
style: ElevatedButton.styleFrom(
foregroundColor: Colors.white,
backgroundColor: const Color.fromARGB(255, 90, 175, 249),
shape: RoundedRectangleBorder(
borderRadius: BorderRadius.circular(20.0),
),
),
child: const Text('Sign Up'),
);
}
String? _validateEmail(String? value) {
if (value == null || value.isEmpty) {
return 'Email cannot be empty';
}
if (!RegExp(r'^[\w-\.]+@([\w-]+\.)+[\w-]{2,4}$').hasMatch(value)) {
return 'Invalid email';
}
return null;
}
String? _validatePassword(String? value) {
if (value == null || value.isEmpty) {
return 'Password cannot be empty';
}
if (value.length < 6) {
return 'Password must be at least 6 characters long';
}
return null;
}
Future<void> validateAndSubmit() async {
final form = _formKey.currentState;
if (form != null && form.validate()) {
// Form is valid, process sign up here.
String email = _emailController.text.trim();
String password = _passwordController.text;
try {
UserCredential userCredential =
await widget.auth.createUserWithEmailAndPassword(
email: email,
password: password,
);
widget.onSignedIn();
if (kDebugMode) {
print('User created: ${userCredential.user!.uid}');
}
// Proceed with navigation or any other action upon successful sign-up
} catch (e) {
if (kDebugMode) {
print('Error: $e');
}
// Handle sign-up errors, such as displaying an error message
}
}
}
}
class DateOfBirthDropdowns extends StatelessWidget {
const DateOfBirthDropdowns({
super.key,
this.selectedDay,
this.selectedMonth,
this.selectedYear,
required this.onChangedDay,
required this.onChangedMonth, // This field name should match the one provided here
required this.onChangedYear,
});
final int? selectedDay;
final int? selectedMonth;
final int? selectedYear;
final ValueChanged<int?> onChangedDay;
final ValueChanged<int?>
onChangedMonth; // Ensure this matches the field name provided
final ValueChanged<int?> onChangedYear;
@override
Widget build(BuildContext context) {
return Row(
children: <Widget>[
Expanded(
child: DropdownButtonFormField<int>(
decoration: const InputDecoration(
labelText: 'Day',
),
value: selectedDay,
onChanged: onChangedDay,
items: List.generate(31, (index) {
return DropdownMenuItem<int>(
value: index + 1,
child: Text((index + 1).toString()),
);
}),
),
),
const SizedBox(width: 20.0),
Expanded(
child: DropdownButtonFormField<int>(
decoration: const InputDecoration(
labelText: 'Month',
),
value: selectedMonth,
onChanged:
onChangedMonth, // Ensure this matches the field name provided
items: List.generate(12, (index) {
return DropdownMenuItem<int>(
value: index + 1,
child: Text((index + 1).toString()),
);
}),
),
),
const SizedBox(width: 20.0),
Expanded(
child: DropdownButtonFormField<int>(
decoration: const InputDecoration(
labelText: 'Year',
),
value: selectedYear,
onChanged: onChangedYear,
items: List.generate(80, (index) {
return DropdownMenuItem<int>(
value: DateTime.now().year - index,
child: Text((DateTime.now().year - index).toString()),
);
}),
),
),
],
);
}
}
class GenderDropdown extends StatelessWidget {
const GenderDropdown({
super.key,
required this.selectedGender,
required this.onChangedGender,
});
final String selectedGender;
final ValueChanged<String?> onChangedGender;
@override
Widget build(BuildContext context) {
return DropdownButtonFormField<String>(
decoration: const InputDecoration(
labelText: 'Select Gender',
),
value: selectedGender,
onChanged: onChangedGender,
items: const [
DropdownMenuItem<String>(
value: 'Male',
child: Text('Male'),
),
DropdownMenuItem<String>(
value: 'Female',
child: Text('Female'),
),
],
);
}
}
class TextFieldWidget extends StatelessWidget {
const TextFieldWidget({
super.key,
required this.labelText,
required this.controller,
this.validator,
this.obscureText = false,
});
final String labelText;
final TextEditingController controller;
final String? Function(String?)? validator;
final bool obscureText;
@override
Widget build(BuildContext context) {
return TextFormField(
controller: controller,
decoration: InputDecoration(
labelText: labelText,
),
validator: validator,
obscureText: obscureText,
);
}
}
This is my home
import 'package:flutter/foundation.dart';
import 'package:flutter/material.dart';
import 'package:intl/intl.dart';
import 'package:churchapp/services/auth_service.dart';
class Home extends StatefulWidget {
const Home({
super.key,
required this.auth,
required this.userId,
required this.onSignedOut,
});
final BaseAuth auth;
final String userId;
final VoidCallback onSignedOut;
@override
State<Home> createState() => _HomeState();
}
class _HomeState extends State<Home> {
List<Event> events = [
Event(
title: 'Culto de Domingo',
description:
'Participe do nosso culto dominical com louvor, adoração e uma mensagem inspiradora.',
date: DateTime(2024, 3, 1, 10, 0),
location: 'Igreja da Comunidade',
),
Event(
title: 'Grupo de Estudo Bíblico',
description:
'Venha participar do nosso grupo de estudo bíblico semanal para aprender mais sobre a Palavra de Deus.',
date: DateTime(2024, 3, 4, 19, 0),
location: 'Salão da Igreja',
),
Event(
title: 'Concerto de Natal',
description:
'Celebre a época festiva com músicas de Natal apresentadas pelo coro da igreja.',
date: DateTime(2024, 12, 20, 18, 30),
location: 'Igreja da Comunidade',
),
];
Future<void> _handleSignOut(BuildContext context) async {
try {
await widget.auth.signOut();
widget.onSignedOut();
} catch (e) {
if (kDebugMode) {
print('Error signing out: $e');
}
}
}
@override
Widget build(BuildContext context) {
return Scaffold(
appBar: AppBar(
title: const Text('Home'),
actions: [
IconButton(
icon: const Icon(Icons.logout),
onPressed: () => _handleSignOut(context),
),
],
),
body: ListView.builder(
itemCount: events.length,
itemBuilder: (context, index) {
return GestureDetector(
onTap: () {
_navigateToEventDetailsScreen(context, events[index]);
},
child: EventCard(
title: events[index].title,
description: events[index].description,
date: events[index].date,
location: events[index].location,
),
);
},
),
);
}
void _navigateToEventDetailsScreen(BuildContext context, Event event) {
Navigator.push(
context,
MaterialPageRoute(builder: (context) => EventDetailsScreen(event: event)),
);
}
}
class Event {
final String title;
final String description;
final DateTime date;
final String location;
Event({
required this.title,
required this.description,
required this.date,
required this.location,
});
}
class EventCard extends StatelessWidget {
final String title;
final String description;
final DateTime date;
final String location;
const EventCard({
super.key,
required this.title,
required this.description,
required this.date,
required this.location,
});
@override
Widget build(BuildContext context) {
return Card(
margin: const EdgeInsets.all(16),
child: Padding(
padding: const EdgeInsets.all(16),
child: Column(
crossAxisAlignment: CrossAxisAlignment.start,
children: [
Text(
title,
style: const TextStyle(
fontSize: 20,
fontWeight: FontWeight.bold,
),
),
const SizedBox(height: 8),
Text(
description,
style: const TextStyle(fontSize: 16),
),
const SizedBox(height: 8),
Text(
'Data: ${DateFormat('dd/MM/yyyy').format(date)}',
style: const TextStyle(fontSize: 16),
),
const SizedBox(height: 8),
// You can add time here if needed
Text(
'Horário: ${DateFormat('HH:mm').format(date)}', // Format time as needed
style: const TextStyle(fontSize: 16),
),
const SizedBox(height: 8),
Text(
'Local: $location',
style: const TextStyle(fontSize: 16),
),
],
),
),
);
}
}
class EventDetailsScreen extends StatelessWidget {
final Event event;
const EventDetailsScreen({super.key, required this.event});
@override
Widget build(BuildContext context) {
return Scaffold(
appBar: AppBar(
title: Text(event.title),
),
body: Padding(
padding: const EdgeInsets.all(16.0),
child: Column(
crossAxisAlignment: CrossAxisAlignment.start,
children: [
Text(
'Descrição: ${event.description}',
style: const TextStyle(fontSize: 18),
),
const SizedBox(height: 16),
Text(
'Data: ${DateFormat('dd/MM/yyyy').format(event.date)}',
style: const TextStyle(fontSize: 18),
),
const SizedBox(height: 8),
// You can add time here if needed
Text(
'Horário: ${DateFormat('HH:mm').format(event.date)}', // Format time as needed
style: const TextStyle(fontSize: 18),
),
const SizedBox(height: 16),
Text(
'Local: ${event.location}',
style: const TextStyle(fontSize: 18),
),
],
),
),
);
}
}