Skip to content

Commit 153481e

Browse files
committed
Buat fitur reset password by email
Buat fitur reset password by email dimana, nantinya si pengguna akan menerima email reset password dari Firebase. Didalam email tersebut terdapat link yang berfungsi untuk me-reset password-nya.
1 parent d5620a6 commit 153481e

File tree

1 file changed

+199
-19
lines changed

1 file changed

+199
-19
lines changed

lib/main.dart

Lines changed: 199 additions & 19 deletions
Original file line numberDiff line numberDiff line change
@@ -5,6 +5,7 @@ import 'package:firebase_core/firebase_core.dart';
55
import 'package:flutter/cupertino.dart';
66
import 'package:flutter/foundation.dart';
77
import 'package:flutter/material.dart';
8+
import 'package:flutter/services.dart';
89
import 'package:google_fonts/google_fonts.dart';
910

1011
// https://github.com/FilledStacks/responsive_builder/blob/master/lib/src/sizing_information.dart#L85
@@ -122,6 +123,13 @@ class _LoginPageState extends State<LoginPage> {
122123
child: Column(
123124
crossAxisAlignment: CrossAxisAlignment.center,
124125
children: [
126+
Text(
127+
'Sign In',
128+
style: Theme.of(context).textTheme.headline6?.copyWith(
129+
color: Colors.white,
130+
),
131+
),
132+
SizedBox(height: 16),
125133
TextFormField(
126134
controller: controllerUsername,
127135
decoration: InputDecoration(
@@ -139,16 +147,7 @@ class _LoginPageState extends State<LoginPage> {
139147
color: Colors.white,
140148
),
141149
keyboardType: TextInputType.emailAddress,
142-
validator: (value) {
143-
if (value == null || value.isEmpty) {
144-
return 'Enter an email address';
145-
} else {
146-
final isEmailValid = RegExp(
147-
r"^[a-zA-Z0-9.a-zA-Z0-9.!#$%&'*+-/=?^_`{|}~]+@[a-zA-Z0-9]+\.[a-zA-Z]+",
148-
).hasMatch(value);
149-
return isEmailValid ? null : 'Invalid email';
150-
}
151-
},
150+
validator: emailValidator,
152151
textInputAction: TextInputAction.next,
153152
),
154153
SizedBox(height: 16),
@@ -312,7 +311,12 @@ class _LoginPageState extends State<LoginPage> {
312311
children: [
313312
InkWell(
314313
onTap: () {
315-
// TODO: fitur forgot password
314+
Navigator.push(
315+
context,
316+
MaterialPageRoute(
317+
builder: (context) => ForgotPasswordPage(),
318+
),
319+
);
316320
},
317321
child: Focus(
318322
focusNode: focusNodeForgotPassword,
@@ -328,14 +332,6 @@ class _LoginPageState extends State<LoginPage> {
328332
],
329333
);
330334
}
331-
332-
InputBorder _createUnderlineInputBorder() {
333-
return UnderlineInputBorder(
334-
borderSide: BorderSide(
335-
color: Colors.white,
336-
),
337-
);
338-
}
339335
}
340336

341337
class HomePage extends StatelessWidget {
@@ -477,3 +473,187 @@ void _showSnackBar(BuildContext context, String message, double widthScreen) {
477473
);
478474
}
479475
}
476+
477+
InputBorder _createUnderlineInputBorder() {
478+
return UnderlineInputBorder(
479+
borderSide: BorderSide(
480+
color: Colors.white,
481+
),
482+
);
483+
}
484+
485+
class ForgotPasswordPage extends StatefulWidget {
486+
@override
487+
_ForgotPasswordPageState createState() => _ForgotPasswordPageState();
488+
}
489+
490+
class _ForgotPasswordPageState extends State<ForgotPasswordPage> {
491+
final formState = GlobalKey<FormState>();
492+
final controllerEmail = TextEditingController();
493+
final firebaseAuth = FirebaseAuth.instance;
494+
final focusNodeLabelForgotPassword = FocusNode();
495+
final focusNodeLabelResetPasswordCode = FocusNode();
496+
497+
var widthScreen = 0.0;
498+
var isLoading = false;
499+
500+
@override
501+
Widget build(BuildContext context) {
502+
final mediaQueryData = MediaQuery.of(context);
503+
widthScreen = mediaQueryData.size.width;
504+
return Scaffold(
505+
body: Stack(
506+
children: [
507+
_buildWidgetImageBackground(),
508+
_buildWidgetOverlayImageBackground(),
509+
_buildWidgetContent(),
510+
],
511+
),
512+
);
513+
}
514+
515+
Widget _buildWidgetContent() {
516+
return Center(
517+
child: Container(
518+
padding: EdgeInsets.symmetric(horizontal: 16),
519+
width: widthScreen > _mobileExtraLarge ? _mobileExtraLarge : double.infinity,
520+
child: Column(
521+
mainAxisAlignment: MainAxisAlignment.center,
522+
children: [
523+
_buildWidgetTitleApp(context),
524+
SizedBox(height: 48),
525+
_buildWidgetForm(),
526+
],
527+
),
528+
),
529+
);
530+
}
531+
532+
Widget _buildWidgetForm() {
533+
return IgnorePointer(
534+
ignoring: isLoading,
535+
child: _buildWidgetFormResetPassword(),
536+
);
537+
}
538+
539+
Widget _buildWidgetFormResetPassword() {
540+
return Form(
541+
key: formState,
542+
child: Column(
543+
crossAxisAlignment: CrossAxisAlignment.center,
544+
children: [
545+
Focus(
546+
focusNode: focusNodeLabelForgotPassword,
547+
child: Text(
548+
'Forgot Password',
549+
style: Theme.of(context).textTheme.headline6?.copyWith(
550+
color: Colors.white,
551+
),
552+
),
553+
),
554+
SizedBox(height: 16),
555+
TextFormField(
556+
controller: controllerEmail,
557+
decoration: InputDecoration(
558+
hintText: 'Email',
559+
hintStyle: TextStyle(
560+
color: Colors.grey[500],
561+
),
562+
enabledBorder: _createUnderlineInputBorder(),
563+
icon: Icon(
564+
CupertinoIcons.mail,
565+
color: Colors.white,
566+
),
567+
),
568+
style: TextStyle(
569+
color: Colors.white,
570+
),
571+
keyboardType: TextInputType.emailAddress,
572+
validator: emailValidator,
573+
textInputAction: TextInputAction.next,
574+
onFieldSubmitted: (_) {
575+
_doResetPasswordByEmail();
576+
},
577+
),
578+
SizedBox(height: 24),
579+
_buildWidgetButtonResetPassword(),
580+
SizedBox(height: 24),
581+
TextButton(
582+
onPressed: () {
583+
Navigator.pop(context);
584+
},
585+
child: Text('Back to signin'),
586+
),
587+
],
588+
),
589+
);
590+
}
591+
592+
Widget _buildWidgetButtonResetPassword() {
593+
Widget? widgetLoading;
594+
if (isLoading) {
595+
if (kIsWeb) {
596+
widgetLoading = SizedBox(
597+
width: 20,
598+
height: 20,
599+
child: CircularProgressIndicator(
600+
valueColor: AlwaysStoppedAnimation<Color>(
601+
Colors.white,
602+
),
603+
strokeWidth: 2,
604+
),
605+
);
606+
} else {
607+
widgetLoading = Platform.isIOS || Platform.isMacOS
608+
? CupertinoActivityIndicator()
609+
: SizedBox(
610+
width: 20,
611+
height: 20,
612+
child: CircularProgressIndicator(
613+
valueColor: AlwaysStoppedAnimation<Color>(
614+
Colors.white,
615+
),
616+
strokeWidth: 2,
617+
),
618+
);
619+
}
620+
}
621+
final padding = _setPaddingButton();
622+
return ElevatedButton(
623+
onPressed: () {
624+
_doResetPasswordByEmail();
625+
},
626+
child: widgetLoading ?? Text('RESET PASSWORD'),
627+
style: ElevatedButton.styleFrom(
628+
padding: padding,
629+
),
630+
);
631+
}
632+
633+
void _doResetPasswordByEmail() async {
634+
if (formState.currentState!.validate()) {
635+
focusNodeLabelForgotPassword.requestFocus();
636+
setState(() => isLoading = true);
637+
final email = controllerEmail.text.trim();
638+
await firebaseAuth.sendPasswordResetEmail(email: email);
639+
setState(() => isLoading = false);
640+
_showSnackBar(
641+
context,
642+
'We have sent a link reset password to your email',
643+
widthScreen,
644+
);
645+
Navigator.pop(context);
646+
}
647+
}
648+
}
649+
650+
String? emailValidator(String? value) {
651+
if (value == null || value.isEmpty) {
652+
return 'Enter an email address';
653+
} else {
654+
final isEmailValid = RegExp(
655+
r"^[a-zA-Z0-9.a-zA-Z0-9.!#$%&'*+-/=?^_`{|}~]+@[a-zA-Z0-9]+\.[a-zA-Z]+",
656+
).hasMatch(value);
657+
return isEmailValid ? null : 'Invalid email';
658+
}
659+
}

0 commit comments

Comments
 (0)