From 1025ef60a12db821082e8ce3d29ff0ab6e4bad7f Mon Sep 17 00:00:00 2001 From: VINISTAN Date: Wed, 13 Nov 2024 19:14:41 +0530 Subject: [PATCH] Change password added --- lib/main.dart | 2 +- lib/presentation/Screens/changepassword.dart | 202 ++++++++++++++++++ .../Screens/confirm_password.dart | 174 +++++++++++++++ .../Screens/otp_verification.dart | 197 +++++++++++++++++ lib/presentation/Screens/profilepage.dart | 21 +- 5 files changed, 590 insertions(+), 6 deletions(-) create mode 100644 lib/presentation/Screens/changepassword.dart create mode 100644 lib/presentation/Screens/confirm_password.dart create mode 100644 lib/presentation/Screens/otp_verification.dart diff --git a/lib/main.dart b/lib/main.dart index 7e432d77..df1ec5b7 100644 --- a/lib/main.dart +++ b/lib/main.dart @@ -29,7 +29,7 @@ class MainApp extends StatelessWidget { Widget build(BuildContext context) { return MaterialApp( home: RegisterScreen(), - // home: ProfileScreen(), + //home: ProfileScreen(), debugShowCheckedModeBanner: false, ); } diff --git a/lib/presentation/Screens/changepassword.dart b/lib/presentation/Screens/changepassword.dart new file mode 100644 index 00000000..f4d4c18e --- /dev/null +++ b/lib/presentation/Screens/changepassword.dart @@ -0,0 +1,202 @@ + +import 'package:flutter/material.dart'; +import 'otp_verification.dart'; + +class Changepassword extends StatefulWidget { + const Changepassword({Key? key}) : super(key: key); + + @override + State createState() => _ResetPasswordScreenState(); +} + +class _ResetPasswordScreenState extends State { + final _formKey = GlobalKey(); + final _emailController = TextEditingController(); + bool _isLoading = false; + + void _handleSubmit() { + if (_formKey.currentState!.validate()) { + setState(() { + _isLoading = true; + }); + Navigator.push( + context, + MaterialPageRoute(builder: (context) => EmailVerificationScreen()), + ); + + // TODO: Implement your password reset logic here + // After API call, set _isLoading back to false + } + } + + @override + void dispose() { + _emailController.dispose(); + super.dispose(); + } + + @override + Widget build(BuildContext context) { + double screenheight = MediaQuery.of(context).size.height; + double screenwidth = MediaQuery.of(context).size.width; + return Scaffold( + backgroundColor: Colors.white, + body: SingleChildScrollView( + child: SafeArea( + child: Padding( + padding: const EdgeInsets.all(24.0), + child: Form( + key: _formKey, + child: Column( + mainAxisAlignment: MainAxisAlignment.spaceBetween, + children: [ + Column( + crossAxisAlignment: CrossAxisAlignment.start, + children: [ + Center( + child: const Text( + 'Reset Password', + style: TextStyle( + fontSize: 40, + fontWeight: FontWeight.w300, + color: Colors.black87, + ), + ), + ), + const SizedBox(height: 8), + Center( + child: const Text( + 'Please Enter Your Email Address To\nReceive a verification Code', + style: TextStyle( + fontSize: 14, + color: Colors.black87, + fontWeight: FontWeight.w400, + height: 1.5, + ), + ), + ), + const SizedBox(height: 24), + TextFormField( + controller: _emailController, + keyboardType: TextInputType.emailAddress, + decoration: InputDecoration( + hintText: 'Enter your email', + hintStyle: const TextStyle( + color: Colors.black38, + fontSize: 14, + ), + prefixIcon: const Icon( + Icons.email_outlined, + color: Colors.blue, + size: 20, + ), + filled: true, + fillColor: Colors.white, + border: OutlineInputBorder( + borderRadius: BorderRadius.circular(8), + borderSide: const BorderSide( + color: Colors.black12, + width: 1, + ), + ), + enabledBorder: OutlineInputBorder( + borderRadius: BorderRadius.circular(8), + borderSide: const BorderSide( + color: Colors.black12, + width: 1, + ), + ), + focusedBorder: OutlineInputBorder( + borderRadius: BorderRadius.circular(8), + borderSide: const BorderSide( + color: Color(0xFF8B7355), + width: 1, + ), + ), + contentPadding: const EdgeInsets.symmetric( + horizontal: 16, + vertical: 14, + ), + ), + validator: (value) { + if (value == null || value.isEmpty) { + return 'Please enter your email'; + } + if (!RegExp(r'^[\w-\.]+@([\w-]+\.)+[\w-]{2,4}$') + .hasMatch(value)) { + return 'Please enter a valid email'; + } + return null; + }, + ), + const SizedBox(height: 24), + SizedBox( + width: double.infinity, + height: 48, + child: ElevatedButton( + onPressed: _isLoading ? null : _handleSubmit, + style: ElevatedButton.styleFrom( + backgroundColor: const Color(0xFF8B7355), + foregroundColor: Colors.white, + shape: RoundedRectangleBorder( + borderRadius: BorderRadius.circular(8), + ), + elevation: 0, + ), + child: Row( + mainAxisAlignment: MainAxisAlignment.center, + children: [ + if (_isLoading) + const SizedBox( + width: 20, + height: 20, + child: CircularProgressIndicator( + color: Colors.white, + strokeWidth: 2, + ), + ) + else ...[ + const Text( + 'Send', + style: TextStyle( + fontSize: 16, + fontWeight: FontWeight.w500, + ), + ), + SizedBox(width: 2,), + Icon(Icons.arrow_forward_ios,color: Colors.white38,size: 18,), + + ], + ], + ), + ), + ), + ], + ), + SizedBox(height: screenheight/3,), + + Center( + child: Container( + height: screenheight/8, + width: screenwidth/2, + decoration: BoxDecoration( + image: DecorationImage( + image: AssetImage("assets/splash_screen/logo.png"), // Background image asset + fit: BoxFit.fill, + ), + ), + )) + ], + ), + ), + ), + ), + ), + ); + } +} + + + + + diff --git a/lib/presentation/Screens/confirm_password.dart b/lib/presentation/Screens/confirm_password.dart new file mode 100644 index 00000000..0edd45c6 --- /dev/null +++ b/lib/presentation/Screens/confirm_password.dart @@ -0,0 +1,174 @@ +import 'package:flutter/material.dart'; + +class ConfirmPassword extends StatefulWidget { + ConfirmPassword({super.key}); + + @override + State createState() => _ConfirmPasswordState(); +} + +class _ConfirmPasswordState extends State { + final _formKey = GlobalKey(); + bool _obscurePassword = true; + bool _obscureConfirmPassword = true; + String? _password; + + String? _validatePassword(String? value) { + if (value == null || value.isEmpty) { + return 'Required'; + } else if (value.length < 6) { + return 'Password must be at least 6 characters'; + } + _password = value; // Store the password for confirm password validation + return null; + } + + String? _validateConfirmPassword(String? value) { + if (value == null || value.isEmpty) { + return 'Required'; + } else if (value != _password) { + return 'Passwords do not match'; + } + return null; + } + + @override + Widget build(BuildContext context) { + double screenheight = MediaQuery.of(context).size.height; + double screenwidth = MediaQuery.of(context).size.width; + return Scaffold( + backgroundColor: Colors.white, + body: SingleChildScrollView( + child: SafeArea( + child: Form( + key: _formKey, + child: Column( + mainAxisAlignment: MainAxisAlignment.spaceAround, + children: [ + Padding( + padding: const EdgeInsets.all(24.0), + child: Column( + children: [ + SizedBox(height: screenheight/6,), + Text( + "Create New Password", + style: TextStyle( + fontSize: 24, + fontWeight: FontWeight.bold, + ), + ), + SizedBox(height: screenheight/35,), + Text( + "Your new password must de different\nform previously used password", + textAlign: TextAlign.center, + style: TextStyle( + fontSize: 16, + color: Colors.grey[600], + ), + ), + SizedBox(height: screenheight/35,), + TextFormField( + obscureText: _obscurePassword, + decoration: InputDecoration( + hintText: 'Enter your password', + prefixIcon: Icon( + Icons.lock, + color: Colors.blue, + ), + suffixIcon: IconButton( + icon: Icon( + _obscurePassword + ? Icons.visibility + : Icons.visibility_off, + color: Colors.blue, + ), + onPressed: () { + setState(() { + _obscurePassword = !_obscurePassword; + }); + }, + ), + border: OutlineInputBorder(), + ), + validator: _validatePassword, + ), + SizedBox(height: screenheight/35,), + TextFormField( + obscureText: _obscureConfirmPassword, + decoration: InputDecoration( + hintText: 'Confirm password', + prefixIcon: Icon( + Icons.lock, + color: Colors.blue, + ), + suffixIcon: IconButton( + icon: Icon( + _obscureConfirmPassword + ? Icons.visibility + : Icons.visibility_off, + color: Colors.blue, + ), + onPressed: () { + setState(() { + _obscureConfirmPassword = !_obscureConfirmPassword; + }); + }, + ), + border: OutlineInputBorder(), + ), + validator: _validateConfirmPassword, + ), + SizedBox(height: screenheight/35,), + SizedBox( + width: screenwidth/1.1, + child: ElevatedButton( + onPressed: () { + if ((_formKey.currentState?.validate() ?? false)) { + // Proceed with registration if form is valid and checkbox is checked + + } + // Add verification logic here + }, + style: ElevatedButton.styleFrom( + backgroundColor: Colors.brown[300], + padding: EdgeInsets.symmetric(horizontal: 80, vertical: 16), + shape: RoundedRectangleBorder( + borderRadius: BorderRadius.circular(10), + ), + ), + child: Row( + mainAxisAlignment: MainAxisAlignment.center, + children: [ + Text( + "Save", + style: TextStyle(fontSize: 18,color: Colors.white), + ), + SizedBox(width: 2,), + Icon(Icons.arrow_forward_ios,color: Colors.white38,size: 18,), + ], + ), + ), + ), + ], + ), + ), + SizedBox(height: screenheight/15,), + Center( + child: Container( + height: screenheight/10, + width: screenwidth/2.5, + decoration: BoxDecoration( + image: DecorationImage( + image: AssetImage("assets/splash_screen/logo.png"), // Background image asset + fit: BoxFit.fill, + ), + ), + )) + ], + ), + ), + ), + ), + ); + } +} diff --git a/lib/presentation/Screens/otp_verification.dart b/lib/presentation/Screens/otp_verification.dart new file mode 100644 index 00000000..e2fddc2b --- /dev/null +++ b/lib/presentation/Screens/otp_verification.dart @@ -0,0 +1,197 @@ +import 'dart:async'; + +import 'package:flutter/material.dart'; + +import 'confirm_password.dart'; + +class EmailVerificationScreen extends StatefulWidget { + @override + _EmailVerificationScreenState createState() => + _EmailVerificationScreenState(); +} + +class _EmailVerificationScreenState extends State { + final List _otpControllers = + List.generate(4, (_) => TextEditingController()); + int _secondsRemaining = 120; // 2 minutes timer + late Timer _timer; + + @override + void initState() { + super.initState(); + _startTimer(); + } + + void _startTimer() { + _timer = Timer.periodic(Duration(seconds: 1), (timer) { + if (_secondsRemaining > 0) { + setState(() { + _secondsRemaining--; + }); + } else { + timer.cancel(); + } + }); + } + + String get _formattedTime { + final minutes = _secondsRemaining ~/ 60; + final seconds = _secondsRemaining % 60; + return '$minutes:${seconds.toString().padLeft(2, '0')}'; + } + + @override + void dispose() { + _timer.cancel(); + for (var controller in _otpControllers) { + controller.dispose(); + } + super.dispose(); + } + + + @override + Widget build(BuildContext context) { + double screenheight = MediaQuery.of(context).size.height; + double screenwidth = MediaQuery.of(context).size.width; + return Scaffold( + backgroundColor: Colors.white, + body: SingleChildScrollView( + child: SafeArea( + child: Column( + mainAxisAlignment: MainAxisAlignment.spaceEvenly, + children: [ + Column( + children: [ + SizedBox(height: screenheight/6,), + Text( + "Verify Your Email", + style: TextStyle( + fontSize: 40, + fontWeight: FontWeight.w400, + color: Colors.black87, + ), + ), + SizedBox(height: 8), + Text( + "Please Enter the 4 digit Code Sent to\nrjosh289778@gmail.com", + textAlign: TextAlign.center, + style: TextStyle( + fontSize: 16, + color: Colors.grey[600], + ), + ), + SizedBox(height: 24), + Row( + mainAxisAlignment: MainAxisAlignment.spaceEvenly, + children: List.generate(4, (index) { + return Container( + width: 50, + height: 50, + alignment: Alignment.center, + decoration: BoxDecoration( + border: Border.all(color: Colors.grey.shade400, width: 1), + borderRadius: BorderRadius.circular(8), + ), + child: + TextField( + controller: _otpControllers[index], + keyboardType: TextInputType.number, + textAlign: TextAlign.center, + maxLength: 1, + decoration: InputDecoration( + counterText: "", + border: OutlineInputBorder( + borderRadius: BorderRadius.circular(8), + borderSide: BorderSide(color: Colors.blue, width: 2), + ), + focusedBorder: OutlineInputBorder( + borderRadius: BorderRadius.circular(8), + borderSide: BorderSide(color: Colors.blue, width: 2), + ), + ), + onChanged: (value) { + if (value.length == 1 && index < 3) { + FocusScope.of(context).nextFocus(); + } + }, + ), + ); + }), + ), + SizedBox(height: 16), + Text.rich( + TextSpan( + text: "Code Expires in ", + style: TextStyle(color: Colors.grey[600]), + children: [ + TextSpan( + text: _formattedTime, + style: TextStyle(fontWeight: FontWeight.w900,color: Colors.black87), + ), + ], + ), + ), + SizedBox(height: 5), + TextButton( + onPressed: () { + setState(() { + _secondsRemaining = 120; + _startTimer(); + }); + }, + child: Text("Resend Code",style: TextStyle(color: Colors.brown,fontWeight: FontWeight.bold),), + ), + SizedBox(height: 5), + SizedBox( + width: screenwidth/1.2, + child: ElevatedButton( + onPressed: () { + Navigator.push( + context, + MaterialPageRoute(builder: (context) => ConfirmPassword()), + ); + + // Add verification logic here + }, + style: ElevatedButton.styleFrom( + backgroundColor: Colors.brown[300], + padding: EdgeInsets.symmetric(horizontal: 80, vertical: 16), + shape: RoundedRectangleBorder( + borderRadius: BorderRadius.circular(8), + ), + ), + child: Row( + mainAxisAlignment: MainAxisAlignment.center, + children: [ + Text( + "Verify", + style: TextStyle(fontSize: 18,color: Colors.white), + ), + SizedBox(width: 3,), + Icon(Icons.arrow_forward_ios,color: Colors.white38,size: 18,), + ], + ), + ), + ), + ], + ), + SizedBox(height: screenheight/6,), + Center( + child: Container( + height: screenheight/8, + width: screenwidth/2, + decoration: BoxDecoration( + image: DecorationImage( + image: AssetImage("assets/splash_screen/logo.png"), // Background image asset + fit: BoxFit.fill, + ), + ), + )) + ], + ), + ), + ), + ); + } +} \ No newline at end of file diff --git a/lib/presentation/Screens/profilepage.dart b/lib/presentation/Screens/profilepage.dart index a7efcfdd..f39ca581 100644 --- a/lib/presentation/Screens/profilepage.dart +++ b/lib/presentation/Screens/profilepage.dart @@ -8,6 +8,8 @@ import 'package:image_picker/image_picker.dart'; import 'package:intl/intl.dart'; import 'package:pocketbase/pocketbase.dart'; +import 'changepassword.dart'; + class ProfileScreen extends StatefulWidget { @override State createState() => _ProfileScreenState(); @@ -527,11 +529,20 @@ class _ProfileScreenState extends State { SizedBox(height: 20), Center( - child: Text( - "Change Password", - style: TextStyle( - color: Colors.blue, - decoration: TextDecoration.underline), + child: GestureDetector( + onTap: (){ + Navigator.push( + context, + MaterialPageRoute(builder: (context) => Changepassword()), + ); + + }, + child: Text( + "Change Password", + style: TextStyle( + color: Colors.blue, + decoration: TextDecoration.underline), + ), ), ), SizedBox(height: 20),