mirror of
https://github.com/SyncrowIOT/syncrow-app.git
synced 2025-07-16 01:56:19 +00:00
Implemented sign up and otp screens
This commit is contained in:
@ -19,8 +19,16 @@ class AuthCubit extends Cubit<AuthState> {
|
|||||||
final TextEditingController emailController = TextEditingController();
|
final TextEditingController emailController = TextEditingController();
|
||||||
final TextEditingController passwordController = TextEditingController();
|
final TextEditingController passwordController = TextEditingController();
|
||||||
|
|
||||||
final TextEditingController emailSignUpController = TextEditingController();
|
// final TextEditingController emailSignUpController = TextEditingController();
|
||||||
final TextEditingController passwordSignUpController = TextEditingController();
|
// final TextEditingController fullNameController = TextEditingController();
|
||||||
|
// final TextEditingController passwordSignUpController = TextEditingController();
|
||||||
|
// final TextEditingController reEnterPasswordSignUpController = TextEditingController();
|
||||||
|
|
||||||
|
String fullName = '';
|
||||||
|
String email = '';
|
||||||
|
String signUpPassword = '';
|
||||||
|
String maskedEmail = '';
|
||||||
|
String otpCode = '';
|
||||||
final loginFormKey = GlobalKey<FormState>();
|
final loginFormKey = GlobalKey<FormState>();
|
||||||
final signUpFormKey = GlobalKey<FormState>();
|
final signUpFormKey = GlobalKey<FormState>();
|
||||||
bool isPasswordVisible = false;
|
bool isPasswordVisible = false;
|
||||||
@ -46,32 +54,69 @@ class AuthCubit extends Cubit<AuthState> {
|
|||||||
/////////////////////////////////////VALIDATORS/////////////////////////////////////
|
/////////////////////////////////////VALIDATORS/////////////////////////////////////
|
||||||
String? passwordValidator(String? value) {
|
String? passwordValidator(String? value) {
|
||||||
if (value != null) {
|
if (value != null) {
|
||||||
if (value.isNotEmpty) {
|
if (value.isEmpty) {
|
||||||
// if (value.length >= 6) {
|
|
||||||
return null;
|
|
||||||
//TODO uncomment this code when the password validation is needed
|
|
||||||
// if (RegExp(
|
|
||||||
// r'^(?=.*[a-z])(?=.*[A-Z])(?=.*\d)(?=.*[@$!%*?&])[A-Za-z\d@$!%*?&]{8,}$')
|
|
||||||
// .hasMatch(value)) {
|
|
||||||
// return null;
|
|
||||||
// } else {
|
|
||||||
// return 'Password must contain at least one uppercase letter, one lowercase letter, one number and one special character';
|
|
||||||
// }
|
|
||||||
// } else {
|
|
||||||
// return 'Password must be at least 6 characters';
|
|
||||||
// }
|
|
||||||
} else {
|
|
||||||
return 'Please enter your password';
|
return 'Please enter your password';
|
||||||
}
|
}
|
||||||
|
if (value.isNotEmpty) {
|
||||||
|
if (!RegExp(r'^(?=.*[a-z])(?=.*[A-Z])(?=.*\d)(?=.*[@$!%*?&])[A-Za-z\d@$!%*?&]{8,}$')
|
||||||
|
.hasMatch(value)) {
|
||||||
|
return 'Password must contain at least one uppercase letter, one lowercase letter, one number and one special character';
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if (signUpFormKey.currentState != null) {
|
||||||
|
signUpFormKey.currentState!.save();
|
||||||
}
|
}
|
||||||
return null;
|
return null;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
String? fullNameValidator(String? value) {
|
||||||
|
if (value == null) return 'Full name is required';
|
||||||
|
|
||||||
|
final withoutExtraSpaces = value.replaceAll(RegExp(r"\s+"), ' ').trim();
|
||||||
|
|
||||||
|
if (withoutExtraSpaces.length < 2 || withoutExtraSpaces.length > 30) {
|
||||||
|
return 'Full name must be between 2 and 30 characters long';
|
||||||
|
}
|
||||||
|
|
||||||
|
// Test if it contains anything but alphanumeric spaces and single quote
|
||||||
|
|
||||||
|
if (RegExp(r"/[^ a-zA-Z0-9-\']/").hasMatch(withoutExtraSpaces)) {
|
||||||
|
return 'Only alphanumeric characters, space, dash and single quote are allowed';
|
||||||
|
}
|
||||||
|
|
||||||
|
final parts = withoutExtraSpaces.split(' ');
|
||||||
|
|
||||||
|
if (parts.length < 2) return 'Full name must contain first and last names';
|
||||||
|
|
||||||
|
if (parts.length > 3) return 'Full name can at most contain 3 parts';
|
||||||
|
|
||||||
|
if (parts.any((part) => part.length < 2 || part.length > 30)) {
|
||||||
|
return 'Full name parts must be between 2 and 30 characters long';
|
||||||
|
}
|
||||||
|
if (signUpFormKey.currentState != null) {
|
||||||
|
signUpFormKey.currentState!.save();
|
||||||
|
}
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
|
||||||
|
String reEnterPasswordCheck(String? value) {
|
||||||
|
passwordValidator(value);
|
||||||
|
if (signUpPassword == value) {
|
||||||
|
if (signUpFormKey.currentState != null) {
|
||||||
|
signUpFormKey.currentState!.save();
|
||||||
|
}
|
||||||
|
return '';
|
||||||
|
} else {
|
||||||
|
return 'Passwords do not match';
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
String? emailAddressValidator(String? value) {
|
String? emailAddressValidator(String? value) {
|
||||||
if (value != null && value.isNotEmpty && value != "") {
|
if (value != null && value.isNotEmpty && value != "") {
|
||||||
if (checkValidityOfEmail(value)) {
|
if (checkValidityOfEmail(value)) {
|
||||||
if (loginFormKey.currentState != null) {
|
if (signUpFormKey.currentState != null) {
|
||||||
loginFormKey.currentState!.save();
|
signUpFormKey.currentState!.save();
|
||||||
}
|
}
|
||||||
return null;
|
return null;
|
||||||
} else {
|
} else {
|
||||||
@ -92,6 +137,23 @@ class AuthCubit extends Cubit<AuthState> {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Function to mask the email
|
||||||
|
String maskEmail(String email) {
|
||||||
|
final emailParts = email.split('@');
|
||||||
|
if (emailParts.length != 2) return email;
|
||||||
|
|
||||||
|
final localPart = emailParts[0];
|
||||||
|
final domainPart = emailParts[1];
|
||||||
|
|
||||||
|
if (localPart.length < 3) return email;
|
||||||
|
|
||||||
|
final start = localPart.substring(0, 2);
|
||||||
|
final end = localPart.substring(localPart.length - 1);
|
||||||
|
|
||||||
|
final maskedLocalPart = '$start******$end';
|
||||||
|
return '$maskedLocalPart@$domainPart';
|
||||||
|
}
|
||||||
|
|
||||||
/////////////////////////////////////API CALLS/////////////////////////////////////
|
/////////////////////////////////////API CALLS/////////////////////////////////////
|
||||||
login() async {
|
login() async {
|
||||||
emit(AuthLoginLoading());
|
emit(AuthLoginLoading());
|
||||||
@ -128,21 +190,23 @@ class AuthCubit extends Cubit<AuthState> {
|
|||||||
emit(AuthLoginLoading());
|
emit(AuthLoginLoading());
|
||||||
final response;
|
final response;
|
||||||
try {
|
try {
|
||||||
|
List<String> userFullName = fullName.split(' ');
|
||||||
response = await AuthenticationAPI.signUp(
|
response = await AuthenticationAPI.signUp(
|
||||||
model: SignUpModel(
|
model: SignUpModel(
|
||||||
email: emailController.text.toLowerCase(),
|
email: email.toLowerCase(),
|
||||||
password: passwordController.text,
|
password: signUpPassword,
|
||||||
firstName: '',
|
firstName: userFullName[0],
|
||||||
lastName: ''),
|
lastName: userFullName[1]),
|
||||||
);
|
);
|
||||||
} catch (failure) {
|
} catch (failure) {
|
||||||
emit(AuthLoginError(message: failure.toString()));
|
emit(AuthLoginError(message: failure.toString()));
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
if (response['statusCode'] == 201) {
|
if (response) {
|
||||||
emailController.clear();
|
maskedEmail = maskEmail(email);
|
||||||
passwordController.clear();
|
final response = await AuthenticationAPI.sendOtp(body: {'email': email, 'type': 'PASSWORD'});
|
||||||
emit(AuthLoginSuccess());
|
otpCode = response['otp'];
|
||||||
|
emit(AuthSignUpSuccess());
|
||||||
} else {
|
} else {
|
||||||
emit(AuthLoginError(message: 'Something went wrong'));
|
emit(AuthLoginError(message: 'Something went wrong'));
|
||||||
}
|
}
|
||||||
|
@ -20,6 +20,10 @@ class AuthLoginLoading extends AuthLoading {}
|
|||||||
|
|
||||||
class AuthLoginSuccess extends AuthSuccess {}
|
class AuthLoginSuccess extends AuthSuccess {}
|
||||||
|
|
||||||
|
class AuthOtpSuccess extends AuthSuccess {}
|
||||||
|
|
||||||
|
class AuthSignUpSuccess extends AuthSuccess {}
|
||||||
|
|
||||||
class AuthLoginError extends AuthError {
|
class AuthLoginError extends AuthError {
|
||||||
AuthLoginError({required super.message, super.code});
|
AuthLoginError({required super.message, super.code});
|
||||||
}
|
}
|
||||||
|
@ -2,10 +2,10 @@ import 'package:flutter/material.dart';
|
|||||||
import 'package:flutter_bloc/flutter_bloc.dart';
|
import 'package:flutter_bloc/flutter_bloc.dart';
|
||||||
import 'package:flutter_svg/flutter_svg.dart';
|
import 'package:flutter_svg/flutter_svg.dart';
|
||||||
import 'package:syncrow_app/features/auth/bloc/auth_cubit.dart';
|
import 'package:syncrow_app/features/auth/bloc/auth_cubit.dart';
|
||||||
import 'package:syncrow_app/features/auth/view/widgets/login/dont_have_an_account.dart';
|
import 'package:syncrow_app/features/auth/view/widgets/dont_have_an_account.dart';
|
||||||
import 'package:syncrow_app/features/auth/view/widgets/login/login_divider.dart';
|
import 'package:syncrow_app/features/auth/view/widgets/login_divider.dart';
|
||||||
import 'package:syncrow_app/features/auth/view/widgets/login/login_form.dart';
|
import 'package:syncrow_app/features/auth/view/widgets/login_form.dart';
|
||||||
import 'package:syncrow_app/features/auth/view/widgets/login/login_with_google_facebook.dart';
|
import 'package:syncrow_app/features/auth/view/widgets/login_with_google_facebook.dart';
|
||||||
import 'package:syncrow_app/features/shared_widgets/text_widgets/title_medium.dart';
|
import 'package:syncrow_app/features/shared_widgets/text_widgets/title_medium.dart';
|
||||||
import 'package:syncrow_app/generated/assets.dart';
|
import 'package:syncrow_app/generated/assets.dart';
|
||||||
import 'package:syncrow_app/navigation/routing_constants.dart';
|
import 'package:syncrow_app/navigation/routing_constants.dart';
|
221
lib/features/auth/view/otp_view.dart
Normal file
221
lib/features/auth/view/otp_view.dart
Normal file
@ -0,0 +1,221 @@
|
|||||||
|
import 'package:flutter/material.dart';
|
||||||
|
import 'package:flutter_bloc/flutter_bloc.dart';
|
||||||
|
import 'package:flutter_svg/svg.dart';
|
||||||
|
import 'package:pin_code_fields/pin_code_fields.dart';
|
||||||
|
import 'package:syncrow_app/features/auth/bloc/auth_cubit.dart';
|
||||||
|
import 'package:syncrow_app/features/shared_widgets/default_button.dart';
|
||||||
|
import 'package:syncrow_app/features/shared_widgets/text_widgets/body_medium.dart';
|
||||||
|
import 'package:syncrow_app/features/shared_widgets/text_widgets/title_medium.dart';
|
||||||
|
import 'package:syncrow_app/generated/assets.dart';
|
||||||
|
import 'package:syncrow_app/navigation/routing_constants.dart';
|
||||||
|
import 'package:syncrow_app/utils/context_extension.dart';
|
||||||
|
import 'package:syncrow_app/utils/resource_manager/constants.dart';
|
||||||
|
import 'package:syncrow_app/utils/resource_manager/font_manager.dart';
|
||||||
|
import 'package:syncrow_app/utils/resource_manager/styles_manager.dart';
|
||||||
|
|
||||||
|
class OtpView extends StatelessWidget {
|
||||||
|
const OtpView({super.key});
|
||||||
|
|
||||||
|
@override
|
||||||
|
Widget build(BuildContext context) {
|
||||||
|
final formKey = AuthCubit.get(context).signUpFormKey;
|
||||||
|
return BlocConsumer<AuthCubit, AuthState>(
|
||||||
|
listener: (context, state) {
|
||||||
|
if (state is AuthError) {
|
||||||
|
} else if (state is AuthOtpSuccess) {
|
||||||
|
Navigator.popAndPushNamed(context, Routes.homeRoute);
|
||||||
|
}
|
||||||
|
},
|
||||||
|
builder: (context, state) {
|
||||||
|
return SafeArea(
|
||||||
|
child: Scaffold(
|
||||||
|
body: Stack(
|
||||||
|
children: [
|
||||||
|
Container(
|
||||||
|
width: MediaQuery.sizeOf(context).width,
|
||||||
|
height: MediaQuery.sizeOf(context).height,
|
||||||
|
decoration: const BoxDecoration(
|
||||||
|
image: DecorationImage(
|
||||||
|
image: AssetImage(
|
||||||
|
Assets.assetsImagesBackground,
|
||||||
|
),
|
||||||
|
fit: BoxFit.cover,
|
||||||
|
),
|
||||||
|
),
|
||||||
|
),
|
||||||
|
Container(
|
||||||
|
width: MediaQuery.sizeOf(context).width,
|
||||||
|
height: MediaQuery.sizeOf(context).height,
|
||||||
|
decoration: const BoxDecoration(
|
||||||
|
image: DecorationImage(
|
||||||
|
image: AssetImage(Assets.assetsImagesVector),
|
||||||
|
fit: BoxFit.cover,
|
||||||
|
opacity: 0.9,
|
||||||
|
),
|
||||||
|
),
|
||||||
|
),
|
||||||
|
Padding(
|
||||||
|
padding: const EdgeInsets.only(
|
||||||
|
right: Constants.defaultPadding,
|
||||||
|
left: Constants.defaultPadding,
|
||||||
|
top: Constants.defaultPadding,
|
||||||
|
),
|
||||||
|
child: SingleChildScrollView(
|
||||||
|
child: Center(
|
||||||
|
child: Column(
|
||||||
|
mainAxisAlignment: MainAxisAlignment.center,
|
||||||
|
crossAxisAlignment: CrossAxisAlignment.start,
|
||||||
|
children: [
|
||||||
|
Center(
|
||||||
|
child: SvgPicture.asset(
|
||||||
|
Assets.assetsImagesLogo,
|
||||||
|
width: 160,
|
||||||
|
),
|
||||||
|
),
|
||||||
|
const SizedBox(
|
||||||
|
height: 40,
|
||||||
|
),
|
||||||
|
TitleMedium(
|
||||||
|
text: 'Verification Code',
|
||||||
|
style: context.titleMedium.copyWith(
|
||||||
|
fontWeight: FontsManager.extraBold,
|
||||||
|
color: Colors.white,
|
||||||
|
),
|
||||||
|
),
|
||||||
|
const SizedBox(
|
||||||
|
height: 20,
|
||||||
|
),
|
||||||
|
RichText(
|
||||||
|
text: TextSpan(
|
||||||
|
text:
|
||||||
|
'We have sent the verification codeWe have sent the verification code to',
|
||||||
|
style: Theme.of(context).textTheme.titleSmall!.copyWith(
|
||||||
|
color: Colors.white,
|
||||||
|
fontWeight: FontsManager.regular,
|
||||||
|
fontSize: 14,
|
||||||
|
),
|
||||||
|
children: [
|
||||||
|
TextSpan(
|
||||||
|
text: ' ex******e@email.com',
|
||||||
|
style: Theme.of(context).textTheme.titleSmall!.copyWith(
|
||||||
|
color: Colors.black,
|
||||||
|
fontWeight: FontsManager.bold,
|
||||||
|
fontSize: 14,
|
||||||
|
),
|
||||||
|
),
|
||||||
|
TextSpan(
|
||||||
|
text: ' change email?',
|
||||||
|
style: Theme.of(context).textTheme.titleSmall!.copyWith(
|
||||||
|
color: const Color(0xFF87C7FF),
|
||||||
|
fontWeight: FontsManager.regular,
|
||||||
|
fontSize: 14,
|
||||||
|
),
|
||||||
|
),
|
||||||
|
]),
|
||||||
|
),
|
||||||
|
Column(
|
||||||
|
crossAxisAlignment: CrossAxisAlignment.start,
|
||||||
|
children: [
|
||||||
|
SizedBox(
|
||||||
|
height: 40,
|
||||||
|
),
|
||||||
|
PinCodeTextField(
|
||||||
|
key: const Key('pin_code_text_field'),
|
||||||
|
appContext: context,
|
||||||
|
length: 4,
|
||||||
|
cursorHeight: 25,
|
||||||
|
backgroundColor: Colors.transparent,
|
||||||
|
keyboardType: TextInputType.number,
|
||||||
|
autoFocus: true,
|
||||||
|
animationDuration: const Duration(milliseconds: 30),
|
||||||
|
// controller: AuthCubit.get(context).emailController,
|
||||||
|
// cursorColor: KeysperColors.primaryBase,
|
||||||
|
beforeTextPaste: (text) {
|
||||||
|
// Allow pasting only if all characters are numeric
|
||||||
|
return int.tryParse(text!) != null;
|
||||||
|
},
|
||||||
|
textStyle: Theme.of(context)
|
||||||
|
.textTheme
|
||||||
|
.headlineMedium!
|
||||||
|
.copyWith(color: Colors.black),
|
||||||
|
hintStyle: Theme.of(context)
|
||||||
|
.textTheme
|
||||||
|
.headlineMedium!
|
||||||
|
.copyWith(color: Colors.grey),
|
||||||
|
enablePinAutofill: true,
|
||||||
|
pinTheme: PinTheme(
|
||||||
|
borderRadius: BorderRadius.circular(8),
|
||||||
|
inactiveBorderWidth: 1,
|
||||||
|
disabledBorderWidth: 1,
|
||||||
|
selectedBorderWidth: 1,
|
||||||
|
activeBorderWidth: 1,
|
||||||
|
errorBorderWidth: 1,
|
||||||
|
borderWidth: 1,
|
||||||
|
errorBorderColor: Colors.red,
|
||||||
|
activeColor: Colors.white,
|
||||||
|
inactiveColor: Colors.white,
|
||||||
|
activeFillColor: Colors.white,
|
||||||
|
inactiveFillColor: Colors.white,
|
||||||
|
selectedFillColor: Colors.white,
|
||||||
|
disabledColor: Colors.white,
|
||||||
|
fieldHeight: 50,
|
||||||
|
fieldWidth: 50,
|
||||||
|
selectedColor: Colors.white,
|
||||||
|
shape: PinCodeFieldShape.box,
|
||||||
|
),
|
||||||
|
onChanged: (value) async {
|
||||||
|
// otpCode = value;
|
||||||
|
// await bloc.onOTPChanged(value);
|
||||||
|
},
|
||||||
|
onCompleted: (value) {},
|
||||||
|
onSubmitted: (value) async {
|
||||||
|
// await bloc.onOTPSubmitted();
|
||||||
|
},
|
||||||
|
),
|
||||||
|
const SizedBox(height: 40),
|
||||||
|
Row(
|
||||||
|
mainAxisAlignment: MainAxisAlignment.center,
|
||||||
|
children: [
|
||||||
|
Expanded(
|
||||||
|
child: DefaultButton(
|
||||||
|
isDone: state is AuthLoginSuccess,
|
||||||
|
isLoading: state is AuthLoading,
|
||||||
|
customButtonStyle: ButtonStyle(
|
||||||
|
backgroundColor: MaterialStateProperty.all(
|
||||||
|
Colors.black.withOpacity(.25),
|
||||||
|
),
|
||||||
|
foregroundColor: MaterialStateProperty.all(
|
||||||
|
Colors.white,
|
||||||
|
),
|
||||||
|
),
|
||||||
|
child: const Text(
|
||||||
|
'Verify',
|
||||||
|
),
|
||||||
|
onPressed: () {
|
||||||
|
if (formKey.currentState!.validate()) {
|
||||||
|
if ((state is! AuthLoading)) {
|
||||||
|
AuthCubit.get(context).signUp();
|
||||||
|
FocusScope.of(context).unfocus();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
},
|
||||||
|
),
|
||||||
|
),
|
||||||
|
],
|
||||||
|
)
|
||||||
|
],
|
||||||
|
),
|
||||||
|
],
|
||||||
|
),
|
||||||
|
),
|
||||||
|
),
|
||||||
|
)
|
||||||
|
],
|
||||||
|
),
|
||||||
|
),
|
||||||
|
);
|
||||||
|
},
|
||||||
|
);
|
||||||
|
;
|
||||||
|
}
|
||||||
|
}
|
@ -2,7 +2,7 @@ import 'package:flutter/material.dart';
|
|||||||
import 'package:flutter_bloc/flutter_bloc.dart';
|
import 'package:flutter_bloc/flutter_bloc.dart';
|
||||||
import 'package:flutter_svg/svg.dart';
|
import 'package:flutter_svg/svg.dart';
|
||||||
import 'package:syncrow_app/features/auth/bloc/auth_cubit.dart';
|
import 'package:syncrow_app/features/auth/bloc/auth_cubit.dart';
|
||||||
import 'package:syncrow_app/features/auth/view/widgets/login/login_form.dart';
|
import 'package:syncrow_app/features/auth/view/widgets/login_form.dart';
|
||||||
import 'package:syncrow_app/features/shared_widgets/default_button.dart';
|
import 'package:syncrow_app/features/shared_widgets/default_button.dart';
|
||||||
import 'package:syncrow_app/features/shared_widgets/text_widgets/body_medium.dart';
|
import 'package:syncrow_app/features/shared_widgets/text_widgets/body_medium.dart';
|
||||||
import 'package:syncrow_app/features/shared_widgets/text_widgets/title_medium.dart';
|
import 'package:syncrow_app/features/shared_widgets/text_widgets/title_medium.dart';
|
||||||
@ -21,14 +21,8 @@ class SignUpView extends StatelessWidget {
|
|||||||
final formKey = AuthCubit.get(context).signUpFormKey;
|
final formKey = AuthCubit.get(context).signUpFormKey;
|
||||||
return BlocConsumer<AuthCubit, AuthState>(
|
return BlocConsumer<AuthCubit, AuthState>(
|
||||||
listener: (context, state) {
|
listener: (context, state) {
|
||||||
if (state is AuthError) {
|
if (state is AuthSignUpSuccess) {
|
||||||
// ScaffoldMessenger.of(context).showSnackBar(
|
Navigator.popAndPushNamed(context, Routes.otpRoute);
|
||||||
// SnackBar(
|
|
||||||
// content: Text(state.message),
|
|
||||||
// ),
|
|
||||||
// );
|
|
||||||
} else if (state is AuthLoginSuccess) {
|
|
||||||
Navigator.popAndPushNamed(context, Routes.homeRoute);
|
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
builder: (context, state) {
|
builder: (context, state) {
|
||||||
@ -92,48 +86,66 @@ class SignUpView extends StatelessWidget {
|
|||||||
),
|
),
|
||||||
Form(
|
Form(
|
||||||
key: formKey,
|
key: formKey,
|
||||||
autovalidateMode: AutovalidateMode.onUserInteraction,
|
|
||||||
child: SingleChildScrollView(
|
child: SingleChildScrollView(
|
||||||
child: Column(
|
child: Column(
|
||||||
crossAxisAlignment: CrossAxisAlignment.start,
|
crossAxisAlignment: CrossAxisAlignment.start,
|
||||||
children: [
|
children: [
|
||||||
|
const BodyMedium(
|
||||||
|
text: "Full Name",
|
||||||
|
fontColor: Colors.white,
|
||||||
|
),
|
||||||
|
TextFormField(
|
||||||
|
// autovalidateMode: AutovalidateMode.onUserInteraction,
|
||||||
|
textInputAction: TextInputAction.done,
|
||||||
|
keyboardType: TextInputType.name,
|
||||||
|
scrollPadding: EdgeInsets.zero,
|
||||||
|
autocorrect: false,
|
||||||
|
autofillHints: const [AutofillHints.name],
|
||||||
|
// controller: AuthCubit.get(context).fullNameController,
|
||||||
|
validator: AuthCubit.get(context).fullNameValidator,
|
||||||
|
onTapOutside: (event) {
|
||||||
|
FocusScope.of(context).unfocus();
|
||||||
|
},
|
||||||
|
onChanged: (value) {
|
||||||
|
AuthCubit.get(context).fullName = value;
|
||||||
|
},
|
||||||
|
decoration: defaultInputDecoration(context, hint: "Full Name"),
|
||||||
|
),
|
||||||
|
const SizedBox(height: 16),
|
||||||
const BodyMedium(
|
const BodyMedium(
|
||||||
text: "Email",
|
text: "Email",
|
||||||
fontColor: Colors.white,
|
fontColor: Colors.white,
|
||||||
),
|
),
|
||||||
TextFormField(
|
TextFormField(
|
||||||
autovalidateMode: AutovalidateMode.disabled,
|
|
||||||
textInputAction: TextInputAction.done,
|
textInputAction: TextInputAction.done,
|
||||||
keyboardType: TextInputType.text,
|
keyboardType: TextInputType.text,
|
||||||
scrollPadding: EdgeInsets.zero,
|
scrollPadding: EdgeInsets.zero,
|
||||||
autocorrect: false,
|
autocorrect: false,
|
||||||
autofillHints: const [AutofillHints.email],
|
autofillHints: const [AutofillHints.email],
|
||||||
controller: AuthCubit.get(context).emailController,
|
validator: AuthCubit.get(context).emailAddressValidator,
|
||||||
validator: (value) {
|
|
||||||
return AuthCubit.get(context).emailAddressValidator(value);
|
|
||||||
},
|
|
||||||
onTapOutside: (event) {
|
onTapOutside: (event) {
|
||||||
FocusScope.of(context).unfocus();
|
FocusScope.of(context).unfocus();
|
||||||
},
|
},
|
||||||
onChanged: (value) {},
|
onChanged: (value) {
|
||||||
|
AuthCubit.get(context).email = value;
|
||||||
|
},
|
||||||
decoration:
|
decoration:
|
||||||
defaultInputDecoration(context, hint: "Example@email.com"),
|
defaultInputDecoration(context, hint: "Example@email.com"),
|
||||||
),
|
),
|
||||||
const SizedBox(height: 15),
|
const SizedBox(height: 16),
|
||||||
const BodyMedium(
|
const BodyMedium(
|
||||||
text: "Password",
|
text: "Password",
|
||||||
fontColor: Colors.white,
|
fontColor: Colors.white,
|
||||||
),
|
),
|
||||||
TextFormField(
|
TextFormField(
|
||||||
autovalidateMode: AutovalidateMode.disabled,
|
|
||||||
textInputAction: TextInputAction.done,
|
textInputAction: TextInputAction.done,
|
||||||
keyboardType: TextInputType.text,
|
keyboardType: TextInputType.text,
|
||||||
scrollPadding: EdgeInsets.zero,
|
scrollPadding: EdgeInsets.zero,
|
||||||
autocorrect: false,
|
autocorrect: false,
|
||||||
autofillHints: const [AutofillHints.password],
|
autofillHints: const [AutofillHints.password],
|
||||||
controller: AuthCubit.get(context).passwordController,
|
validator: AuthCubit.get(context).passwordValidator,
|
||||||
validator: (value) {
|
onChanged: (value) {
|
||||||
return AuthCubit.get(context).passwordValidator(value);
|
AuthCubit.get(context).signUpPassword = value;
|
||||||
},
|
},
|
||||||
onTapOutside: (event) {
|
onTapOutside: (event) {
|
||||||
FocusScope.of(context).unfocus();
|
FocusScope.of(context).unfocus();
|
||||||
@ -142,22 +154,19 @@ class SignUpView extends StatelessWidget {
|
|||||||
decoration: defaultInputDecoration(context,
|
decoration: defaultInputDecoration(context,
|
||||||
hint: "At least 8 characters"),
|
hint: "At least 8 characters"),
|
||||||
),
|
),
|
||||||
const SizedBox(height: 15),
|
const SizedBox(height: 16),
|
||||||
const BodyMedium(
|
const BodyMedium(
|
||||||
text: "Re-enter Password",
|
text: "Re-enter Password",
|
||||||
fontColor: Colors.white,
|
fontColor: Colors.white,
|
||||||
),
|
),
|
||||||
TextFormField(
|
TextFormField(
|
||||||
autovalidateMode: AutovalidateMode.disabled,
|
|
||||||
textInputAction: TextInputAction.done,
|
textInputAction: TextInputAction.done,
|
||||||
keyboardType: TextInputType.text,
|
keyboardType: TextInputType.text,
|
||||||
scrollPadding: EdgeInsets.zero,
|
scrollPadding: EdgeInsets.zero,
|
||||||
autocorrect: false,
|
autocorrect: false,
|
||||||
autofillHints: const [AutofillHints.password],
|
autofillHints: const [AutofillHints.password],
|
||||||
controller: AuthCubit.get(context).passwordController,
|
onChanged: (value) {},
|
||||||
validator: (value) {
|
validator: AuthCubit.get(context).reEnterPasswordCheck,
|
||||||
return AuthCubit.get(context).passwordValidator(value);
|
|
||||||
},
|
|
||||||
onTapOutside: (event) {
|
onTapOutside: (event) {
|
||||||
FocusScope.of(context).unfocus();
|
FocusScope.of(context).unfocus();
|
||||||
},
|
},
|
||||||
@ -187,7 +196,7 @@ class SignUpView extends StatelessWidget {
|
|||||||
onPressed: () {
|
onPressed: () {
|
||||||
if (formKey.currentState!.validate()) {
|
if (formKey.currentState!.validate()) {
|
||||||
if ((state is! AuthLoading)) {
|
if ((state is! AuthLoading)) {
|
||||||
AuthCubit.get(context).login();
|
AuthCubit.get(context).signUp();
|
||||||
FocusScope.of(context).unfocus();
|
FocusScope.of(context).unfocus();
|
||||||
}
|
}
|
||||||
}
|
}
|
@ -1,10 +0,0 @@
|
|||||||
import 'package:flutter/material.dart';
|
|
||||||
|
|
||||||
class DidntGetCodeView extends StatelessWidget {
|
|
||||||
const DidntGetCodeView({super.key});
|
|
||||||
|
|
||||||
@override
|
|
||||||
Widget build(BuildContext context) {
|
|
||||||
return const Placeholder();
|
|
||||||
}
|
|
||||||
}
|
|
@ -1,7 +1,7 @@
|
|||||||
import 'package:flutter/material.dart';
|
import 'package:flutter/material.dart';
|
||||||
import 'package:flutter_bloc/flutter_bloc.dart';
|
import 'package:flutter_bloc/flutter_bloc.dart';
|
||||||
import 'package:syncrow_app/features/auth/bloc/auth_cubit.dart';
|
import 'package:syncrow_app/features/auth/bloc/auth_cubit.dart';
|
||||||
import 'package:syncrow_app/features/auth/view/widgets/login/forget_password.dart';
|
import 'package:syncrow_app/features/auth/view/widgets/forget_password.dart';
|
||||||
import 'package:syncrow_app/features/shared_widgets/default_button.dart';
|
import 'package:syncrow_app/features/shared_widgets/default_button.dart';
|
||||||
import 'package:syncrow_app/features/shared_widgets/text_widgets/body_medium.dart';
|
import 'package:syncrow_app/features/shared_widgets/text_widgets/body_medium.dart';
|
||||||
import 'package:syncrow_app/utils/resource_manager/styles_manager.dart';
|
import 'package:syncrow_app/utils/resource_manager/styles_manager.dart';
|
@ -1,10 +0,0 @@
|
|||||||
import 'package:flutter/material.dart';
|
|
||||||
|
|
||||||
class OneTimePasswordView extends StatelessWidget {
|
|
||||||
const OneTimePasswordView({super.key});
|
|
||||||
|
|
||||||
@override
|
|
||||||
Widget build(BuildContext context) {
|
|
||||||
return const Placeholder();
|
|
||||||
}
|
|
||||||
}
|
|
@ -1,10 +0,0 @@
|
|||||||
import 'package:flutter/material.dart';
|
|
||||||
|
|
||||||
class PrivacyPolicyView extends StatelessWidget {
|
|
||||||
const PrivacyPolicyView({super.key});
|
|
||||||
|
|
||||||
@override
|
|
||||||
Widget build(BuildContext context) {
|
|
||||||
return const Placeholder();
|
|
||||||
}
|
|
||||||
}
|
|
@ -1,10 +0,0 @@
|
|||||||
import 'package:flutter/material.dart';
|
|
||||||
|
|
||||||
class UserAgreementView extends StatelessWidget {
|
|
||||||
const UserAgreementView({super.key});
|
|
||||||
|
|
||||||
@override
|
|
||||||
Widget build(BuildContext context) {
|
|
||||||
return const Placeholder();
|
|
||||||
}
|
|
||||||
}
|
|
@ -2,7 +2,7 @@ import 'package:flutter/material.dart';
|
|||||||
import 'package:flutter_bloc/flutter_bloc.dart';
|
import 'package:flutter_bloc/flutter_bloc.dart';
|
||||||
import 'package:flutter_svg/flutter_svg.dart';
|
import 'package:flutter_svg/flutter_svg.dart';
|
||||||
import 'package:syncrow_app/features/auth/bloc/auth_cubit.dart';
|
import 'package:syncrow_app/features/auth/bloc/auth_cubit.dart';
|
||||||
import 'package:syncrow_app/features/auth/view/widgets/login/login_view.dart';
|
import 'package:syncrow_app/features/auth/view/login_view.dart';
|
||||||
import 'package:syncrow_app/generated/assets.dart';
|
import 'package:syncrow_app/generated/assets.dart';
|
||||||
import 'package:syncrow_app/navigation/routing_constants.dart';
|
import 'package:syncrow_app/navigation/routing_constants.dart';
|
||||||
import 'package:syncrow_app/utils/helpers/custom_page_route.dart';
|
import 'package:syncrow_app/utils/helpers/custom_page_route.dart';
|
||||||
|
@ -1,11 +1,8 @@
|
|||||||
import 'package:flutter/material.dart';
|
import 'package:flutter/material.dart';
|
||||||
import 'package:syncrow_app/features/app_layout/view/app_layout.dart';
|
import 'package:syncrow_app/features/app_layout/view/app_layout.dart';
|
||||||
import 'package:syncrow_app/features/auth/view/widgets/didnt_get_code/didnt_get_code_view.dart';
|
import 'package:syncrow_app/features/auth/view/otp_view.dart';
|
||||||
import 'package:syncrow_app/features/auth/view/widgets/login/login_view.dart';
|
import 'package:syncrow_app/features/auth/view/login_view.dart';
|
||||||
import 'package:syncrow_app/features/auth/view/widgets/one_time_password/one_time_password_view.dart';
|
import 'package:syncrow_app/features/auth/view/sign_up_view.dart';
|
||||||
import 'package:syncrow_app/features/auth/view/widgets/privacy_policy/privacy_policy_view.dart';
|
|
||||||
import 'package:syncrow_app/features/auth/view/widgets/sign_up/sign_up_view.dart';
|
|
||||||
import 'package:syncrow_app/features/auth/view/widgets/user_agreement/user_agreement_view.dart';
|
|
||||||
import 'package:syncrow_app/features/dashboard/view/dashboard_view.dart';
|
import 'package:syncrow_app/features/dashboard/view/dashboard_view.dart';
|
||||||
import 'package:syncrow_app/features/layout/view/layout_view.dart';
|
import 'package:syncrow_app/features/layout/view/layout_view.dart';
|
||||||
import 'package:syncrow_app/features/menu/view/menu_view.dart';
|
import 'package:syncrow_app/features/menu/view/menu_view.dart';
|
||||||
@ -19,60 +16,38 @@ class Router {
|
|||||||
static Route<dynamic> generateRoute(RouteSettings settings) {
|
static Route<dynamic> generateRoute(RouteSettings settings) {
|
||||||
switch (settings.name) {
|
switch (settings.name) {
|
||||||
case Routes.splash:
|
case Routes.splash:
|
||||||
return MaterialPageRoute(
|
return MaterialPageRoute(builder: (_) => const SplashView(), settings: settings);
|
||||||
builder: (_) => const SplashView(), settings: settings);
|
|
||||||
|
|
||||||
// case Routes.devicesRoute:
|
// case Routes.devicesRoute:
|
||||||
// return MaterialPageRoute(
|
// return MaterialPageRoute(
|
||||||
// builder: (_) => const DevicesView(), settings: settings);
|
// builder: (_) => const DevicesView(), settings: settings);
|
||||||
|
|
||||||
case Routes.profileRoute:
|
case Routes.profileRoute:
|
||||||
return MaterialPageRoute(
|
return MaterialPageRoute(builder: (_) => const ProfileView(), settings: settings);
|
||||||
builder: (_) => const ProfileView(), settings: settings);
|
|
||||||
|
|
||||||
case Routes.sceneRoute:
|
case Routes.sceneRoute:
|
||||||
return MaterialPageRoute(
|
return MaterialPageRoute(builder: (_) => const SceneView(), settings: settings);
|
||||||
builder: (_) => const SceneView(), settings: settings);
|
|
||||||
|
|
||||||
case Routes.layoutRoute:
|
case Routes.layoutRoute:
|
||||||
return MaterialPageRoute(
|
return MaterialPageRoute(builder: (_) => const LayoutPage(), settings: settings);
|
||||||
builder: (_) => const LayoutPage(), settings: settings);
|
|
||||||
|
|
||||||
case Routes.authLogin:
|
case Routes.authLogin:
|
||||||
return MaterialPageRoute(
|
return MaterialPageRoute(builder: (_) => const LoginView(), settings: settings);
|
||||||
builder: (_) => const LoginView(), settings: settings);
|
|
||||||
|
|
||||||
case Routes.authOneTimePassword:
|
case Routes.otpRoute:
|
||||||
return MaterialPageRoute(
|
return MaterialPageRoute(builder: (_) => const OtpView(), settings: settings);
|
||||||
builder: (_) => const OneTimePasswordView(), settings: settings);
|
|
||||||
|
|
||||||
case Routes.authSignUp:
|
case Routes.authSignUp:
|
||||||
return MaterialPageRoute(
|
return MaterialPageRoute(builder: (_) => const SignUpView(), settings: settings);
|
||||||
builder: (_) => const SignUpView(), settings: settings);
|
|
||||||
|
|
||||||
case Routes.policyRoute:
|
|
||||||
return MaterialPageRoute(
|
|
||||||
builder: (_) => const PrivacyPolicyView(), settings: settings);
|
|
||||||
|
|
||||||
case Routes.termsRoute:
|
|
||||||
return MaterialPageRoute(
|
|
||||||
builder: (_) => const UserAgreementView(), settings: settings);
|
|
||||||
|
|
||||||
case Routes.authDidNotGetCode:
|
|
||||||
return MaterialPageRoute(
|
|
||||||
builder: (_) => const DidntGetCodeView(), settings: settings);
|
|
||||||
|
|
||||||
case Routes.dashboardRoute:
|
case Routes.dashboardRoute:
|
||||||
return MaterialPageRoute(
|
return MaterialPageRoute(builder: (_) => const DashboardView(), settings: settings);
|
||||||
builder: (_) => const DashboardView(), settings: settings);
|
|
||||||
|
|
||||||
case Routes.homeRoute:
|
case Routes.homeRoute:
|
||||||
return MaterialPageRoute(
|
return MaterialPageRoute(builder: (_) => const AppLayout(), settings: settings);
|
||||||
builder: (_) => const AppLayout(), settings: settings);
|
|
||||||
|
|
||||||
case Routes.menuRoute:
|
case Routes.menuRoute:
|
||||||
return MaterialPageRoute(
|
return MaterialPageRoute(builder: (_) => const MenuView(), settings: settings);
|
||||||
builder: (_) => const MenuView(), settings: settings);
|
|
||||||
|
|
||||||
default:
|
default:
|
||||||
return MaterialPageRoute(
|
return MaterialPageRoute(
|
||||||
|
@ -15,4 +15,5 @@ class Routes {
|
|||||||
static const String authDidNotGetCode = '$authRoute/did-not-get-code';
|
static const String authDidNotGetCode = '$authRoute/did-not-get-code';
|
||||||
static const String policyRoute = '/policy';
|
static const String policyRoute = '/policy';
|
||||||
static const String termsRoute = '/terms';
|
static const String termsRoute = '/terms';
|
||||||
|
static const String otpRoute = '/otp';
|
||||||
}
|
}
|
||||||
|
@ -24,12 +24,21 @@ class AuthenticationAPI {
|
|||||||
return response;
|
return response;
|
||||||
}
|
}
|
||||||
|
|
||||||
static Future<Token> signUp({required SignUpModel model}) async {
|
static Future<bool> signUp({required SignUpModel model}) async {
|
||||||
final response = await HTTPService().post(
|
final response = await HTTPService().post(
|
||||||
path: ApiEndpoints.signUp,
|
path: ApiEndpoints.signUp,
|
||||||
body: model.toJson(),
|
body: model.toJson(),
|
||||||
showServerMessage: false,
|
showServerMessage: false,
|
||||||
expectedResponseModel: (json) => Token.fromJson(json['data']));
|
expectedResponseModel: (json) => json['statusCode'] == 201);
|
||||||
|
return response;
|
||||||
|
}
|
||||||
|
|
||||||
|
static Future<Map<String, dynamic>> sendOtp({required Map<String, dynamic> body}) async {
|
||||||
|
final response = await HTTPService().post(
|
||||||
|
path: ApiEndpoints.sendOtp,
|
||||||
|
body: body,
|
||||||
|
showServerMessage: false,
|
||||||
|
expectedResponseModel: (json) => json['data']);
|
||||||
return response;
|
return response;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -605,6 +605,14 @@ packages:
|
|||||||
url: "https://pub.dev"
|
url: "https://pub.dev"
|
||||||
source: hosted
|
source: hosted
|
||||||
version: "6.0.2"
|
version: "6.0.2"
|
||||||
|
pin_code_fields:
|
||||||
|
dependency: "direct main"
|
||||||
|
description:
|
||||||
|
name: pin_code_fields
|
||||||
|
sha256: "4c0db7fbc889e622e7c71ea54b9ee624bb70c7365b532abea0271b17ea75b729"
|
||||||
|
url: "https://pub.dev"
|
||||||
|
source: hosted
|
||||||
|
version: "8.0.1"
|
||||||
platform:
|
platform:
|
||||||
dependency: transitive
|
dependency: transitive
|
||||||
description:
|
description:
|
||||||
|
@ -4,7 +4,7 @@ description: This is the mobile application project, developed with Flutter for
|
|||||||
# pub.dev using `flutter pub publish`. This is preferred for private packages.
|
# pub.dev using `flutter pub publish`. This is preferred for private packages.
|
||||||
publish_to: "none" # Remove this line if you wish to publish to pub.dev
|
publish_to: "none" # Remove this line if you wish to publish to pub.dev
|
||||||
|
|
||||||
version: 1.0.0+1
|
version: 1.0.1+2
|
||||||
|
|
||||||
environment:
|
environment:
|
||||||
sdk: ">=3.0.6 <4.0.0"
|
sdk: ">=3.0.6 <4.0.0"
|
||||||
@ -40,6 +40,7 @@ dependencies:
|
|||||||
equatable: ^2.0.5
|
equatable: ^2.0.5
|
||||||
onesignal_flutter: ^5.2.0
|
onesignal_flutter: ^5.2.0
|
||||||
permission_handler: ^11.3.1
|
permission_handler: ^11.3.1
|
||||||
|
pin_code_fields: ^8.0.1
|
||||||
|
|
||||||
dev_dependencies:
|
dev_dependencies:
|
||||||
flutter_test:
|
flutter_test:
|
||||||
|
Reference in New Issue
Block a user