In my app "see the structure image" I use a wrapper to navigate the StartUp page or HomePage/NewsFeed page. On the startup page, I have 2 options 1. User Login 2. Volunteer Login. When I use any of these pages to log in its successful to login but page changes in the background. My login page doesn't pop out. I use Navigator.of(context).pop() but nothing works
Main Page code
void main() => runApp(MyApp());
class MyApp extends StatelessWidget {
// This widget is the root of This application.
#override
Widget build(BuildContext context) {
return StreamProvider<User>.value(
value: Authentication().user,
child: MaterialApp(
title: 'Flutter Demo',
theme: ThemeData().copyWith(
scaffoldBackgroundColor: Color(0XFF00B8A9),
canvasColor: Color(0XFF00B8A9),
cursorColor: Color(0XFF00B8A9),
),
initialRoute: Wrapper.id,
routes: {
Wrapper.id: (context) => Wrapper(),
StartUpScreen.id: (context) => StartUpScreen(),
SignIn.id: (context) => SignIn(),
VolunteerLogin.id: (context) => VolunteerLogin(),
Registration.id: (context) => Registration(),
VolunteerHome.id: (context) => VolunteerHome(),
},
),
);
}
}
Wrapper Page Code
class Wrapper extends StatelessWidget {
static String id = "Wrapper";
#override
Widget build(BuildContext context) {
// Check if the user login or not and based on condition send him to different screen
final user = Provider.of<User>(context);
if(user == null){
return StartUpScreen();
}else{
return NewsFeed();
}
}
}
StartUp page code
class StartUpScreen extends StatefulWidget {
static String id = "Start_Up_Screen";
#override
_StartUpScreenState createState() => _StartUpScreenState();
}
class _StartUpScreenState extends State<StartUpScreen> {
#override
Widget build(BuildContext context) {
return Scaffold(
body: SafeArea(
child: Column(
children: <Widget>[
Row(
mainAxisAlignment: MainAxisAlignment.center,
children: <Widget>[
GestureDetector(
onTap: () {
Navigator.pushNamed(context, SignIn.id);
},
child: ReusableButton(
containerColor: kPrimaryButtonColor,
buttonChild: Text(
"User Login",
style: TextStyle(
fontFamily: 'Roboto',
fontSize: 15.0,
),
),
),
),
SizedBox(
height: 40.0,
width: 30.0,
),
GestureDetector(
onTap: () =>
Navigator.pushNamed(context, VolunteerHome.id),
child: ReusableButton(
containerColor: kSOSButtonColor,
buttonChild: Text(
"Volunteer Login",
style: TextStyle(
fontFamily: 'Roboto',
fontSize: 15.0,
color: Colors.white,
),
),
),
),
],
)
],
),
),
);
}
}
Login Page code
class SignIn extends StatefulWidget {
static String id = "Sign_In";
#override
_SignInState createState() => _SignInState();
}
class _SignInState extends State<SignIn> {
Authentication _authentication = Authentication();
final _formKey = GlobalKey<FormState>();
// text field state
String email = '';
String password = '';
#override
Widget build(BuildContext context) {
return Scaffold(
body: Container(
padding: EdgeInsets.symmetric(horizontal: 30.0),
child: Form(
key: _formKey,
autovalidate: true,
child: Column(
mainAxisAlignment: MainAxisAlignment.center,
crossAxisAlignment: CrossAxisAlignment.center,
children: <Widget>[
TextFormField(
decoration: kInputFormFieldDecoration.copyWith(hintText: 'email'),
validator: (val) => val.isEmpty ? 'Enter an email' : null,
onChanged: (val) {
setState(() => email = val);
},
),
SizedBox(height: 20.0),
TextFormField(
decoration: kInputFormFieldDecoration.copyWith(hintText: 'password'),
obscureText: true,
validator: (val) => val.length < 6 ? 'Enter a password 6+ chars long' : null,
onChanged: (val) {
setState(() => password = val);
},
),
SizedBox(height: 20.0),
RaisedButton(
color: Colors.pink[400],
child: Text(
'Sign In',
style: TextStyle(color: kPrimaryButtonColor),
),
onPressed: () async {
await _authentication.signInWithEmailAndPassword(email, password);
},
)
],
),
),
),
);
}
}
Where do you use Navigator.of(context).pop() I see you using Navigator.pushNamed(context, routeName); which would be why your screen is not popping off try changing this too.
Navigator.of(context).popAndPushNamed(routeName)
If you have tried this already let me know and I will try and help you further.
Related
Here is my main.dart code,
void main() {
// Bloc.observer = AppBlocObserver();
runApp(const MyApp());
}
class MyApp extends StatelessWidget {
const MyApp({super.key});
// This widget is the root of your application.
#override
Widget build(BuildContext context) {
return MultiBlocProvider(
providers: [
BlocProvider<SignInCubit>(
create: (BuildContext context) => SignInCubit(),
),
BlocProvider<SignUpCubit>(
create: (BuildContext context) => SignUpCubit(),
),
],
child: LayoutBuilder(
builder: (BuildContext context, BoxConstraints constraints) {
return OrientationBuilder(
builder: (BuildContext context, Orientation orientation) {
//sizeConfiguration
SizeConfig().init(constraints, orientation);
return MaterialApp(
title: 'Flutter Demo',
theme: lightThemeData(context),
darkTheme: darkThemeData(context),
// themeMode: _themeMode,
scaffoldMessengerKey: Messenger.rootScaffoldMessengerKey,
navigatorKey: CustomRoutes.navigatorKey,
home: const SplashPage(),
initialRoute: SplashPage.id,
routes: <String, WidgetBuilder> {
SplashPage.id:(BuildContext context) => const SplashPage(),
SignInPage.id: (BuildContext context) => const SignInPage(),
SignUpPage.id: (BuildContext context) => const SignUpPage(),
},
);
});
}),
);
}
Here is the code on SignIn screen,
class SignInPage extends StatefulWidget {
const SignInPage({super.key});
static const String id = 'SignInPage';
#override
State<SignInPage> createState() => _SignInPageState();
}
class _SignInPageState extends State<SignInPage> {
final dynamic _formKey = GlobalKey<FormState>();
final TextEditingController _passwordController = TextEditingController();
#override
void initState() {
createFocusNodeListeners();
SchedulerBinding.instance.addPostFrameCallback((Duration timeStamp) {
_passwordFocus.addListener(_passwordListener);
});
super.initState();
}
#override
Widget build(BuildContext context) {
final CTTheme cTTheme = Theme.of(context).extension<CTTheme>()!;
//https://medium.com/codex/flutter-bloc-an-introduction-with-cubit-7eae1e740fd0
final SignInCubitModel state = context.watch<SignInCubit>().state;
return Scaffold(
body: CustomPaint(
painter:
LoginCustomPaint(customPaintColor: cTTheme.customPaintCircleColor1),
child: GestureDetector(
onTap: () {
FocusScope.of(context).unfocus();
},
child: SingleChildScrollView(
child: Padding(
padding: const EdgeInsets.symmetric(horizontal: 24), // common padding
child: Form(
key: _formKey,
child: Column(
crossAxisAlignment: CrossAxisAlignment.start,
children: <Widget>[
const SizedBox(
height: 98,
),
Text(
AppStrings.welcomeTo, // heading 3
style: cTTheme.heading3,
),
const SizedBox(
height: 16,
),
RichText(
text: TextSpan(
text: AppStrings.m,
style: cTTheme.heading1, // heading1 with pink color
children: <TextSpan>[
TextSpan(
text: AppStrings.onteFiore,
style: cTTheme.heading2, //heading2 with pink color
),
TextSpan(
text: '\n${AppStrings.c}', style: cTTheme.heading1),
TextSpan(
text: AppStrings.linical, style: cTTheme.heading2),
TextSpan(
text: ' ${AppStrings.t}', style: cTTheme.heading1),
TextSpan(
text: AppStrings.rials, style: cTTheme.heading2),
],
),
),
const SizedBox(
height: 16,
),
Text(
AppStrings.findOutClinicalTrailAndStudies,
style: cTTheme.subtitle3, // subtitle 1
),
SizedBox(
height: SizeConfig.heightMultiplier! * 19.8,
),
TextFormField(
autofocus: false,
style:cTTheme.menuItemTextStyle,
controller: _passwordController,
autovalidateMode: state.passwordValidation
? AutovalidateMode.onUserInteraction
: AutovalidateMode.disabled,
obscureText: !state.signInPasswordVisibility,
// obscuringCharacter: '*',
focusNode: _passwordFocus,
decoration: kTextFieldDecoration2(context).copyWith(
labelText: AppStrings.password,
enabledBorder: UnderlineInputBorder(
borderSide: BorderSide(
color: state.isInvalidPassWord
? state.passWordTextFormFieldColor
: cTTheme.dividerColor!)),
prefixIcon: Padding(
padding: const EdgeInsetsDirectional.only(end: 16.0),
child: Image.asset(// constants
AppIconsPath.padLockIcon),
),
suffixIcon: InkWell(
onTap: () {
context
.read<SignInCubit>()
.changeSignINPassowrdVisibilty(
state.signInPasswordVisibility
? ChangePasswordVisibilityEnum.invisible
: ChangePasswordVisibilityEnum.visible);
},
child: state.signInPasswordVisibility
? Image.asset(AppIconsPath.eyeIcon)
: Image.asset(AppIconsPath.privacyIcon),
),
),
onTap: () => context
.read<SignInCubit>()
.changePasswordTextFormFieldColor(
color: cTTheme.dividerColor!,
isInvalidPassWord: false),
onChanged: (String? value) {
_debouncer.run(() {
checkControllerValues();
});
},
onEditingComplete: () {
if (Validators.validateSignInPassword(
_passwordController.text) !=
null) {
context
.read<SignInCubit>()
.enableValidatorForPasswordTextField();
}
},
validator: (String? value) =>
Validators.validateSignInPassword(value!),
),
errorMessage(state.isInvalidPassWord, 'Password Is Incorrect'),
const SizedBox(
height: 14,
),
Align(
alignment: Alignment.bottomRight,
child: InkWell(
onTap: () async {
final bool isConnocted = await checkConnectivity();
if (isConnocted) {
CustomRoutes.push(
screen: const ForgotPasswordPage());
return;
}
CustomRoutes.push(
screen: InternetErrorScreen(
onPressed: () {
ConnectivityManager.internetChecker()
.then((bool retry) {
if (retry) {
CustomRoutes.back();
}
});
},
),
);
},
child: Text(
AppStrings.forgotPassword,
style: cTTheme.description1,
))),
const SizedBox(
height: 48,
),
PrimaryButton(
onPressed: state.isSignInButtonDissabled
? null
: () {
FocusManager.instance.primaryFocus?.unfocus();
if (_formKey.currentState!.validate()) {
context.read<SignInCubit>().onSignInSubmit(
_emailOrPhoneController.text,
_passwordController.text);
}
},
text: AppStrings.signIn.toUpperCase(),
isLoadingVisible: state.isLoading,
),
const SizedBox(
height: 16,
),
InkWell(
onTap: () async {
final bool isConnocted = await checkConnectivity();
if (isConnocted) {
Navigator.pushNamed(context, SignUpPage.id);
// CustomRoutes.pushreplace(screen: const SignUpPage());
return;
}
CustomRoutes.push(
screen: InternetErrorScreen(onPressed: () {
ConnectivityManager.internetChecker()
.then((bool retry) {
if (retry) {
CustomRoutes.back();
}
});
}));
},
child: Center(
child: RichText(
text: TextSpan(
text: AppStrings.dontHaveAnAccount,
style: cTTheme.subtitle2,
children: <TextSpan>[
TextSpan(
text: ' ${AppStrings.signUp}',
style: cTTheme.iconButtonTextStyle),
],
),
),
),
),
const SizedBox(
height: 66,
),
Center(
child: Text(
AppStrings.byLoggingInYouAgreeToOur,
style: cTTheme.noteTextStyle1,
)),
const SizedBox(
height: 6,
),
Center(
child: InkWell(
onTap: () => CustomRoutes.push(
screen: InternetErrorScreen(onPressed: () {
ConnectivityManager.internetChecker().then((bool value) {
if (value) {
CustomRoutes.back();
}
});
})),
child: Text(
AppStrings.termsAndpolicies,
style: cTTheme.noteTextStyle2,
),
)),
const SizedBox(
height: 20,
),
],
),
),
),
),
),
));
}
I am switching(show/hide) eye icon on the password textfield to show and hide the eye image using "changeSignINPassowrdVisibilty" function from cubit file. Here is the Cubit file code,
class SignInCubit extends Cubit<SignInCubitModel> {
SignInCubit()
: super(
SignInCubitModel()); // here inside SignInCubit class, all the fields are already initialized
final CTTheme cTTheme =
Theme.of(CustomRoutes.navigatorKey.currentContext!).extension<CTTheme>()!;
void changeSignINPassowrdVisibilty(ChangePasswordVisibilityEnum newState) {
emit(state.copyWith(
signInPasswordVisibility:
newState == ChangePasswordVisibilityEnum.visible));
}
}
Here is the code from SignInCubitModel class,
class SignInCubitModel {
SignInCubitModel({
this.signInPasswordVisibility = false,
});
bool signInPasswordVisibility;
SignInCubitModel copyWith({
bool? signInPasswordVisibility,
}) {
return SignInCubitModel(
signInPasswordVisibility:
signInPasswordVisibility ?? this.signInPasswordVisibility,
);
}
}
Initially signInPasswordVisibility field value is false. When user try to switch visibility of the password , signInPasswordVisibility will change its value to true or false.
Here is my problem,
1.I am enabling signInPasswordVisibility to true on SignIn screen by clicking eye icon. Please note now signInPasswordVisibility value is true.
And
2.I am pushing to Signup screen when they click signup button from SignIn screen.
And
3.I am pushing to SignIn screen again when they click SignIn button from signup screen.
But this time signInPasswordVisibility value in SignIn screen still remains true. Its supposed to be false since I am pushing to this screen again. It has to reset the all SignIn screen state values when I push to SignIn screen. But Its not happening.
Signin screen still keeps old state values even if I push to the Signin screen multiple time.
Is there any problem with the way I implemented flutter_bloc? OR Is there any solution to reset the state values every time we push the SignIn screen?
I'm developing an app to make meal reservations, and I have an ElevatedButton that opens an alert when pressed. This alert is where the user is able to confirm the reservation. So, the alert has 2 text buttons, and I need that when the "sim" button is pressed, the ElevatedButton changes from "Reservar" with green color to "Cancelar Reserva" with red color.
I tried this way but it doesn't work:
import 'package:flutter/material.dart';
import 'package:flutter/cupertino.dart';
import '../components/meal_item.dart';
import '../models/day_of_week.dart';
import '../models/want_to_comment.dart';
import '../models/meal.dart';
import '../utils/app_routes.dart';
import '../data/dummy_data.dart';
enum StatusReserva { y, n }
Color statusToColor(StatusReserva value) {
Color color = Colors.green;
switch (value) {
case StatusReserva.n:
break;
case StatusReserva.y:
color = Colors.red;
break;
}
return color;
}
String statusToString(StatusReserva value) {
String title = 'Reservar';
switch (value) {
case StatusReserva.n:
break;
case StatusReserva.y:
title = 'Cancelar Reserva';
break;
}
return title;
}
class DaysOfWeekMealsScreen extends StatefulWidget {
final List<Meal> meals;
final StatusReserva status;
final Function(StatusReserva) onStatusChanged;
const DaysOfWeekMealsScreen({
Key? key,
required this.meals,
required this.status,
required this.onStatusChanged,
}) : super(key: key);
#override
State<DaysOfWeekMealsScreen> createState() => _DaysOfWeekMealsScreenState();
}
class _DaysOfWeekMealsScreenState extends State<DaysOfWeekMealsScreen> {
StatusReserva status = StatusReserva();
#override
void initState() {
super.initState();
status = widget.status;
}
#override
Widget build(BuildContext context) {
final dayOfWeek = ModalRoute.of(context)!.settings.arguments as DayOfWeek;
final dayOfWeekMeals = widget.meals.where((meal) {
return meal.days_of_week.contains(dayOfWeek.id);
}).toList();
void _incrementCount(BuildContext context) {
dayOfWeek.count++;
}
Future<void> _showMyDialog(BuildContext context) async {
return showDialog<void>(
context: context,
barrierDismissible: false, // user must tap button!
builder: (BuildContext context) {
return AlertDialog(
title: const Text(
' ',
),
content: SingleChildScrollView(
child: ListBody(
children: const <Widget>[
Text(
'Confirmar reserva para o dia XX/XX/XX?',
textAlign: TextAlign.center,
style: TextStyle(
fontSize: 15,
fontFamily: 'Raleway',
fontWeight: FontWeight.bold),
),
],
),
),
actions: <Widget>[
Row(
mainAxisAlignment: MainAxisAlignment.end,
children: [
TextButton(
child: const Text('Sim'),
onPressed: () => {
_incrementCount,
Navigator.pop(context),
status = StatusReserva.y
},
),
TextButton(
child: const Text('Não'),
onPressed: () => Navigator.pop(context),
),
],
),
],
);
},
);
}
return Scaffold(
appBar: AppBar(
title: Row(
mainAxisAlignment: MainAxisAlignment.start,
children: [
Image.asset(
'assets/images/logo.png',
fit: BoxFit.contain,
height: 32,
),
Container(
padding: const EdgeInsets.all(8.0),
child: Text(dayOfWeek.title)),
],
),
),
body: Column(
crossAxisAlignment: CrossAxisAlignment.stretch,
children: [
Card(
shape: RoundedRectangleBorder(
borderRadius: BorderRadius.circular(15),
),
margin: const EdgeInsets.all(10),
child: ElevatedButton(
onPressed: () => {_showMyDialog(context)},
style: ButtonStyle(
shape: MaterialStateProperty.all(RoundedRectangleBorder(
borderRadius: BorderRadius.circular(15),
)),
padding: MaterialStateProperty.all(const EdgeInsets.all(15)),
backgroundColor:
MaterialStateProperty.all(statusToColor(widget.status)),
),
child: Text(statusToString(widget.status)),
),
),
Expanded(
child: ListView.builder(
itemCount: dayOfWeekMeals.length,
itemBuilder: (ctx, index) {
return MealItem(dayOfWeekMeals[index]);
},
),
),
],
),
);
}
}
import 'package:apetit_project/models/want_to_comment.dart';
import 'package:apetit_project/screens/login_screen.dart';
import 'package:flutter/material.dart';
import 'screens/tabs_screen.dart';
import 'screens/days_of_week_meals_screen.dart';
import 'screens/meal_detail_screen.dart';
import 'screens/settings_screen.dart';
import 'screens/want_to_comment_screen.dart';
import 'screens/comment_screen.dart';
import 'utils/app_routes.dart';
import 'models/meal.dart';
import 'models/settings.dart';
import 'data/dummy_data.dart';
void main() => runApp(MyApp());
class MyApp extends StatefulWidget {
#override
_MyAppState createState() => _MyAppState();
}
class _MyAppState extends State<MyApp> {
Settings settings = Settings();
StatusReserva status = StatusReserva();
List<Meal> _gourmetMeals = [];
List<Meal> _lightMeals = [];
void _filterMeals(Settings settings) {
setState(() {
this.settings = settings;
});
}
void _reserveMeals(StatusReserva status) {
setState(() {
this.status = status;
});
}
void _toggleGourmet(Meal meal) {
setState(() {
_gourmetMeals.contains(meal)
? _gourmetMeals.remove(meal)
: _gourmetMeals.add(meal);
});
}
bool _isGourmet(Meal meal) {
return _gourmetMeals.contains(meal);
}
void _toggleLight(Meal meal) {
setState(() {
_lightMeals.contains(meal)
? _lightMeals.remove(meal)
: _lightMeals.add(meal);
});
}
bool _isLight(Meal meal) {
return _lightMeals.contains(meal);
}
#override
Widget build(BuildContext context) {
final ThemeData tema = ThemeData(
fontFamily: 'Raleway',
textTheme: ThemeData.light().textTheme.copyWith(
headline6: const TextStyle(
fontSize: 20,
fontFamily: 'Raleway',
fontWeight: FontWeight.bold,
),
),
);
return MaterialApp(
title: 'Appetit',
theme: tema.copyWith(
colorScheme: tema.colorScheme.copyWith(
primary: const Color.fromRGBO(222, 1, 59, 1),
secondary: const Color.fromRGBO(240, 222, 77, 1),
),
),
routes: {
AppRoutes.LOGIN: (ctx) => LoginScreen(),
AppRoutes.HOME: (ctx) => TabsScreen(_gourmetMeals, _lightMeals),
AppRoutes.WANT_TO_COMMENT: (ctx) => const WantToCommentScreen(),
AppRoutes.COMMENT: (ctx) => const CommentScreen(),
AppRoutes.DAYS_OF_WEEK_MEALS: (ctx) => DaysOfWeekMealsScreen(
meals: DUMMY_MEALS,
status,
_reserveMeals,
),
AppRoutes.MEAL_DETAIL: (ctx) => MealDetailScreen(
_toggleGourmet, _isGourmet, _toggleLight, _isLight),
AppRoutes.SETTINGS: (ctx) => SettingsScreen(settings, _filterMeals),
},
);
}
createMaterialColor(Color color) {}
}
To change the state of a widget you can use setState
enum StatusReserva { y, n }
Color statusToColor(StatusReserva value) {
Color color = Colors.green;
switch (value) {
case StatusReserva.n:
break;
case StatusReserva.y:
color = Colors.red;
break;
}
return color;
}
class StatusTest extends StatefulWidget {
const StatusTest({Key? key}) : super(key: key);
#override
State<StatusTest> createState() => _StatusTestState();
}
class _StatusTestState extends State<StatusTest> {
var status = StatusReserva.n;
Future<void> _showMyDialog(BuildContext context) async {
return showDialog<void>(
context: context,
barrierDismissible: false, // user must tap button!
builder: (BuildContext context) {
return AlertDialog(
title: const Text(
' ',
),
content: SingleChildScrollView(
child: ListBody(
children: const <Widget>[
Text(
'Confirmar reserva para o dia XX/XX/XX?',
textAlign: TextAlign.center,
style: TextStyle(
fontSize: 15,
fontFamily: 'Raleway',
fontWeight: FontWeight.bold),
),
],
),
),
actions: <Widget>[
Row(
mainAxisAlignment: MainAxisAlignment.end,
children: [
TextButton(
child: const Text('Sim'),
onPressed: () => setState(() {
Navigator.pop(context);
status = StatusReserva.n;
}),
),
TextButton(
child: const Text('Não'),
onPressed: () => setState(() {
Navigator.pop(context);
status = StatusReserva.y;
}),
),
],
),
],
);
},
);
}
#override
Widget build(BuildContext context) {
return Scaffold(
appBar: AppBar(
elevation: 0,
),
body: Center(
child: Column(
mainAxisAlignment: MainAxisAlignment.center,
children: [
SizedBox(
width: 100,
height: 100,
child: Container(
color: statusToColor(status),
child: const Center(
child: Text(
'Status color',
style: TextStyle(color: Colors.white),
)),
),
),
ElevatedButton(
onPressed: () {
_showMyDialog(context);
},
child: const Text('Show dialog'),
),
],
),
),
);
}
}
For further clarification
The StatusReserva status = StatusReserva.n; should be in the State class _DaysOfWeekMealsScreenState. And to change it use setState. This value should never change if not inside a setState.
The Sim button onPressed should be like the following (Also with fixes of an unintended Set creation):
TextButton(
child: const Text('Sim'),
onPressed: () {
_incrementCount();
Navigator.pop(context);
setState(() => status = StatusReserva.y);
},
),
Use a boolean value instead of enum like this
bool isCancelReservar = false;
and in the state class before build method add this code :
bool isCancelReservar = false;
#override
void initState(){
isCancelReservar = widget.isCancelReservar;
super.initState();
}
Now you are able to update the value of isCancelReservar on clicking "sim button" using setState method. Your text button should look like this :
TextButton(
child: const Text('Sim'),
onPressed: () {
setState(() {
isCancelReservar = true;
});
_incrementCount,
Navigator.pop(context);
},
),
and your elevated button like this :
Card(
shape: RoundedRectangleBorder(
borderRadius: BorderRadius.circular(15),
),
margin: const EdgeInsets.all(10),
child: ElevatedButton(
onPressed: () => {_showMyDialog(context)},
style: ButtonStyle(
shape: MaterialStateProperty.all(RoundedRectangleBorder(
borderRadius: BorderRadius.circular(15),
)),
padding: MaterialStateProperty.all(const EdgeInsets.all(15)),
backgroundColor:
MaterialStateProperty.all(isCancelReservar ? Colors.red :
Colors.green),
),
child: Text(isCancelReservar ? "Cancelar Reserva" : "Reservar"),
),
),
where you can see the backgroundColor will be red with text "Cancelar Reserva" if the value of isCancelReservar is true else it would be of color green with test Reservar.
I am including an AlertDialog when the app user is not registered in Cloud Firestore:
class MuroScreen extends StatefulWidget {
const MuroScreen({Key? key}) : super(key: key);
#override
_MuroScreenState createState() => _MuroScreenState();
}
class _MuroScreenState extends State<MuroScreen> {
CollectionReference userRef = FirebaseFirestore.instance.collection('clientes');
Future<void> salir() async {
await FirebaseAuth.instance.signOut().catchError((error){
print(error.toString());
});
Navigator.of(context).push(MaterialPageRoute(builder: (c)=>MyHomePage001()),);
}
Future<void> verificarUsuario() async{
DocumentSnapshot snapshotUser = await userRef
.doc(FirebaseAuth.instance.currentUser!.phoneNumber)
.get();
print("existe?"+snapshotUser.exists.toString());
if(snapshotUser.exists){
//ya existe
print("si EXISTE");
}
else {
//no existe
print("no EXISTE");
var nameController = TextEditingController();
Alert(
context: context,
title: "LOGIN",
content: Column(
children: <Widget>[
TextField(
decoration: InputDecoration(
icon: Icon(Icons.account_circle),
labelText: 'Username',
),
),
TextField(
obscureText: true,
decoration: InputDecoration(
icon: Icon(Icons.lock),
labelText: 'Password',
),
),
],
),
buttons: [
DialogButton(
onPressed: () => Navigator.pop(context),
child: Text(
"LOGIN",
style: TextStyle(color: Colors.white, fontSize: 20),
),
)
]).show();
}
}
#override
void initState() {
// TODO: implement initState
super.initState();
verificarUsuario();
}
#override
Widget build(BuildContext context) {
return Scaffold(
appBar: AppBar(
title: Text("Home"),
),
body: Column(
mainAxisAlignment: MainAxisAlignment.center,
children: [
Container(
margin: EdgeInsets.all(65),
width: double.infinity,
child: ElevatedButton(
style: ElevatedButton.styleFrom(
primary: Colors.red,
),
onPressed: () {
salir();
},
child: Text("Logout",style: TextStyle(color:Colors.white,fontSize: 16, fontWeight: FontWeight.bold),),
),
)
],
),
);
}
}
Alert is a rflutter_alert widget.
The issue is that every time I click on a textfield inside the alert widget, the screen reloads and shows the alert again without showing the keyboard, it reloads again.
You are calling the verificarUsuario(); in init() which doesn't have a context. The alert needs a context from build method to show. Please add a button inside the scaffold and open this alert after passing the the context as an argument. It should work.
I have the following code that initially displays a blank page, but I'd like an rAlert dialog to display automatically. Once the user clicks 'Request' or 'Cancel', some text will be displayed on the screen.
But I can't get the code to run that displays the Alert. I had it working by showing a button and clicking the button, but i need the Alert to display automatically when the page is displayed. I tried putting it in the initState. I didn't get any errors, but it didn't work either.
Anyone know what I need to do? Thanks?
import 'package:flutter/material.dart';
import 'package:rflutter_alert/rflutter_alert.dart';
import 'dart:async';
import 'package:rostermeon/cwidgets/general_widgets.dart';
import 'package:rostermeon/rmo_constants.dart';
class ForgotPassword extends StatefulWidget {
static const String id = 'forgot_password_screen';
#override
_ForgotPasswordState createState() => _ForgotPasswordState();
}
class _ForgotPasswordState extends State<ForgotPassword> {
StreamController<bool> _events;
#override
initState() {
super.initState();
_events = new StreamController<bool>();
doRequest(context: context);
}
Future<bool> doSaveRequest({String pReason}) async {
await Future.delayed(const Duration(seconds: 3), () {});
return false;
}
Future<bool> doRequest({context}) {
String _reason = '';
GlobalKey<FormState> _formKey = GlobalKey<FormState>();
TextEditingController reasonController = TextEditingController();
TextStyle _style = TextStyle(fontFamily: 'Montserrat', fontSize: 18.0, fontWeight: FontWeight.normal);
InputDecoration _textFormFieldDecoration({String hintText, double padding}) => InputDecoration(
//contentPadding: EdgeInsets.fromLTRB(8.0, 8.0, 8.0, 8.0),
contentPadding: EdgeInsets.all(padding),
isDense: true,
hintText: hintText,
hintStyle: TextStyle(color: kHintText),
border: OutlineInputBorder(
borderRadius: BorderRadius.all(Radius.circular(5)),
),
);
return Alert(
context: context,
title: 'Request New Password',
content: StreamBuilder<bool>(
initialData: false,
stream: _events.stream,
builder: (BuildContext context, AsyncSnapshot<bool> snapshot) {
print(" ${snapshot.data.toString()}");
return snapshot.data
? CircularProgressIndicator()
: Form(
key: _formKey,
child: Column(
crossAxisAlignment: CrossAxisAlignment.start,
children: <Widget>[
SizedBox(height: 20.0),
Text('Email', textAlign: TextAlign.left, style: _style),
SizedBox(height: 10.0),
TextFormField(
validator: (value) {
if (value.isEmpty) {
return "please enter email";
}
return null;
},
onSaved: (value) {
_reason = value;
},
decoration: _textFormFieldDecoration(
hintText: 'your email address',
padding: 8.0,
),
controller: reasonController,
),
SizedBox(height: 10.0),
],
),
);
}),
buttons: [
DialogButton(
child: Text('Request', style: TextStyle(color: Colors.white, fontSize: 20)),
color: kMainColor,
onPressed: () async {
if (_formKey.currentState.validate()) {
_formKey.currentState.save();
print(_reason);
_events.add(true);
var saved = await doSaveRequest(pReason: _reason);
if (saved) {
Navigator.pop(context, false);
} else {
_events.add(false);
}
Navigator.of(context).pop();
// Navigator.pop(context, false);
}
},
),
DialogButton(
child: Text('Cancel', style: TextStyle(color: Colors.white, fontSize: 20)),
color: kMainColor,
onPressed: () {
Navigator.pop(context, false);
},
),
],
).show();
}
#override
Widget build(BuildContext context) {
return Scaffold(
appBar: rmoAppBar(subText: 'Request New Password', hideBackButton: false),
body: Center(
child: Column(
mainAxisAlignment: MainAxisAlignment.center,
children: <Widget>[],
),
),
);
}
}
Dialogs/Alerts need the buildContext in order to work, You can't have the buildContext before build() method is called, that's why you can't just call it in initstate() before the build is called.
To make it work use addPostFrameCallback to make sure it delays until widget is built:
void initState() {
super.initState();
WidgetsBinding.instance
.addPostFrameCallback((_) => yourMethod(context));
}
https://www.didierboelens.com/2019/04/addpostframecallback/
Am i trying to get the second screen double value in first screen when i click the device back button but i can't get it.I don't know how to do it. I'm a beginner for flutter.Help me to solve it.
My task is first screen get two double value using text field and pass it to second screen.
second screen have text field to enter the operator and click device back button it will check the operator and make the equal operations like(addition,subtraction,multiplication and division) then the answer will be display in the first screen.
How can i get the second screen double variable(value) in first screen. How to pass a double value to another class
This is my code.
import 'package:flutter/material.dart';
import 'package:flutter/services.dart';
class User {
final double a, b,c;
User(
{
this.a,
this.b,
this.c,
}
);
}
void main() {
runApp(MaterialApp(
title: 'Navigation Basics',
home: App(),
));
}
class App extends StatelessWidget{
#override
Widget build(BuildContext context){
return MaterialApp(
debugShowCheckedModeBanner: false,
theme: ThemeData(
primaryColor: Color(0xFFFB415B),
fontFamily: "Ubuntu"
),
home: LoginPage(),
);
}
}
class LoginPage extends StatefulWidget{
final User value;
LoginPage ({Key key, this.value}) : super(key: key);
#override
_LoginPageState createState() => _LoginPageState();
}
class _LoginPageState extends State<LoginPage>{
double c1;
/*callback(double c2) {
print("$c2");
setState(() {
c1 = c2;
});
}*/
bool _isHidden = true;
var _acontroller= new TextEditingController();
var _bcontroller= new TextEditingController();
void _toggleVisibility(){
setState(() {
_isHidden = !_isHidden;
});
}
Future<bool> _onWillPop() {
return showDialog(
context: context,
builder: (context) => new AlertDialog(
title: new Text('Are you sure?'),
content: new Text('Do you want to exit an App'),
actions: <Widget>[
new FlatButton(
onPressed: () => Navigator.of(context).pop(false),
child: new Text('No'),
),
new FlatButton(
onPressed: () => Navigator.of(context).pop(true),
child: new Text('Yes'),
),
],
),
) ?? false;
}
#override
Widget build(BuildContext context){
return WillPopScope(
onWillPop:_onWillPop,
child: Scaffold(
appBar: AppBar(
title: Text("First Page"),
),
resizeToAvoidBottomPadding: false,
body: Container(
padding: EdgeInsets.only(top: 100.0, right: 20.0, left: 20.0, bottom: 20.0),
child: Column(
mainAxisAlignment: MainAxisAlignment.spaceBetween,
crossAxisAlignment: CrossAxisAlignment.center,
children: <Widget>[
Text(
'Hello',
style: TextStyle(
fontSize: 50.0,
fontWeight: FontWeight.bold,
fontFamily: "Pacifico"
),
),
TextFormField(
keyboardType: TextInputType.number,
inputFormatters: <TextInputFormatter>[
WhitelistingTextInputFormatter.digitsOnly
],
controller: _acontroller,
decoration: InputDecoration(
border: OutlineInputBorder(
borderRadius: BorderRadius.circular(20.0),
),
hintText: 'Enter A value',
hintStyle: TextStyle(color: Colors.grey),
contentPadding: EdgeInsets.all(10)
)
),
TextFormField(
keyboardType: TextInputType.number,
inputFormatters: <TextInputFormatter>[
WhitelistingTextInputFormatter.digitsOnly
],
controller: _bcontroller,
decoration: InputDecoration(
border: OutlineInputBorder(
borderRadius: BorderRadius.circular(20.0),
),
hintText: 'Enter B value',
hintStyle: TextStyle(color: Colors.grey),
contentPadding: EdgeInsets.all(5)
)
),
RaisedButton(
child: Text(" OK "),
color: Colors.red,
textColor: Colors.white,
splashColor: Colors.grey,
padding: EdgeInsets.fromLTRB(10, 10, 10, 10),
onPressed: () async {
if(_acontroller.text == "" && _bcontroller.text == "")
{
await showDialog(
context: context,
builder: (context) => new AlertDialog(
title: new Text('Please Enter The value'),
),
);
}
else if(_acontroller.text == "")
{
await showDialog(
context: context,
builder: (context) => new AlertDialog(
title: new Text('Please Enter The A value'),
),
);
}
else if(_bcontroller.text == "")
{
await showDialog(
context: context,
builder: (context) => new AlertDialog(
title: new Text('Please Enter The B value'),
),
);
}
else
{
//a = emailController.text;
var route = new MaterialPageRoute(
builder: (BuildContext context) =>
new SecondScreen(
value: User(
a:double.parse(_acontroller.text) ,
b:double.parse(_bcontroller.text) ,
)
),
);
Navigator.of(context).push(route);
}
}
),
Text('Answers : $c1',//+ {widget.value.c}.toString(),//${widget.value.c}
style: TextStyle(
fontSize: 35.0,
fontWeight: FontWeight.bold,
fontFamily: "Pacifico"
),
),
]
)
)
));
}
}
class SecondScreen extends StatefulWidget {
final User value;
double c1;
double c2;
//Function(double) callback;
SecondScreen ({Key key, this.value}) : super(key: key);
#override
_SecondScreenState createState() => _SecondScreenState();
}
class _SecondScreenState extends State<SecondScreen> {
var _ccontroller= new TextEditingController();
Future<bool> _onWillPop() async {
if(_ccontroller.text == ""){
await showDialog(
context: context,
builder: (context) => new AlertDialog(
title: new Text('Please Enter The Operator'),
),
);
}
else if(_ccontroller.text == "+"){
double a1= widget.value.a;
double b1= widget.value.b;
// c1 = a1+b1;
setState(() {
widget.c1 = a1+b1;
});
//widget.callback = (c) as Function(double);
Navigator.pop(context);
}
else if(_ccontroller.text == "-"){
double a1= widget.value.a;
double b1= widget.value.b;
setState(() {
widget.c1 = a1-b1;
});
Navigator.pop(context, '$widget.c1');
}
else if(_ccontroller.text == "*" || _ccontroller.text =="×" ){
double a1= widget.value.a;
double b1= widget.value.b;
setState(() {
widget.c1 = a1*b1;
});
Navigator.pop(context, '$widget.c1');
}
else if(_ccontroller.text == "/"){
double a1= widget.value.a;
double b1= widget.value.b;
setState(() {
widget.c1 = a1/b1;
});
Navigator.pop(context, '$widget.c1');
}
else{
await showDialog(
context: context,
builder: (context) => new AlertDialog(
title: new Text('Wrong Operator'),
),
);
}
}
#override
Widget build(BuildContext context) {
return WillPopScope(
onWillPop:_onWillPop,
child: Scaffold(
appBar: AppBar(
title: Text('Operation'),
backgroundColor: new Color(0xFF81C784),
),
body: Center(
child: Wrap(
children: <Widget>[
TextFormField(
controller: _ccontroller,
decoration: new InputDecoration.collapsed(
border: OutlineInputBorder(
borderRadius: BorderRadius.circular(10.0),
),
hintText: 'Enter Operator'
),
),
],
),
)
),
);
}
}
You can await the result from your Navigator.of(context).push(...) and use it in your first screen to display the result from the second screen. Also, when you pop your second screen, you need to do it by calling Navigator.of(context).pop(yourValue) for it to work.
Check out this article from Flutter.dev: Return Data from a Screen for a detailed, step-by-step explanation on the topic.
Check cookbook at
https://flutter.dev/docs/cookbook/navigation/returning-data
Basically
Navigator.pop(context, 'Nope.');