diff --git a/assets/images/Password_invisible.svg b/assets/images/Password_invisible.svg new file mode 100644 index 00000000..bb190eb3 --- /dev/null +++ b/assets/images/Password_invisible.svg @@ -0,0 +1,3 @@ + + + diff --git a/assets/images/password_visible.svg b/assets/images/password_visible.svg new file mode 100644 index 00000000..25c55434 --- /dev/null +++ b/assets/images/password_visible.svg @@ -0,0 +1,3 @@ + + + diff --git a/lib/main.dart b/lib/main.dart index 629a8725..6fbc2cb1 100644 --- a/lib/main.dart +++ b/lib/main.dart @@ -1,8 +1,7 @@ import 'package:flutter/gestures.dart'; import 'package:flutter/material.dart'; -import 'package:syncrow_web/pages/auth/login/view/login_page.dart'; +import 'package:syncrow_web/pages/auth/view/login_page.dart'; import 'package:syncrow_web/services/locator.dart'; - void main() { WidgetsFlutterBinding.ensureInitialized(); initialSetup(); diff --git a/lib/pages/auth/login/bloc/login_bloc.dart b/lib/pages/auth/bloc/auth_bloc.dart similarity index 59% rename from lib/pages/auth/login/bloc/login_bloc.dart rename to lib/pages/auth/bloc/auth_bloc.dart index 080dfd01..f6931e7b 100644 --- a/lib/pages/auth/login/bloc/login_bloc.dart +++ b/lib/pages/auth/bloc/auth_bloc.dart @@ -1,28 +1,104 @@ +import 'dart:async'; import 'package:flutter/foundation.dart'; import 'package:flutter/material.dart'; import 'package:flutter_bloc/flutter_bloc.dart'; import 'package:flutter_secure_storage/flutter_secure_storage.dart'; -import 'package:syncrow_web/pages/auth/login/bloc/login_event.dart'; -import 'package:syncrow_web/pages/auth/login/bloc/login_state.dart'; -import 'package:syncrow_web/pages/auth/login/model/login_with_email_model.dart'; -import 'package:syncrow_web/pages/auth/login/model/token.dart'; -import 'package:syncrow_web/pages/auth/login/model/user_model.dart'; +import 'package:syncrow_web/pages/auth/bloc/auth_event.dart'; +import 'package:syncrow_web/pages/auth/bloc/auth_state.dart'; +import 'package:syncrow_web/pages/auth/model/login_with_email_model.dart'; +import 'package:syncrow_web/pages/auth/model/token.dart'; +import 'package:syncrow_web/pages/auth/model/user_model.dart'; import 'package:syncrow_web/services/auth_api.dart'; import 'package:syncrow_web/utils/snack_bar.dart'; -class LoginBloc extends Bloc { - LoginBloc() : super(LoginInitial()) { +class AuthBloc extends Bloc { + AuthBloc() : super(LoginInitial()) { on(_login); - on(checkBoxTgl); + on(checkBoxToggle); + on(changePassword); + on(_onStartTimer); + on(_onStopTimer); + on(_onUpdateTimer); + on(_passwordVisible); + } - final TextEditingController emailController = TextEditingController(); - final TextEditingController passwordController = TextEditingController(); - final formKey = GlobalKey(); - bool isChecked = false; - bool obscureText = true; - _login(LoginButtonPressed event, Emitter emit) async { +////////////////////////////// forget password ////////////////////////////////// + final TextEditingController forgetEmailController = TextEditingController(); + final TextEditingController forgetPasswordController = TextEditingController(); + final TextEditingController forgetOtp = TextEditingController(); + final forgetFormKey = GlobalKey(); + + Timer? _timer; + int _remainingTime = 0; + + Future _onStartTimer(StartTimerEvent event, Emitter emit) async { + if (_validateInputs(emit)) return; + print("StartTimerEvent received"); + if (_timer != null && _timer!.isActive) { + print("Timer is already active"); + return; + } + _remainingTime = 60; + add(UpdateTimerEvent( + remainingTime: _remainingTime, isButtonEnabled: false)); + print("Timer started, initial remaining time: $_remainingTime"); + await AuthenticationAPI.sendOtp(email: forgetEmailController.text); + _timer = Timer.periodic(const Duration(seconds: 1), (timer) { + _remainingTime--; + print("Timer tick, remaining time: $_remainingTime"); // Debug print + if (_remainingTime <= 0) { + _timer?.cancel(); + add(const UpdateTimerEvent(remainingTime: 0, isButtonEnabled: true)); + print("Timer finished"); // Debug print + } else { + add(UpdateTimerEvent(remainingTime: _remainingTime, isButtonEnabled: false)); + } + }); + } + + void _onStopTimer(StopTimerEvent event, Emitter emit) { + _timer?.cancel(); + emit(const TimerState(isButtonEnabled: true, remainingTime: 0)); + } + + Future changePassword( + ChangePasswordEvent event, Emitter emit) async { + try { + emit(LoadingForgetState()); + await AuthenticationAPI.forgetPassword( + password: forgetPasswordController.text, email: forgetEmailController.text); + emit(SuccessForgetState()); + } catch (failure) { + print(failure); + emit(FailureForgetState(error: failure.toString())); + } + } + + + void _onUpdateTimer(UpdateTimerEvent event, Emitter emit) { + emit(TimerState( + isButtonEnabled: event.isButtonEnabled, + remainingTime: event.remainingTime)); + } + + ///////////////////////////////////// login ///////////////////////////////////// + final TextEditingController loginEmailController = TextEditingController(); + final TextEditingController loginPasswordController = TextEditingController(); + final loginFormKey = GlobalKey(); + bool isChecked = false; + bool obscureText = false; + + String newPassword = ''; + String maskedEmail = ''; + String otpCode = ''; + + static Token token = Token.emptyConstructor(); + static UserModel? user; + bool showValidationMessage = false; + + void _login(LoginButtonPressed event, Emitter emit) async { emit(LoginLoading()); if(isChecked) { try { @@ -54,8 +130,8 @@ class LoginBloc extends Bloc { value: Token.decodeToken(token.accessToken)['uuid'].toString() ); user = UserModel.fromToken(token); - emailController.clear(); - passwordController.clear(); + loginEmailController.clear(); + loginPasswordController.clear(); emit(LoginSuccess()); } else { emit(const LoginFailure(error: 'Something went wrong')); @@ -66,12 +142,17 @@ class LoginBloc extends Bloc { } } - checkBoxTgl(CheckBoxEvent event, Emitter emit,){ + checkBoxToggle(CheckBoxEvent event, Emitter emit,){ emit(LoginLoading()); isChecked = event.newValue!; emit(LoginInitial()); } + void _passwordVisible(PasswordVisibleEvent event, Emitter emit) { + emit(LoginLoading()); + obscureText = !event.newValue!; + emit(PasswordVisibleState()); + } void launchURL(String url) { if (kDebugMode) { @@ -80,16 +161,6 @@ class LoginBloc extends Bloc { } - - String newPassword = ''; - String maskedEmail = ''; - String otpCode = ''; - - static Token token = Token.emptyConstructor(); - static UserModel? user; - - bool showValidationMessage = false; - /////////////////////////////////////VALIDATORS///////////////////////////////////// String? validatePassword(String? value) { @@ -110,8 +181,23 @@ class LoginBloc extends Bloc { return null; } + String? validateCode(String? value) { + if (value == null || value.isEmpty) { + return 'Code is required'; + } + return null; + } - + bool _validateInputs(Emitter emit) { + emit(LoadingForgetState()); + final nameError = validateEmail(forgetEmailController.text); + if (nameError != null) { + emit(FailureForgetState(error:nameError )) ; + // CustomSnackBar.displaySnackBar(nameError); + return true; + } + return false; + } String? validateRegion(String? value) { if (value == null || value.isEmpty) { @@ -227,7 +313,6 @@ class LoginBloc extends Bloc { return '$maskedLocalPart@$domainPart'; } - final List regions = [ 'North America', 'South America', @@ -238,31 +323,5 @@ class LoginBloc extends Bloc { 'Antarctica', ]; - // signUp() async { - // emit(LoginLoading()); - // final response; - // try { - // List userFullName = fullName.split(' '); - // response = await AuthenticationAPI.signUp( - // model: SignUpModel( - // email: email.toLowerCase(), - // password: signUpPassword, - // firstName: userFullName[0], - // lastName: userFullName[1]), - // ); - // } catch (failure) { - // emit(AuthLoginError(message: failure.toString())); - // return; - // } - // if (response) { - // maskedEmail = maskEmail(email); - // await sendOtp(); - // } else { - // emit(AuthLoginError(message: 'Something went wrong')); - // } - // } - - - } diff --git a/lib/pages/auth/bloc/auth_event.dart b/lib/pages/auth/bloc/auth_event.dart new file mode 100644 index 00000000..cdcfc51e --- /dev/null +++ b/lib/pages/auth/bloc/auth_event.dart @@ -0,0 +1,52 @@ +import 'package:equatable/equatable.dart'; + +abstract class AuthEvent extends Equatable { + const AuthEvent(); + + @override + List get props => []; +} + +class LoginButtonPressed extends AuthEvent { + final String username; + final String password; + + const LoginButtonPressed({required this.username, required this.password}); + + @override + List get props => [username, password]; +} + + +class CheckBoxEvent extends AuthEvent { + final bool? newValue; + + const CheckBoxEvent({required this.newValue,}); + + @override + List get props => [newValue!,]; +} + +class GetCodeEvent extends AuthEvent{} + +class SubmitEvent extends AuthEvent{} + +class StartTimerEvent extends AuthEvent{} + +class StopTimerEvent extends AuthEvent{} + +class UpdateTimerEvent extends AuthEvent { + final int remainingTime; + final bool isButtonEnabled; + const UpdateTimerEvent({required this.remainingTime, required this.isButtonEnabled}); +} + +class ChangePasswordEvent extends AuthEvent{} + +class SendOtpEvent extends AuthEvent{} + +class PasswordVisibleEvent extends AuthEvent{ + final bool? newValue; + + const PasswordVisibleEvent({required this.newValue,}); +} \ No newline at end of file diff --git a/lib/pages/auth/bloc/auth_state.dart b/lib/pages/auth/bloc/auth_state.dart new file mode 100644 index 00000000..d8e15d5b --- /dev/null +++ b/lib/pages/auth/bloc/auth_state.dart @@ -0,0 +1,65 @@ +import 'package:equatable/equatable.dart'; + +abstract class AuthState extends Equatable { + const AuthState(); + + @override + List get props => []; +} + +class LoginInitial extends AuthState {} + +class LoginLoading extends AuthState {} + +class LoginSuccess extends AuthState {} + +class LoginFailure extends AuthState { + final String error; + + const LoginFailure({required this.error}); + + @override + List get props => [error]; +} + +class LoginValid extends AuthState {} + +class LoginInvalid extends AuthState { + final String error; + + const LoginInvalid({required this.error}); + + @override + List get props => [error]; +} + +class InitialForgetState extends AuthState{} + +class LoadingForgetState extends AuthState{} + +class SuccessForgetState extends AuthState{} +class PasswordVisibleState extends AuthState{} + +class FailureForgetState extends AuthState { + final String error; + const FailureForgetState({required this.error}); + @override + List get props => [error]; +} + +class TimerState extends AuthState { + final bool isButtonEnabled ; + final int remainingTime; + + const TimerState({required this.isButtonEnabled, required this.remainingTime}); + + @override + List get props => [isButtonEnabled, remainingTime]; +} + + + + + + +// class AuthState extends AuthState {} diff --git a/lib/pages/auth/forget_password/bloc/forget_password_bloc.dart b/lib/pages/auth/forget_password/bloc/forget_password_bloc.dart deleted file mode 100644 index 07b61a24..00000000 --- a/lib/pages/auth/forget_password/bloc/forget_password_bloc.dart +++ /dev/null @@ -1,195 +0,0 @@ -import 'dart:async'; -import 'package:flutter/material.dart'; -import 'package:flutter_bloc/flutter_bloc.dart'; -import 'package:syncrow_web/pages/auth/forget_password/bloc/forget_password_event.dart'; -import 'package:syncrow_web/pages/auth/forget_password/bloc/forget_password_state.dart'; -import 'package:syncrow_web/services/auth_api.dart'; - -class ForgetPasswordBloc - extends Bloc { - ForgetPasswordBloc() : super(InitialForgetState()) { - on(changePassword); - on(_onStartTimer); - on(_onStopTimer); - on(_onUpdateTimer); - } - - void _onUpdateTimer(UpdateTimerEvent event, Emitter emit) { - emit(TimerState( - isButtonEnabled: event.isButtonEnabled, - remainingTime: event.remainingTime)); - } - - final TextEditingController emailController = TextEditingController(); - final TextEditingController passwordController = TextEditingController(); - final TextEditingController otp = TextEditingController(); - final formKey = GlobalKey(); - - Timer? _timer; - int _remainingTime = 0; - - Future _onStartTimer( - StartTimerEvent event, Emitter emit) async { - if (_validateInputs(emit)) return; - print("StartTimerEvent received"); - if (_timer != null && _timer!.isActive) { - print("Timer is already active"); - return; - } - _remainingTime = 60; - add(UpdateTimerEvent( - remainingTime: _remainingTime, isButtonEnabled: false)); - print("Timer started, initial remaining time: $_remainingTime"); - await AuthenticationAPI.sendOtp(email: emailController.text); - _timer = Timer.periodic(const Duration(seconds: 1), (timer) { - _remainingTime--; - print("Timer tick, remaining time: $_remainingTime"); // Debug print - if (_remainingTime <= 0) { - _timer?.cancel(); - add(const UpdateTimerEvent(remainingTime: 0, isButtonEnabled: true)); - print("Timer finished"); // Debug print - } else { - add(UpdateTimerEvent(remainingTime: _remainingTime, isButtonEnabled: false)); - } - }); - } - - void _onStopTimer(StopTimerEvent event, Emitter emit) { - _timer?.cancel(); - emit(TimerState(isButtonEnabled: true, remainingTime: 0)); - } - - Future changePassword( - ChangePasswordEvent event, Emitter emit) async { - try { - emit(LoadingForgetState()); - await AuthenticationAPI.forgetPassword( - password: passwordController.text, email: emailController.text); - emit(SuccessForgetState()); - } catch (failure) { - print(failure); - emit(FailureForgetState(error: failure.toString())); - } - } - - String? validateEmail(String? value) { - if (value == null || value.isEmpty) { - return 'Email is required'; - } else if (!RegExp(r'^[^@]+@[^@]+\.[^@]+').hasMatch(value)) { - return 'Enter a valid email address'; - } - return null; - } - - String? validateRegion(String? value) { - if (value == null || value.isEmpty) { - return 'Please select a region'; - } - return null; - } - - String? otpValidate(String? value) { - if (value == null || value.isEmpty) { - return 'Please select a region'; - } - return null; - } - - String? passwordValidator(String? value) { - if (value == null || value.isEmpty) { - return 'Please enter your password'; - } - List validationErrors = []; - if (!RegExp(r'^(?=.*[a-z])').hasMatch(value)) { - validationErrors.add(' - one lowercase letter'); - } - if (!RegExp(r'^(?=.*[A-Z])').hasMatch(value)) { - validationErrors.add(' - one uppercase letter'); - } - if (!RegExp(r'^(?=.*\d)').hasMatch(value)) { - validationErrors.add(' - one number'); - } - if (!RegExp(r'^(?=.*[@$!%*?&])').hasMatch(value)) { - validationErrors.add(' - one special character'); - } - if (value.length < 8) { - validationErrors.add(' - minimum 8 characters'); - } - if (validationErrors.isNotEmpty) { - return 'Password must contain at least:\n${validationErrors.join('\n')}'; - } - return null; - } - - final List regions = [ - 'North America', - 'South America', - 'Europe', - 'Asia', - 'Africa', - 'Australia', - 'Antarctica', - ]; - - - bool _validateInputs(Emitter emit) { - emit(LoadingForgetState()); - final nameError = validateEmail(emailController.text); - if (nameError != null) { - emit(FailureForgetState(error:nameError )) ; - // CustomSnackBar.displaySnackBar(nameError); - return true; - } - return false; - } -} - - - - - -// -// -// _login(LoginButtonPressed event, Emitter emit) async { -// emit(LoginLoading()); -// if(isChecked) { -// try { -// if (event.username.isEmpty || event.password.isEmpty) { -// CustomSnackBar.displaySnackBar('Please enter your credentials'); -// emit(const LoginFailure(error: 'Something went wrong')); -// return; -// } -// token = await AuthenticationAPI.loginWithEmail( -// model: LoginWithEmailModel( -// email: event.username, -// password: event.password, -// ), -// ); -// } -// catch (failure) { -// emit(const LoginFailure(error: 'Something went wrong')); -// // emit(LoginFailure(error: failure.toString())); -// return; -// } -// if (token.accessTokenIsNotEmpty) { -// debugPrint('token: ${token.accessToken}'); -// FlutterSecureStorage storage = const FlutterSecureStorage(); -// await storage.write( -// key: Token.loginAccessTokenKey, value: token.accessToken); -// -// const FlutterSecureStorage().write( -// key: UserModel.userUuidKey, -// value: Token.decodeToken(token.accessToken)['uuid'].toString() -// ); -// user = UserModel.fromToken(token); -// emailController.clear(); -// passwordController.clear(); -// emit(LoginSuccess()); -// } else { -// emit(const LoginFailure(error: 'Something went wrong')); -// } -// } -// else{ -// emit(const LoginFailure(error: 'Accept terms and condition')); -// } -// } diff --git a/lib/pages/auth/forget_password/bloc/forget_password_event.dart b/lib/pages/auth/forget_password/bloc/forget_password_event.dart deleted file mode 100644 index 3a42ef76..00000000 --- a/lib/pages/auth/forget_password/bloc/forget_password_event.dart +++ /dev/null @@ -1,26 +0,0 @@ - -import 'package:equatable/equatable.dart'; - -abstract class ForgetPasswordEvent extends Equatable { -const ForgetPasswordEvent(); - @override - List get props => []; -} - -class GetCodeEvent extends ForgetPasswordEvent{} - -class SubmitEvent extends ForgetPasswordEvent{} - -class StartTimerEvent extends ForgetPasswordEvent{} - -class StopTimerEvent extends ForgetPasswordEvent{} - -class UpdateTimerEvent extends ForgetPasswordEvent { - final int remainingTime; - final bool isButtonEnabled; - const UpdateTimerEvent({required this.remainingTime, required this.isButtonEnabled}); -} - -class ChangePasswordEvent extends ForgetPasswordEvent{} - -class SendOtpEvent extends ForgetPasswordEvent{} \ No newline at end of file diff --git a/lib/pages/auth/forget_password/bloc/forget_password_state.dart b/lib/pages/auth/forget_password/bloc/forget_password_state.dart deleted file mode 100644 index 28d6116b..00000000 --- a/lib/pages/auth/forget_password/bloc/forget_password_state.dart +++ /dev/null @@ -1,35 +0,0 @@ - - -import 'package:equatable/equatable.dart'; - -class ForgetPasswordState extends Equatable{ - const ForgetPasswordState(); - - @override - List get props => []; - -} - -class InitialForgetState extends ForgetPasswordState{} - -class LoadingForgetState extends ForgetPasswordState{} - -class SuccessForgetState extends ForgetPasswordState{} - -class FailureForgetState extends ForgetPasswordState { - final String error; - const FailureForgetState({required this.error}); - @override - List get props => [error]; -} - - -class TimerState extends ForgetPasswordState { - final bool isButtonEnabled ; - final int remainingTime; - - const TimerState({required this.isButtonEnabled, required this.remainingTime}); - - @override - List get props => [isButtonEnabled, remainingTime]; -} \ No newline at end of file diff --git a/lib/pages/auth/login/bloc/login_event.dart b/lib/pages/auth/login/bloc/login_event.dart deleted file mode 100644 index 7bfdb1bc..00000000 --- a/lib/pages/auth/login/bloc/login_event.dart +++ /dev/null @@ -1,28 +0,0 @@ -import 'package:equatable/equatable.dart'; - -abstract class LoginEvent extends Equatable { - const LoginEvent(); - - @override - List get props => []; -} - -class LoginButtonPressed extends LoginEvent { - final String username; - final String password; - - const LoginButtonPressed({required this.username, required this.password}); - - @override - List get props => [username, password]; -} - - -class CheckBoxEvent extends LoginEvent { - final bool? newValue; - - const CheckBoxEvent({required this.newValue,}); - - @override - List get props => [newValue!,]; -} diff --git a/lib/pages/auth/login/bloc/login_state.dart b/lib/pages/auth/login/bloc/login_state.dart deleted file mode 100644 index f82d12a5..00000000 --- a/lib/pages/auth/login/bloc/login_state.dart +++ /dev/null @@ -1,39 +0,0 @@ -import 'package:equatable/equatable.dart'; - -abstract class LoginState extends Equatable { - const LoginState(); - - @override - List get props => []; -} - -class LoginInitial extends LoginState {} - -class LoginLoading extends LoginState {} - -class LoginSuccess extends LoginState {} - -class LoginFailure extends LoginState { - final String error; - - const LoginFailure({required this.error}); - - @override - List get props => [error]; -} - - - -class LoginValid extends LoginState {} - -class LoginInvalid extends LoginState { - final String error; - - const LoginInvalid({required this.error}); - - @override - List get props => [error]; -} - - -// class LoginState extends LoginState {} diff --git a/lib/pages/auth/login/model/login_with_email_model.dart b/lib/pages/auth/model/login_with_email_model.dart similarity index 100% rename from lib/pages/auth/login/model/login_with_email_model.dart rename to lib/pages/auth/model/login_with_email_model.dart diff --git a/lib/pages/auth/login/model/signup_model.dart b/lib/pages/auth/model/signup_model.dart similarity index 100% rename from lib/pages/auth/login/model/signup_model.dart rename to lib/pages/auth/model/signup_model.dart diff --git a/lib/pages/auth/login/model/token.dart b/lib/pages/auth/model/token.dart similarity index 100% rename from lib/pages/auth/login/model/token.dart rename to lib/pages/auth/model/token.dart diff --git a/lib/pages/auth/login/model/user_model.dart b/lib/pages/auth/model/user_model.dart similarity index 95% rename from lib/pages/auth/login/model/user_model.dart rename to lib/pages/auth/model/user_model.dart index 44bc6b0d..674eee9a 100644 --- a/lib/pages/auth/login/model/user_model.dart +++ b/lib/pages/auth/model/user_model.dart @@ -1,5 +1,6 @@ -import 'package:syncrow_web/pages/auth/login/model/token.dart'; + +import 'package:syncrow_web/pages/auth/model/token.dart'; class UserModel { static String userUuidKey = 'userUuid'; diff --git a/lib/pages/auth/login/model/verify_code.dart b/lib/pages/auth/model/verify_code.dart similarity index 100% rename from lib/pages/auth/login/model/verify_code.dart rename to lib/pages/auth/model/verify_code.dart diff --git a/lib/pages/auth/forget_password/view/forget_password_mobile_page.dart b/lib/pages/auth/view/forget_password_mobile_page.dart similarity index 100% rename from lib/pages/auth/forget_password/view/forget_password_mobile_page.dart rename to lib/pages/auth/view/forget_password_mobile_page.dart diff --git a/lib/pages/auth/forget_password/view/forget_password_page.dart b/lib/pages/auth/view/forget_password_page.dart similarity index 67% rename from lib/pages/auth/forget_password/view/forget_password_page.dart rename to lib/pages/auth/view/forget_password_page.dart index a80d515a..da09a888 100644 --- a/lib/pages/auth/forget_password/view/forget_password_page.dart +++ b/lib/pages/auth/view/forget_password_page.dart @@ -1,8 +1,7 @@ import 'package:flutter/material.dart'; -import 'package:syncrow_web/pages/auth/forget_password/view/forget_password_mobile_page.dart'; -import 'package:syncrow_web/pages/auth/forget_password/view/forget_password_web_page.dart'; - +import 'package:syncrow_web/pages/auth/view/forget_password_mobile_page.dart'; +import 'package:syncrow_web/pages/auth/view/forget_password_web_page.dart'; import 'package:syncrow_web/utils/responsive_layout.dart'; diff --git a/lib/pages/auth/forget_password/view/forget_password_web_page.dart b/lib/pages/auth/view/forget_password_web_page.dart similarity index 91% rename from lib/pages/auth/forget_password/view/forget_password_web_page.dart rename to lib/pages/auth/view/forget_password_web_page.dart index 2d65c201..c62541f5 100644 --- a/lib/pages/auth/forget_password/view/forget_password_web_page.dart +++ b/lib/pages/auth/view/forget_password_web_page.dart @@ -1,10 +1,9 @@ import 'package:flutter/material.dart'; import 'package:flutter_bloc/flutter_bloc.dart'; import 'package:flutter_svg/flutter_svg.dart'; -import 'package:syncrow_web/pages/auth/forget_password/bloc/forget_password_bloc.dart'; -import 'package:syncrow_web/pages/auth/forget_password/bloc/forget_password_event.dart'; -import 'package:syncrow_web/pages/auth/forget_password/bloc/forget_password_state.dart'; -import 'package:syncrow_web/pages/auth/login/view/login_page.dart'; +import 'package:syncrow_web/pages/auth/bloc/auth_bloc.dart'; +import 'package:syncrow_web/pages/auth/bloc/auth_event.dart'; +import 'package:syncrow_web/pages/auth/bloc/auth_state.dart'; import 'package:syncrow_web/pages/common/default_button.dart'; import 'package:syncrow_web/pages/common/first_layer.dart'; import 'package:syncrow_web/utils/color_manager.dart'; @@ -18,8 +17,8 @@ class ForgetPasswordWebPage extends StatelessWidget { Widget build(BuildContext context) { return Scaffold( body: BlocProvider( - create: (context) => ForgetPasswordBloc(), - child: BlocConsumer( + create: (context) => AuthBloc(), + child: BlocConsumer( listener: (context, state) { if (state is LoadingForgetState) { } else if (state is FailureForgetState) { @@ -42,8 +41,8 @@ class ForgetPasswordWebPage extends StatelessWidget { ); } - Widget _buildForm(BuildContext context, ForgetPasswordState state) { - final forgetBloc = BlocProvider.of(context); + Widget _buildForm(BuildContext context, AuthState state) { + final forgetBloc = BlocProvider.of(context); return FirstLayer( second: Container( margin: const EdgeInsets.all(50), @@ -74,7 +73,7 @@ class ForgetPasswordWebPage extends StatelessWidget { border: Border.all(color: ColorsManager.graysColor.withOpacity(0.2)), ), child: Form( - key: forgetBloc.formKey, + key: forgetBloc.forgetFormKey, child: Padding( padding: const EdgeInsets.symmetric(horizontal: 50, vertical: 20), child: Column( @@ -147,7 +146,7 @@ class ForgetPasswordWebPage extends StatelessWidget { width: MediaQuery.sizeOf(context).width * 0.2, child: TextFormField( validator: forgetBloc.validateEmail, - controller: forgetBloc.emailController, + controller: forgetBloc.forgetEmailController, decoration: textBoxDecoration()!.copyWith(hintText: 'Enter your email'), style: const TextStyle(color: Colors.black), ), @@ -164,9 +163,9 @@ class ForgetPasswordWebPage extends StatelessWidget { SizedBox( width: MediaQuery.sizeOf(context).width * 0.2, child: TextFormField( - validator: forgetBloc.otpValidate, + validator: forgetBloc.validateCode, keyboardType: TextInputType.visiblePassword, - controller: forgetBloc.otp, + controller: forgetBloc.forgetOtp, decoration: textBoxDecoration()!.copyWith( hintText: 'Enter Code', suffixIcon: SizedBox( @@ -174,7 +173,7 @@ class ForgetPasswordWebPage extends StatelessWidget { child: Center( child: InkWell( onTap: () { - BlocProvider.of(context).add(StartTimerEvent()); + BlocProvider.of(context).add(StartTimerEvent()); }, child: Text( 'Get Code ${state is TimerState && !state.isButtonEnabled ? "(${state.remainingTime.toString()})" : ""}', @@ -205,7 +204,7 @@ class ForgetPasswordWebPage extends StatelessWidget { child: TextFormField( validator: forgetBloc.passwordValidator, keyboardType: TextInputType.visiblePassword, - controller: forgetBloc.passwordController, + controller: forgetBloc.forgetPasswordController, decoration: textBoxDecoration()!.copyWith( hintText: 'At least 8 characters', ), @@ -224,7 +223,7 @@ class ForgetPasswordWebPage extends StatelessWidget { backgroundColor: ColorsManager.btnColor, child: const Text('Submit'), onPressed: () { - if (forgetBloc.formKey.currentState!.validate()) { + if (forgetBloc.forgetFormKey.currentState!.validate()) { forgetBloc.add(ChangePasswordEvent()); } }, diff --git a/lib/pages/auth/login/view/login_mobile_page.dart b/lib/pages/auth/view/login_mobile_page.dart similarity index 95% rename from lib/pages/auth/login/view/login_mobile_page.dart rename to lib/pages/auth/view/login_mobile_page.dart index b1dff73b..7b52400a 100644 --- a/lib/pages/auth/login/view/login_mobile_page.dart +++ b/lib/pages/auth/view/login_mobile_page.dart @@ -3,10 +3,10 @@ import 'package:flutter/gestures.dart'; import 'package:flutter/material.dart'; import 'package:flutter_bloc/flutter_bloc.dart'; import 'package:flutter_svg/svg.dart'; -import 'package:syncrow_web/pages/auth/forget_password/view/forget_password_page.dart'; -import 'package:syncrow_web/pages/auth/login/bloc/login_bloc.dart'; -import 'package:syncrow_web/pages/auth/login/bloc/login_event.dart'; -import 'package:syncrow_web/pages/auth/login/bloc/login_state.dart'; +import 'package:syncrow_web/pages/auth/bloc/auth_bloc.dart'; +import 'package:syncrow_web/pages/auth/bloc/auth_event.dart'; +import 'package:syncrow_web/pages/auth/bloc/auth_state.dart'; +import 'package:syncrow_web/pages/auth/view/forget_password_page.dart'; import 'package:syncrow_web/pages/common/default_button.dart'; import 'package:syncrow_web/utils/color_manager.dart'; import 'package:syncrow_web/utils/constants/assets.dart'; @@ -20,8 +20,8 @@ class LoginMobilePage extends StatelessWidget { Widget build(BuildContext context) { return Scaffold( body: BlocProvider( - create: (context) => LoginBloc(), - child: BlocConsumer( + create: (context) => AuthBloc(), + child: BlocConsumer( listener: (context, state) { if (state is LoginSuccess) { // Navigate to home screen after successful login @@ -51,7 +51,7 @@ class LoginMobilePage extends StatelessWidget { } Widget _buildLoginForm(BuildContext context) { - final loginBloc = BlocProvider.of(context); + final loginBloc = BlocProvider.of(context); final TextEditingController _usernameController = TextEditingController(); final TextEditingController _passwordController = TextEditingController(); return Center( @@ -108,7 +108,7 @@ class LoginMobilePage extends StatelessWidget { color: ColorsManager.graysColor.withOpacity(0.2))), child: Form( - key: loginBloc.formKey, + key: loginBloc.loginFormKey, child: Column( mainAxisAlignment: MainAxisAlignment.spaceEvenly, crossAxisAlignment: CrossAxisAlignment.start, @@ -174,7 +174,7 @@ class LoginMobilePage extends StatelessWidget { SizedBox( child: TextFormField( validator: loginBloc.validateEmail, - controller: loginBloc.emailController, + controller: loginBloc.loginEmailController, decoration: textBoxDecoration()! .copyWith(hintText: 'Enter your email'), style: const TextStyle(color: Colors.black), @@ -196,7 +196,7 @@ class LoginMobilePage extends StatelessWidget { validator: loginBloc.validatePassword, obscureText: loginBloc.obscureText, keyboardType: TextInputType.visiblePassword, - controller: loginBloc.passwordController, + controller: loginBloc.loginPasswordController, decoration: textBoxDecoration()!.copyWith( hintText: 'At least 8 characters', ), @@ -297,14 +297,14 @@ class LoginMobilePage extends StatelessWidget { : ColorsManager.grayColor, child: const Text('Sign in'), onPressed: () { - if (loginBloc.formKey.currentState! + if (loginBloc.loginFormKey.currentState! .validate()) { loginBloc.add( LoginButtonPressed( username: - loginBloc.emailController.text, + loginBloc.loginEmailController.text, password: - loginBloc.passwordController.text, + loginBloc.loginPasswordController.text, ), ); } diff --git a/lib/pages/auth/login/view/login_page.dart b/lib/pages/auth/view/login_page.dart similarity index 74% rename from lib/pages/auth/login/view/login_page.dart rename to lib/pages/auth/view/login_page.dart index 8000aabf..d5644b5e 100644 --- a/lib/pages/auth/login/view/login_page.dart +++ b/lib/pages/auth/view/login_page.dart @@ -1,8 +1,8 @@ import 'package:flutter/cupertino.dart'; import 'package:flutter/material.dart'; import 'package:flutter/widgets.dart'; -import 'package:syncrow_web/pages/auth/login/view/login_mobile_page.dart'; -import 'package:syncrow_web/pages/auth/login/view/login_web_page.dart'; +import 'package:syncrow_web/pages/auth/view/login_mobile_page.dart'; +import 'package:syncrow_web/pages/auth/view/login_web_page.dart'; import 'package:syncrow_web/utils/responsive_layout.dart'; class LoginPage extends StatelessWidget { diff --git a/lib/pages/auth/login/view/login_web_page.dart b/lib/pages/auth/view/login_web_page.dart similarity index 86% rename from lib/pages/auth/login/view/login_web_page.dart rename to lib/pages/auth/view/login_web_page.dart index e74266b5..81a38322 100644 --- a/lib/pages/auth/login/view/login_web_page.dart +++ b/lib/pages/auth/view/login_web_page.dart @@ -4,10 +4,10 @@ import 'package:flutter/material.dart'; import 'package:flutter/widgets.dart'; import 'package:flutter_bloc/flutter_bloc.dart'; import 'package:flutter_svg/svg.dart'; -import 'package:syncrow_web/pages/auth/login/bloc/login_bloc.dart'; -import 'package:syncrow_web/pages/auth/login/bloc/login_event.dart'; -import 'package:syncrow_web/pages/auth/login/bloc/login_state.dart'; -import 'package:syncrow_web/pages/auth/forget_password/view/forget_password_page.dart'; +import 'package:syncrow_web/pages/auth/bloc/auth_bloc.dart'; +import 'package:syncrow_web/pages/auth/bloc/auth_event.dart'; +import 'package:syncrow_web/pages/auth/bloc/auth_state.dart'; +import 'package:syncrow_web/pages/auth/view/forget_password_page.dart'; import 'package:syncrow_web/pages/common/default_button.dart'; import 'package:syncrow_web/pages/common/first_layer.dart'; import 'package:syncrow_web/utils/color_manager.dart'; @@ -22,8 +22,8 @@ class LoginWebPage extends StatelessWidget { Widget build(BuildContext context) { return Scaffold( body: BlocProvider( - create: (context) => LoginBloc(), - child: BlocConsumer( + create: (context) => AuthBloc(), + child: BlocConsumer( listener: (context, state) { if (state is LoginSuccess) { // Navigate to home screen after successful login @@ -44,7 +44,7 @@ class LoginWebPage extends StatelessWidget { if (state is LoginLoading) { return const Center(child: CircularProgressIndicator()); } else { - return _buildLoginForm(context); + return _buildLoginForm(context,state); } }, ), @@ -52,8 +52,8 @@ class LoginWebPage extends StatelessWidget { ); } - Widget _buildLoginForm(BuildContext context) { - final loginBloc = BlocProvider.of(context); + Widget _buildLoginForm(BuildContext context,AuthState state) { + final loginBloc = BlocProvider.of(context); return FirstLayer( second: Container( margin: const EdgeInsets.all(50), @@ -83,7 +83,7 @@ class LoginWebPage extends StatelessWidget { borderRadius: const BorderRadius.all(Radius.circular(30)), border: Border.all(color: ColorsManager.graysColor.withOpacity(0.2))), child: Form( - key: loginBloc.formKey, + key: loginBloc.loginFormKey, child: Padding( padding: const EdgeInsets.symmetric(horizontal: 50, vertical: 20), child: Column( @@ -151,7 +151,7 @@ class LoginWebPage extends StatelessWidget { width: MediaQuery.sizeOf(context).width * 0.2, child: TextFormField( validator:loginBloc.validateEmail , - controller:loginBloc.emailController, + controller:loginBloc.loginEmailController, decoration: textBoxDecoration()!.copyWith(hintText: 'Enter your email'), style: const TextStyle(color: Colors.black), ), @@ -163,17 +163,29 @@ class LoginWebPage extends StatelessWidget { crossAxisAlignment: CrossAxisAlignment.start, mainAxisAlignment: MainAxisAlignment.start, children: [ - Text("Password", - style: smallTextStyle,), + Text("Password", style: smallTextStyle,), SizedBox( width: MediaQuery.sizeOf(context).width * 0.2, child: TextFormField( - validator:loginBloc.validatePassword , + validator:loginBloc.validatePassword, obscureText:loginBloc.obscureText, keyboardType: TextInputType.visiblePassword, - controller:loginBloc.passwordController, + controller:loginBloc.loginPasswordController, decoration: textBoxDecoration()!.copyWith( hintText: 'At least 8 characters', + suffixIcon: IconButton(onPressed: () { + loginBloc.add(PasswordVisibleEvent(newValue: loginBloc.obscureText)); + }, + icon: SizedBox( + child: SvgPicture.asset( + loginBloc.obscureText? + Assets.visiblePassword : + Assets.invisiblePassword, + height: 15, + width: 15, + ), + ), + ) ), style: const TextStyle(color: Colors.black), ), @@ -265,10 +277,10 @@ class LoginWebPage extends StatelessWidget { ColorsManager.btnColor:ColorsManager.grayColor, child: const Text('Sign in'), onPressed: () { - if (loginBloc.formKey.currentState!.validate()) { + if (loginBloc.loginFormKey.currentState!.validate()) { loginBloc.add(LoginButtonPressed( - username: loginBloc.emailController.text, - password: loginBloc.passwordController.text, + username: loginBloc.loginEmailController.text, + password: loginBloc.loginPasswordController.text, ), ); } @@ -359,24 +371,24 @@ class LoginWebPage extends StatelessWidget { // ], // ), // ), - SizedBox( - width: MediaQuery.sizeOf(context).width * 0.2, - child: const Row( - mainAxisAlignment: MainAxisAlignment.center, - crossAxisAlignment: CrossAxisAlignment.center, - children: [ - Flexible( - child: Text( - "Don't you have an account? ", - style: TextStyle(color: Colors.white), - )), - Flexible( - child: Text( - "Sign up", - )), - ], - ), - ) + // SizedBox( + // width: MediaQuery.sizeOf(context).width * 0.2, + // child: const Row( + // mainAxisAlignment: MainAxisAlignment.center, + // crossAxisAlignment: CrossAxisAlignment.center, + // children: [ + // Flexible( + // child: Text( + // "Don't you have an account? ", + // style: TextStyle(color: Colors.white), + // )), + // Flexible( + // child: Text( + // "Sign up", + // )), + // ], + // ), + // ) ], ), ), diff --git a/lib/services/api/http_interceptor.dart b/lib/services/api/http_interceptor.dart index 0b758aed..66e6302a 100644 --- a/lib/services/api/http_interceptor.dart +++ b/lib/services/api/http_interceptor.dart @@ -2,7 +2,7 @@ import 'dart:io'; import 'package:dio/dio.dart'; import 'package:flutter_secure_storage/flutter_secure_storage.dart'; -import 'package:syncrow_web/pages/auth/login/model/token.dart'; +import 'package:syncrow_web/pages/auth/model/token.dart'; import 'package:syncrow_web/services/api/network_exception.dart'; import 'dart:async'; import 'package:syncrow_web/utils/constants/api_const.dart'; diff --git a/lib/services/auth_api.dart b/lib/services/auth_api.dart index ba9480bf..5f832a14 100644 --- a/lib/services/auth_api.dart +++ b/lib/services/auth_api.dart @@ -1,12 +1,9 @@ - - -import 'package:syncrow_web/pages/auth/login/model/token.dart'; +import 'package:syncrow_web/pages/auth/model/token.dart'; import 'package:syncrow_web/services/api/http_service.dart'; import 'package:syncrow_web/utils/constants/api_const.dart'; class AuthenticationAPI { - static Future loginWithEmail({required var model}) async { final response = await HTTPService().post( path: ApiEndpoints.login, @@ -59,6 +56,4 @@ class AuthenticationAPI { return response; } - - } diff --git a/lib/utils/constants/assets.dart b/lib/utils/constants/assets.dart index 1dd7a2eb..0758fa9a 100644 --- a/lib/utils/constants/assets.dart +++ b/lib/utils/constants/assets.dart @@ -13,4 +13,6 @@ class Assets { static const String rightLine = "assets/images/right_line.png"; static const String google = "assets/images/google.svg"; static const String facebook = "assets/images/facebook.svg"; + static const String invisiblePassword = "assets/images/Password_invisible.svg"; + static const String visiblePassword = "assets/images/Password_visible.svg"; }