diff --git a/Sources/justMUSIC/assets/images/key_icon.png b/Sources/justMUSIC/assets/images/key_icon.png new file mode 100644 index 0000000..b869f0e Binary files /dev/null and b/Sources/justMUSIC/assets/images/key_icon.png differ diff --git a/Sources/justMUSIC/lib/components/login_button.dart b/Sources/justMUSIC/lib/components/login_button.dart index 6a41d9c..aa71087 100644 --- a/Sources/justMUSIC/lib/components/login_button.dart +++ b/Sources/justMUSIC/lib/components/login_button.dart @@ -4,8 +4,9 @@ import 'package:flutter_screenutil/flutter_screenutil.dart'; class LoginButton extends StatefulWidget { final Function callback; + final String text; - const LoginButton({Key? key, required this.callback}) : super(key: key); + const LoginButton({Key? key, required this.callback, required this.text}) : super(key: key); @override State createState() => _LoginButtonState(); @@ -57,7 +58,7 @@ class _LoginButtonState extends State { ), alignment: Alignment.center, child: Text( - "Se connecter", + widget.text, textAlign: TextAlign.center, style: TextStyle(color: Colors.white, fontSize: 18), ), diff --git a/Sources/justMUSIC/lib/main.dart b/Sources/justMUSIC/lib/main.dart index 45e9b19..4ac0733 100644 --- a/Sources/justMUSIC/lib/main.dart +++ b/Sources/justMUSIC/lib/main.dart @@ -11,6 +11,7 @@ import 'package:flutter_screenutil/flutter_screenutil.dart'; import 'package:justmusic/screens/add_friend_screen.dart'; import 'package:justmusic/screens/explanations_screen.dart'; import 'package:justmusic/screens/feed_screen.dart'; +import 'package:justmusic/screens/forget_password_screen.dart'; import 'package:justmusic/screens/login_screen.dart'; import 'package:justmusic/screens/launching_rocker_screen.dart'; import 'package:justmusic/screens/post_screen.dart'; @@ -102,6 +103,7 @@ class _MyAppState extends State { '/addFriend': (context) => const AddFriendScreen(), '/launchingRocket': (context) => const LaunchingRocketScreen(), '/verifyEmail': (context) => const VerifyEmailScreen(), + '/forgetPassword': (context) => const ForgetPasswordScreen(), }, debugShowCheckedModeBanner: false, theme: ThemeData( diff --git a/Sources/justMUSIC/lib/screens/forget_password_screen.dart b/Sources/justMUSIC/lib/screens/forget_password_screen.dart new file mode 100644 index 0000000..f43c889 --- /dev/null +++ b/Sources/justMUSIC/lib/screens/forget_password_screen.dart @@ -0,0 +1,234 @@ +import 'dart:async'; + +import 'package:auto_size_text/auto_size_text.dart'; +import 'package:firebase_auth/firebase_auth.dart'; +import 'package:flutter/Material.dart'; +import 'package:flutter_screenutil/flutter_screenutil.dart'; +import 'package:google_fonts/google_fonts.dart'; + +import '../components/login_button.dart'; +import '../values/constants.dart'; + +class ForgetPasswordScreen extends StatefulWidget { + const ForgetPasswordScreen({Key? key}) : super(key: key); + + @override + State createState() => _ForgetPasswordScreenState(); +} + +class _ForgetPasswordScreenState extends State { + bool canResendEmail = true; + Timer? timer; + final _formKey = GlobalKey(); + final _mailTextField = TextEditingController(); + + @override + void dispose() { + timer?.cancel(); + + super.dispose(); + } + + Future sendForgetPasswordEmail() async { + if (_formKey.currentState!.validate()) { + var error; + try { + await FirebaseAuth.instance + .sendPasswordResetEmail(email: _mailTextField.text); + ScaffoldMessenger.of(context).showSnackBar( + SnackBar( + content: Text( + "Un e-mail de réinitialisation a été envoyé. Veuillez patienter pendant 30 secondes avant la prochaine utilisation.", + style: GoogleFonts.plusJakartaSans( + color: Colors.white, + fontWeight: FontWeight.w400, + fontSize: 15.h), + ), + backgroundColor: primaryColor, + ), + ); + setState(() => canResendEmail = false); + await Future.delayed(Duration(minutes: 1)); + setState(() => canResendEmail = true); + } on FirebaseAuthException catch (e) { + if (e.code == "invalid-email") { + error = "Mail incorrect"; + } else if (e.code == "user-not-found") { + error = "Format de mail incorrect"; + } else if (e.code == "too-many-requests") { + error = + "Trop de tentatives. Veuillez réessayer plus tard"; + } + ScaffoldMessenger.of(context).showSnackBar( + SnackBar( + content: Text( + error, + style: GoogleFonts.plusJakartaSans( + color: Colors.white, + fontWeight: FontWeight.w400, + fontSize: 20.h), + ), + backgroundColor: Colors.red, + ), + ); + } + } + } + + @override + Widget build(BuildContext context) { + return Scaffold( + backgroundColor: bgColor, + body: Form( + key: _formKey, + child: Stack( + children: [ + SingleChildScrollView( + child: SizedBox( + width: double.infinity, + child: Column( + children: [ + Padding( + padding: EdgeInsets.only(top: 185.h), + child: Align( + child: SizedBox( + width: 56.h, + child: Image( + image: AssetImage( + "assets/images/key_icon.png")), + ), + )), + Padding( + padding: EdgeInsets.only(top: 28.h), + child: AutoSizeText( + "Mot de passe oublié", + style: GoogleFonts.plusJakartaSans( + color: Colors.white, + fontWeight: FontWeight.w600, + fontSize: 24.w), + maxLines: 1, + maxFontSize: 30, + overflow: TextOverflow.fade, + ), + ), + Padding( + padding: + EdgeInsets.symmetric(horizontal: defaultPadding), + child: Padding( + padding: EdgeInsets.only(bottom: 20.h), + child: Column( + mainAxisAlignment: MainAxisAlignment.end, + children: [ + SizedBox( + height: 15.h, + ), + SizedBox( + width: 346.h, + child: AutoSizeText( + "Afin de procéder à la récupération de votre mot de passe, veuillez renseigner votre adresse mail correspondant a votre compte JustMusic.", + style: GoogleFonts.plusJakartaSans( + color: Colors.white, + fontWeight: FontWeight.w100, + fontSize: 16.w), + maxFontSize: 20, + textAlign: TextAlign.center, + ), + ), + ], + ), + ), + ), + ConstrainedBox( + constraints: BoxConstraints(maxWidth: 600), + child: Column( + mainAxisAlignment: MainAxisAlignment.start, + children: [ + Padding( + padding: EdgeInsets.only( + bottom: 68.h, + left: defaultPadding, + right: defaultPadding), + child: TextFormField( + controller: _mailTextField, + keyboardAppearance: Brightness.dark, + validator: (value) { + if (value == null || value.isEmpty) { + return 'entrez un email valide'; + } + return null; + }, + cursorColor: primaryColor, + keyboardType: + TextInputType.emailAddress, + style: GoogleFonts.plusJakartaSans( + color: primaryColor), + decoration: InputDecoration( + focusedBorder: OutlineInputBorder( + borderSide: BorderSide( + width: 1, + color: strokeTextField), + borderRadius: BorderRadius.all( + Radius.circular(10))), + prefix: const Padding( + padding: EdgeInsets.only( + left: 20.0)), + suffix: const Padding( + padding: EdgeInsets.only( + left: 20.0)), + fillColor: bgTextField, + filled: true, + focusColor: Color.fromRGBO( + 255, 255, 255, 0.30), + enabledBorder: OutlineInputBorder( + borderSide: BorderSide( + width: 1, + color: strokeTextField), + borderRadius: BorderRadius.all( + Radius.circular(10))), + hintText: 'Email', + hintStyle: GoogleFonts.plusJakartaSans(color: strokeTextField)), + )), + Padding( + padding: EdgeInsets.symmetric( + horizontal: defaultPadding), + child: SizedBox( + width: 600, + child: LoginButton( + callback: () { + canResendEmail + ? sendForgetPasswordEmail() + : null; + }, + text: "Envoyer", + )), + ), + ])), + Align( + child: GestureDetector( + behavior: HitTestBehavior.translucent, + onTap: () { + Navigator.pushNamed(context, '/login'); + }, + child: Padding( + padding: EdgeInsets.only(top: 101), + child: RichText( + textAlign: TextAlign.center, + text: TextSpan( + text: 'Revenir a l’étape précédente', + style: GoogleFonts.plusJakartaSans( + fontSize: 15, + fontWeight: FontWeight.w400, + color: primaryColor), + ), + ), + ), + ), + ), + ], + ), + ), + ), + ], + ))); + } +} diff --git a/Sources/justMUSIC/lib/screens/login_screen.dart b/Sources/justMUSIC/lib/screens/login_screen.dart index 0cbddf1..10d3be2 100644 --- a/Sources/justMUSIC/lib/screens/login_screen.dart +++ b/Sources/justMUSIC/lib/screens/login_screen.dart @@ -1,4 +1,3 @@ -import 'package:firebase_auth/firebase_auth.dart'; import 'package:flutter/cupertino.dart'; import 'package:flutter/material.dart'; import 'package:flutter/services.dart'; @@ -27,14 +26,18 @@ class _LoginScreenState extends State { handleLogin() async { if (_formKey.currentState!.validate()) { try { - await MyApp.userViewModel.login(_userMailTextField.text, _passwordTextField.text); + await MyApp.userViewModel + .login(_userMailTextField.text, _passwordTextField.text); Navigator.pushNamed(context, '/feed'); } catch (e) { ScaffoldMessenger.of(context).showSnackBar( SnackBar( content: Text( - e.toString() ?? "", - style: GoogleFonts.plusJakartaSans(color: Colors.white, fontWeight: FontWeight.w400, fontSize: 20.h), + e.toString(), + style: GoogleFonts.plusJakartaSans( + color: Colors.white, + fontWeight: FontWeight.w400, + fontSize: 20.h), ), backgroundColor: Colors.red, ), @@ -63,19 +66,25 @@ class _LoginScreenState extends State { child: Form( key: _formKey, child: Column( - crossAxisAlignment: CrossAxisAlignment.center, + crossAxisAlignment: + CrossAxisAlignment.center, children: [ Flexible( flex: 4, child: Padding( padding: EdgeInsets.only(bottom: 60), child: Column( - mainAxisAlignment: MainAxisAlignment.end, + mainAxisAlignment: + MainAxisAlignment.end, children: [ Text( "Te revoilà!", - style: GoogleFonts.plusJakartaSans( - color: Colors.white, fontWeight: FontWeight.w600, fontSize: 38.h), + style: + GoogleFonts.plusJakartaSans( + color: Colors.white, + fontWeight: + FontWeight.w600, + fontSize: 38.h), ), SizedBox( height: 10, @@ -84,8 +93,12 @@ class _LoginScreenState extends State { width: 230.w, child: Text( "Bon retour parmis nous tu nous as manqué!", - style: GoogleFonts.plusJakartaSans( - color: Colors.white, fontWeight: FontWeight.w400, fontSize: 20.h), + style: GoogleFonts + .plusJakartaSans( + color: Colors.white, + fontWeight: + FontWeight.w400, + fontSize: 20.h), textAlign: TextAlign.center, ), ), @@ -96,33 +109,51 @@ class _LoginScreenState extends State { Expanded( flex: 5, child: Column( - crossAxisAlignment: CrossAxisAlignment.end, - mainAxisAlignment: MainAxisAlignment.center, + crossAxisAlignment: + CrossAxisAlignment.end, + mainAxisAlignment: + MainAxisAlignment.center, children: [ TextFormField( controller: _userMailTextField, - keyboardAppearance: Brightness.dark, + keyboardAppearance: + Brightness.dark, validator: (value) { - if (value == null || value.isEmpty) { + if (value == null || + value.isEmpty) { return 'entrez un email valide'; } return null; }, cursorColor: primaryColor, - keyboardType: TextInputType.emailAddress, - style: GoogleFonts.plusJakartaSans(color: primaryColor), + keyboardType: + TextInputType.emailAddress, + style: + GoogleFonts.plusJakartaSans( + color: primaryColor), decoration: InputDecoration( focusedBorder: OutlineInputBorder( - borderSide: BorderSide(width: 1, color: strokeTextField), - borderRadius: BorderRadius.all(Radius.circular(10))), - prefix: const Padding(padding: EdgeInsets.only(left: 20.0)), - suffix: const Padding(padding: EdgeInsets.only(left: 20.0)), + borderSide: BorderSide( + width: 1, + color: + strokeTextField), + borderRadius: BorderRadius.all( + Radius.circular(10))), + prefix: const Padding( + padding: EdgeInsets.only( + left: 20.0)), + suffix: const Padding( + padding: EdgeInsets.only( + left: 20.0)), fillColor: bgTextField, filled: true, - errorStyle: TextStyle(fontSize: 9, height: 0.3), - focusColor: Color.fromRGBO(255, 255, 255, 0.30), + errorStyle: TextStyle( + fontSize: 9, height: 0.3), + focusColor: Color.fromRGBO( + 255, 255, 255, 0.30), enabledBorder: OutlineInputBorder( - borderSide: BorderSide(width: 1, color: strokeTextField), + borderSide: + BorderSide(width: 1, color: strokeTextField), borderRadius: BorderRadius.all(Radius.circular(10))), hintText: 'Email', hintStyle: GoogleFonts.plusJakartaSans(color: strokeTextField)), @@ -132,31 +163,55 @@ class _LoginScreenState extends State { ), TextFormField( controller: _passwordTextField, - keyboardAppearance: Brightness.dark, + keyboardAppearance: + Brightness.dark, obscureText: passenable, validator: (value) { - if (value == null || value.isEmpty) { + if (value == null || + value.isEmpty) { return 'entrez un mot de passe valide'; } return null; }, cursorColor: primaryColor, - style: GoogleFonts.plusJakartaSans(color: primaryColor), + style: + GoogleFonts.plusJakartaSans( + color: primaryColor), decoration: InputDecoration( - focusedBorder: OutlineInputBorder( - borderSide: BorderSide(width: 1, color: strokeTextField), - borderRadius: BorderRadius.all(Radius.circular(10))), + focusedBorder: + OutlineInputBorder( + borderSide: BorderSide( + width: 1, + color: + strokeTextField), + borderRadius: + BorderRadius.all( + Radius.circular( + 10))), fillColor: bgTextField, filled: true, - focusColor: Color.fromRGBO(255, 255, 255, 0.30), - enabledBorder: OutlineInputBorder( - borderSide: BorderSide(width: 1, color: strokeTextField), - borderRadius: BorderRadius.all(Radius.circular(10))), + focusColor: Color.fromRGBO( + 255, 255, 255, 0.30), + enabledBorder: + OutlineInputBorder( + borderSide: BorderSide( + width: 1, + color: + strokeTextField), + borderRadius: + BorderRadius.all( + Radius.circular( + 10))), hintText: 'Mot de passe', - hintStyle: GoogleFonts.plusJakartaSans(color: strokeTextField), - prefix: const Padding(padding: EdgeInsets.only(left: 20.0)), + hintStyle: + GoogleFonts.plusJakartaSans( + color: strokeTextField), + prefix: const Padding( + padding: EdgeInsets.only( + left: 20.0)), suffixIcon: Container( - padding: EdgeInsets.only(right: 10), + padding: EdgeInsets.only( + right: 10), margin: EdgeInsets.all(5), height: 3, child: InkWell( @@ -170,25 +225,40 @@ class _LoginScreenState extends State { }); }, // Image tapped - splashColor: Colors.white10, + splashColor: + Colors.white10, // Splash color over image child: Image( image: passenable - ? AssetImage("assets/images/show_icon.png") - : AssetImage("assets/images/hide_icon.png"), + ? AssetImage( + "assets/images/show_icon.png") + : AssetImage( + "assets/images/hide_icon.png"), height: 2, ), )), - errorStyle: TextStyle(fontSize: 9, height: 0.3), - ), - ), - Padding( - padding: EdgeInsets.only(top: 10), - child: Text( - "Mot de passe oublié?", - style: GoogleFonts.plusJakartaSans(color: Colors.white), + errorStyle: TextStyle( + fontSize: 9, height: 0.3), ), ), + GestureDetector( + behavior: + HitTestBehavior.translucent, + onTap: () { + Navigator.pushNamed( + context, '/forgetPassword'); + }, + child: Padding( + padding: + EdgeInsets.only(top: 10), + child: Text( + "Mot de passe oublié?", + style: GoogleFonts + .plusJakartaSans( + color: + Colors.white), + ), + )), SizedBox( height: defaultPadding, ), @@ -196,30 +266,44 @@ class _LoginScreenState extends State { width: 600, child: LoginButton( callback: handleLogin, + text: "Se connecter", )), Align( child: GestureDetector( - behavior: HitTestBehavior.translucent, + behavior: + HitTestBehavior.translucent, onTap: () { - Navigator.pushNamed(context, '/register'); + Navigator.pushNamed( + context, '/register'); }, child: Padding( - padding: EdgeInsets.only(top: 20), + padding: + EdgeInsets.only(top: 20), child: RichText( textAlign: TextAlign.center, text: TextSpan( - text: 'Pas encore inscrit?', - style: GoogleFonts.plusJakartaSans( - color: Colors.white, - fontWeight: FontWeight.w400, - fontSize: 15), + text: + 'Pas encore inscrit?', + style: GoogleFonts + .plusJakartaSans( + color: + Colors.white, + fontWeight: + FontWeight + .w400, + fontSize: 15), children: [ TextSpan( text: " S’inscire", - style: GoogleFonts.plusJakartaSans( - fontSize: 15, - fontWeight: FontWeight.w400, - color: primaryColor)), + style: GoogleFonts + .plusJakartaSans( + fontSize: + 15, + fontWeight: + FontWeight + .w400, + color: + primaryColor)), ], ), ), @@ -234,38 +318,55 @@ class _LoginScreenState extends State { child: Padding( padding: EdgeInsets.only(top: 20), child: Column( - mainAxisAlignment: MainAxisAlignment.start, - crossAxisAlignment: CrossAxisAlignment.center, + mainAxisAlignment: + MainAxisAlignment.start, + crossAxisAlignment: + CrossAxisAlignment.center, children: [ ConstrainedBox( - constraints: BoxConstraints(maxWidth: 600), + constraints: BoxConstraints( + maxWidth: 600), child: Row( - mainAxisAlignment: MainAxisAlignment.spaceEvenly, + mainAxisAlignment: + MainAxisAlignment + .spaceEvenly, children: [ Expanded( child: Container( - color: Color(0xFF3D3D3D), + color: + Color(0xFF3D3D3D), height: 1, ), ), Padding( - padding: const EdgeInsets.only( - left: defaultPadding, right: defaultPadding), + padding: const EdgeInsets + .only( + left: + defaultPadding, + right: + defaultPadding), child: Text( 'Ou', - style: GoogleFonts.plusJakartaSans( - color: Colors.white, fontWeight: FontWeight.bold), + style: GoogleFonts + .plusJakartaSans( + color: Colors + .white, + fontWeight: + FontWeight + .bold), ), ), Expanded( child: Container( height: 1, - color: Color(0xFF3D3D3D), + color: + Color(0xFF3D3D3D), )), ], ), ), - SizedBox(height: defaultPadding), + SizedBox( + height: defaultPadding), SignInButton( Buttons.Google, text: "Login with Google", diff --git a/Sources/justMUSIC/lib/screens/registration_screen.dart b/Sources/justMUSIC/lib/screens/registration_screen.dart index 9ff5692..9d03be5 100644 --- a/Sources/justMUSIC/lib/screens/registration_screen.dart +++ b/Sources/justMUSIC/lib/screens/registration_screen.dart @@ -36,7 +36,7 @@ class _RegistrationScreenState extends State { ScaffoldMessenger.of(context).showSnackBar( SnackBar( content: Text( - e.toString() ?? "", + e.toString(), style: GoogleFonts.plusJakartaSans(color: Colors.white, fontWeight: FontWeight.w400, fontSize: 20.h), ), backgroundColor: Colors.red, @@ -276,6 +276,7 @@ class _RegistrationScreenState extends State { width: 600, child: LoginButton( callback: handleRegister, + text: "Continuer", )), ), Align( diff --git a/Sources/justMUSIC/lib/screens/verify_email_screen.dart b/Sources/justMUSIC/lib/screens/verify_email_screen.dart index 6d964e9..63b0e16 100644 --- a/Sources/justMUSIC/lib/screens/verify_email_screen.dart +++ b/Sources/justMUSIC/lib/screens/verify_email_screen.dart @@ -75,7 +75,7 @@ class _VerifyEmailScreenState extends State { ScaffoldMessenger.of(context).showSnackBar( SnackBar( content: Text( - e.toString() ?? "", + e.toString(), style: GoogleFonts.plusJakartaSans(color: Colors.white, fontWeight: FontWeight.w400, fontSize: 20.h), ), backgroundColor: Colors.red, @@ -144,6 +144,7 @@ class _VerifyEmailScreenState extends State { width: 600, child: LoginButton( callback: checkEmailVerified, + text: "Continuer", )), ), Align(