mirror of
https://github.com/SyncrowIOT/syncrow-app.git
synced 2025-07-16 18:16:21 +00:00
Added sign up screen and model
This commit is contained in:
@ -1,7 +1,9 @@
|
||||
import 'package:dio/dio.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_app/features/auth/model/login_with_email_model.dart';
|
||||
import 'package:syncrow_app/features/auth/model/signup_model.dart';
|
||||
import 'package:syncrow_app/features/auth/model/token.dart';
|
||||
import 'package:syncrow_app/features/auth/model/user_model.dart';
|
||||
import 'package:syncrow_app/navigation/navigation_service.dart';
|
||||
@ -16,7 +18,11 @@ class AuthCubit extends Cubit<AuthState> {
|
||||
|
||||
final TextEditingController emailController = TextEditingController();
|
||||
final TextEditingController passwordController = TextEditingController();
|
||||
|
||||
final TextEditingController emailSignUpController = TextEditingController();
|
||||
final TextEditingController passwordSignUpController = TextEditingController();
|
||||
final loginFormKey = GlobalKey<FormState>();
|
||||
final signUpFormKey = GlobalKey<FormState>();
|
||||
bool isPasswordVisible = false;
|
||||
|
||||
static GlobalKey<FormState> formKey = GlobalKey<FormState>();
|
||||
@ -118,6 +124,30 @@ class AuthCubit extends Cubit<AuthState> {
|
||||
}
|
||||
}
|
||||
|
||||
signUp() async {
|
||||
emit(AuthLoginLoading());
|
||||
final response;
|
||||
try {
|
||||
response = await AuthenticationAPI.signUp(
|
||||
model: SignUpModel(
|
||||
email: emailController.text.toLowerCase(),
|
||||
password: passwordController.text,
|
||||
firstName: '',
|
||||
lastName: ''),
|
||||
);
|
||||
} catch (failure) {
|
||||
emit(AuthLoginError(message: failure.toString()));
|
||||
return;
|
||||
}
|
||||
if (response['statusCode'] == 201) {
|
||||
emailController.clear();
|
||||
passwordController.clear();
|
||||
emit(AuthLoginSuccess());
|
||||
} else {
|
||||
emit(AuthLoginError(message: 'Something went wrong'));
|
||||
}
|
||||
}
|
||||
|
||||
logout() async {
|
||||
emit(AuthLogoutLoading());
|
||||
try {
|
||||
|
29
lib/features/auth/model/signup_model.dart
Normal file
29
lib/features/auth/model/signup_model.dart
Normal file
@ -0,0 +1,29 @@
|
||||
class SignUpModel {
|
||||
final String email;
|
||||
final String password;
|
||||
final String firstName;
|
||||
final String lastName;
|
||||
|
||||
SignUpModel(
|
||||
{required this.email,
|
||||
required this.password,
|
||||
required this.firstName,
|
||||
required this.lastName});
|
||||
|
||||
factory SignUpModel.fromJson(Map<String, dynamic> json) {
|
||||
return SignUpModel(
|
||||
email: json['email'],
|
||||
password: json['password'],
|
||||
firstName: json['firstName'],
|
||||
lastName: json['lastName']);
|
||||
}
|
||||
|
||||
Map<String, dynamic> toJson() {
|
||||
return {
|
||||
'email': email,
|
||||
'password': password,
|
||||
'firstName': firstName,
|
||||
'lastName': lastName,
|
||||
};
|
||||
}
|
||||
}
|
@ -46,8 +46,7 @@ class LoginForm extends StatelessWidget {
|
||||
FocusScope.of(context).unfocus();
|
||||
},
|
||||
onChanged: (value) {},
|
||||
decoration: defaultInputDecoration(context,
|
||||
hint: "Example@email.com"),
|
||||
decoration: defaultInputDecoration(context, hint: "Example@email.com"),
|
||||
),
|
||||
const SizedBox(height: 10),
|
||||
const BodyMedium(
|
||||
@ -72,8 +71,7 @@ class LoginForm extends StatelessWidget {
|
||||
FocusScope.of(context).unfocus();
|
||||
},
|
||||
obscureText: !AuthCubit.get(context).isPasswordVisible,
|
||||
decoration: defaultInputDecoration(context,
|
||||
hint: "At least 8 characters"),
|
||||
decoration: defaultInputDecoration(context, hint: "At least 8 characters"),
|
||||
),
|
||||
const SizedBox(height: 10),
|
||||
// const LoginUserAgreement(),
|
||||
|
@ -1,10 +1,216 @@
|
||||
import 'package:flutter/material.dart';
|
||||
import 'package:flutter_bloc/flutter_bloc.dart';
|
||||
import 'package:flutter_svg/svg.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/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 SignUpView extends StatelessWidget {
|
||||
const SignUpView({super.key});
|
||||
|
||||
@override
|
||||
Widget build(BuildContext context) {
|
||||
return const Placeholder();
|
||||
final formKey = AuthCubit.get(context).signUpFormKey;
|
||||
return BlocConsumer<AuthCubit, AuthState>(
|
||||
listener: (context, state) {
|
||||
if (state is AuthError) {
|
||||
// ScaffoldMessenger.of(context).showSnackBar(
|
||||
// SnackBar(
|
||||
// content: Text(state.message),
|
||||
// ),
|
||||
// );
|
||||
} else if (state is AuthLoginSuccess) {
|
||||
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: 'Create new account',
|
||||
style: context.titleMedium.copyWith(
|
||||
fontWeight: FontsManager.extraBold,
|
||||
color: Colors.white,
|
||||
),
|
||||
),
|
||||
const SizedBox(
|
||||
height: 20,
|
||||
),
|
||||
Form(
|
||||
key: formKey,
|
||||
autovalidateMode: AutovalidateMode.onUserInteraction,
|
||||
child: SingleChildScrollView(
|
||||
child: Column(
|
||||
crossAxisAlignment: CrossAxisAlignment.start,
|
||||
children: [
|
||||
const BodyMedium(
|
||||
text: "Email",
|
||||
fontColor: Colors.white,
|
||||
),
|
||||
TextFormField(
|
||||
autovalidateMode: AutovalidateMode.disabled,
|
||||
textInputAction: TextInputAction.done,
|
||||
keyboardType: TextInputType.text,
|
||||
scrollPadding: EdgeInsets.zero,
|
||||
autocorrect: false,
|
||||
autofillHints: const [AutofillHints.email],
|
||||
controller: AuthCubit.get(context).emailController,
|
||||
validator: (value) {
|
||||
return AuthCubit.get(context).emailAddressValidator(value);
|
||||
},
|
||||
onTapOutside: (event) {
|
||||
FocusScope.of(context).unfocus();
|
||||
},
|
||||
onChanged: (value) {},
|
||||
decoration:
|
||||
defaultInputDecoration(context, hint: "Example@email.com"),
|
||||
),
|
||||
const SizedBox(height: 15),
|
||||
const BodyMedium(
|
||||
text: "Password",
|
||||
fontColor: Colors.white,
|
||||
),
|
||||
TextFormField(
|
||||
autovalidateMode: AutovalidateMode.disabled,
|
||||
textInputAction: TextInputAction.done,
|
||||
keyboardType: TextInputType.text,
|
||||
scrollPadding: EdgeInsets.zero,
|
||||
autocorrect: false,
|
||||
autofillHints: const [AutofillHints.password],
|
||||
controller: AuthCubit.get(context).passwordController,
|
||||
validator: (value) {
|
||||
return AuthCubit.get(context).passwordValidator(value);
|
||||
},
|
||||
onTapOutside: (event) {
|
||||
FocusScope.of(context).unfocus();
|
||||
},
|
||||
obscureText: !AuthCubit.get(context).isPasswordVisible,
|
||||
decoration: defaultInputDecoration(context,
|
||||
hint: "At least 8 characters"),
|
||||
),
|
||||
const SizedBox(height: 15),
|
||||
const BodyMedium(
|
||||
text: "Re-enter Password",
|
||||
fontColor: Colors.white,
|
||||
),
|
||||
TextFormField(
|
||||
autovalidateMode: AutovalidateMode.disabled,
|
||||
textInputAction: TextInputAction.done,
|
||||
keyboardType: TextInputType.text,
|
||||
scrollPadding: EdgeInsets.zero,
|
||||
autocorrect: false,
|
||||
autofillHints: const [AutofillHints.password],
|
||||
controller: AuthCubit.get(context).passwordController,
|
||||
validator: (value) {
|
||||
return AuthCubit.get(context).passwordValidator(value);
|
||||
},
|
||||
onTapOutside: (event) {
|
||||
FocusScope.of(context).unfocus();
|
||||
},
|
||||
obscureText: !AuthCubit.get(context).isPasswordVisible,
|
||||
decoration: defaultInputDecoration(context,
|
||||
hint: "At least 8 characters"),
|
||||
),
|
||||
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(
|
||||
'Sign up',
|
||||
),
|
||||
onPressed: () {
|
||||
if (formKey.currentState!.validate()) {
|
||||
if ((state is! AuthLoading)) {
|
||||
AuthCubit.get(context).login();
|
||||
FocusScope.of(context).unfocus();
|
||||
}
|
||||
}
|
||||
},
|
||||
),
|
||||
),
|
||||
],
|
||||
)
|
||||
],
|
||||
),
|
||||
),
|
||||
),
|
||||
],
|
||||
),
|
||||
),
|
||||
),
|
||||
)
|
||||
],
|
||||
),
|
||||
),
|
||||
);
|
||||
},
|
||||
);
|
||||
;
|
||||
}
|
||||
}
|
||||
|
@ -53,6 +53,7 @@ class _DoorLockButtonState extends State<DoorLockButton> with SingleTickerProvid
|
||||
// }
|
||||
BlocProvider.of<SmartDoorBloc>(context)
|
||||
.add(UpdateLockEvent(value: smartDoorModel.normalOpenSwitch));
|
||||
_animationController.reverse();
|
||||
} else if (_animation.status == AnimationStatus.dismissed) {
|
||||
// if (widget.doorLock.status
|
||||
// .firstWhere((element) => element.code == 'normal_open_switch')
|
||||
@ -98,11 +99,11 @@ class _DoorLockButtonState extends State<DoorLockButton> with SingleTickerProvid
|
||||
}
|
||||
},
|
||||
onTapUp: (details) {
|
||||
if (_animationController.status == AnimationStatus.forward) {
|
||||
_animationController.reverse();
|
||||
} else if (_animationController.status == AnimationStatus.reverse) {
|
||||
_animationController.forward();
|
||||
}
|
||||
// if (_animationController.status == AnimationStatus.forward) {
|
||||
// _animationController.reverse();
|
||||
// } else if (_animationController.status == AnimationStatus.reverse) {
|
||||
// _animationController.forward();
|
||||
// }
|
||||
},
|
||||
child: Container(
|
||||
width: context.width * 06,
|
||||
|
@ -1,4 +1,5 @@
|
||||
import 'package:syncrow_app/features/auth/model/login_with_email_model.dart';
|
||||
import 'package:syncrow_app/features/auth/model/signup_model.dart';
|
||||
import 'package:syncrow_app/features/auth/model/token.dart';
|
||||
import 'package:syncrow_app/features/auth/model/verify_code.dart';
|
||||
import 'package:syncrow_app/services/api/api_links_endpoints.dart';
|
||||
@ -14,8 +15,7 @@ class AuthenticationAPI {
|
||||
return response;
|
||||
}
|
||||
|
||||
static Future<Token> loginWithEmail(
|
||||
{required LoginWithEmailModel model}) async {
|
||||
static Future<Token> loginWithEmail({required LoginWithEmailModel model}) async {
|
||||
final response = await HTTPService().post(
|
||||
path: ApiEndpoints.login,
|
||||
body: model.toJson(),
|
||||
@ -23,4 +23,13 @@ class AuthenticationAPI {
|
||||
expectedResponseModel: (json) => Token.fromJson(json['data']));
|
||||
return response;
|
||||
}
|
||||
|
||||
static Future<Token> signUp({required SignUpModel model}) async {
|
||||
final response = await HTTPService().post(
|
||||
path: ApiEndpoints.signUp,
|
||||
body: model.toJson(),
|
||||
showServerMessage: false,
|
||||
expectedResponseModel: (json) => Token.fromJson(json['data']));
|
||||
return response;
|
||||
}
|
||||
}
|
||||
|
Reference in New Issue
Block a user