Files
syncrow-web/lib/pages/auth/view/login_web_page.dart
2024-08-31 15:35:17 +03:00

535 lines
31 KiB
Dart

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:go_router/go_router.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/model/region_model.dart';
import 'package:syncrow_web/pages/auth/view/forget_password_page.dart';
import 'package:syncrow_web/pages/common/buttons/default_button.dart';
import 'package:syncrow_web/pages/common/first_layer.dart';
import 'package:syncrow_web/utils/color_manager.dart';
import 'package:syncrow_web/utils/constants/assets.dart';
import 'package:syncrow_web/utils/constants/routes_const.dart';
import 'package:syncrow_web/utils/style.dart';
class LoginWebPage extends StatefulWidget {
const LoginWebPage({super.key});
@override
State<LoginWebPage> createState() => _LoginWebPageState();
}
class _LoginWebPageState extends State<LoginWebPage> {
@override
Widget build(BuildContext context) {
return Scaffold(
body: BlocProvider(
create: (BuildContext context) => AuthBloc()..add(RegionInitialEvent()),
child: BlocConsumer<AuthBloc, AuthState>(
listener: (context, state) {
if (state is LoginSuccess) {
GoRouter.of(context).go(RoutesConst.home);
} else if (state is LoginFailure) {
ScaffoldMessenger.of(context).showSnackBar(
SnackBar(
content: Text(state.error),
),
);
}
},
builder: (context, state) {
return _buildLoginForm(context, state);
},
),
),
);
}
Widget _buildLoginForm(BuildContext context, AuthState state) {
final loginBloc = BlocProvider.of<AuthBloc>(context);
Size size = MediaQuery.of(context).size;
late ScrollController _scrollController;
_scrollController = ScrollController();
void _scrollToCenter() {
final double middlePosition =
_scrollController.position.maxScrollExtent / 2;
_scrollController.animateTo(
middlePosition,
duration: const Duration(seconds: 1),
curve: Curves.easeInOut,
);
}
WidgetsBinding.instance.addPostFrameCallback((_) {
_scrollToCenter();
});
return Stack(
children: [
FirstLayer(
second: Center(
child: ListView(
controller: _scrollController,
shrinkWrap: true,
children: [
Container(
padding: EdgeInsets.all(size.width * 0.02),
margin: EdgeInsets.all(size.width * 0.09),
decoration: BoxDecoration(
color: Colors.black.withOpacity(0.3),
borderRadius: const BorderRadius.all(Radius.circular(20)),
),
child: Center(
child: Row(
crossAxisAlignment: CrossAxisAlignment.center,
mainAxisAlignment: MainAxisAlignment.center,
children: [
const Spacer(),
Expanded(
flex: 3,
child: SvgPicture.asset(
Assets.loginLogo,
),
),
const Spacer(),
Expanded(
flex: 3,
child: Container(
decoration: BoxDecoration(
color: Colors.white.withOpacity(0.1),
borderRadius: const BorderRadius.all(
Radius.circular(30)),
border: Border.all(
color: ColorsManager.graysColor
.withOpacity(0.2))),
child: Form(
key: loginBloc.loginFormKey,
child: Padding(
padding: EdgeInsets.symmetric(
horizontal: size.width * 0.02,
vertical: size.width * 0.003),
child: Column(
mainAxisAlignment:
MainAxisAlignment.spaceEvenly,
crossAxisAlignment:
CrossAxisAlignment.start,
children: <Widget>[
const SizedBox(height: 40),
Text('Login',
style: Theme.of(context)
.textTheme
.headlineLarge),
SizedBox(height: size.height * 0.03),
Column(
crossAxisAlignment:
CrossAxisAlignment.start,
mainAxisAlignment:
MainAxisAlignment.start,
children: [
Text(
"Country/Region",
style: Theme.of(context)
.textTheme
.bodySmall!
.copyWith(
fontSize: 14,
fontWeight:
FontWeight.w400),
),
const SizedBox(
height: 10,
),
SizedBox(
child: DropdownButtonFormField<
String>(
padding: EdgeInsets.zero,
value: loginBloc.regionList!
.any((region) =>
region.id ==
loginBloc
.regionUuid)
? loginBloc.regionUuid
: null,
validator:
loginBloc.validateRegion,
icon: const Icon(
Icons
.keyboard_arrow_down_outlined,
),
decoration: textBoxDecoration()!
.copyWith(
errorStyle: const TextStyle(
height: 0),
hintText: null,
),
hint: SizedBox(
width: size.width * 0.12,
child: Align(
alignment:
Alignment.centerLeft,
child: Text(
'Select your region/country',
textAlign:
TextAlign.center,
style: Theme.of(context)
.textTheme
.bodySmall!
.copyWith(
color:
ColorsManager
.grayColor,
fontWeight:
FontWeight
.w400),
overflow:
TextOverflow.ellipsis,
),
),
),
isDense: true,
style: const TextStyle(
color: Colors.black),
items: loginBloc.regionList!
.map((RegionModel region) {
return DropdownMenuItem<
String>(
value: region.id,
child: SizedBox(
width:
size.width * 0.08,
child:
Text(region.name)),
);
}).toList(),
onChanged: (String? value) {
loginBloc
.add(CheckEnableEvent());
loginBloc.add(
SelectRegionEvent(
val: value!));
},
),
)
],
),
const SizedBox(height: 20.0),
Column(
crossAxisAlignment:
CrossAxisAlignment.start,
mainAxisAlignment:
MainAxisAlignment.start,
children: [
Text(
"Email",
style: Theme.of(context)
.textTheme
.bodySmall!
.copyWith(
fontSize: 14,
fontWeight:
FontWeight.w400),
),
const SizedBox(
height: 10,
),
SizedBox(
child: TextFormField(
onChanged: (value) {
loginBloc
.add(CheckEnableEvent());
},
validator: loginBloc
.loginValidateEmail,
controller: loginBloc
.loginEmailController,
decoration: textBoxDecoration()!
.copyWith(
errorStyle: const TextStyle(
height:
0), // Hide the error text space
hintText:
'Enter your email address',
hintStyle: Theme.of(
context)
.textTheme
.bodySmall!
.copyWith(
color: ColorsManager
.grayColor,
fontWeight:
FontWeight
.w400)),
style: const TextStyle(
color: Colors.black),
),
),
],
),
const SizedBox(height: 20.0),
Column(
crossAxisAlignment:
CrossAxisAlignment.start,
mainAxisAlignment:
MainAxisAlignment.start,
children: [
Text(
"Password",
style: Theme.of(context)
.textTheme
.bodySmall!
.copyWith(
fontSize: 14,
fontWeight:
FontWeight.w400),
),
const SizedBox(
height: 10,
),
SizedBox(
child: TextFormField(
onChanged: (value) {
loginBloc
.add(CheckEnableEvent());
},
validator:
loginBloc.validatePassword,
obscureText:
loginBloc.obscureText,
keyboardType: TextInputType
.visiblePassword,
controller: loginBloc
.loginPasswordController,
decoration: textBoxDecoration()!
.copyWith(
hintText:
'At least 8 characters',
hintStyle: Theme.of(context)
.textTheme
.bodySmall!
.copyWith(
color: ColorsManager
.grayColor,
fontWeight:
FontWeight.w400),
suffixIcon: IconButton(
onPressed: () {
loginBloc.add(
PasswordVisibleEvent(
newValue: loginBloc
.obscureText));
},
icon: SizedBox(
child: SvgPicture.asset(
loginBloc.obscureText
? Assets
.visiblePassword
: Assets
.invisiblePassword,
height: 15,
width: 15,
),
),
),
errorStyle: const TextStyle(
height:
0), // Hide the error text space
),
style: const TextStyle(
color: Colors.black),
),
),
],
),
const SizedBox(
height: 20,
),
SizedBox(
child: Row(
mainAxisAlignment:
MainAxisAlignment.end,
children: [
InkWell(
onTap: () {
Navigator.of(context)
.push(MaterialPageRoute(
builder: (context) =>
const ForgetPasswordPage(),
));
},
child: Text(
"Forgot Password?",
style: Theme.of(context)
.textTheme
.bodySmall!
.copyWith(
color: Colors.black,
fontSize: 14,
fontWeight:
FontWeight.w400),
),
),
],
),
),
const SizedBox(
height: 20,
),
Row(
children: [
Transform.scale(
scale:
1.2, // Adjust the scale as needed
child: Checkbox(
fillColor: MaterialStateProperty
.all<Color>(Colors.white),
activeColor: Colors.white,
value: loginBloc.isChecked,
checkColor: Colors.black,
shape: const CircleBorder(),
onChanged: (bool? newValue) {
loginBloc.add(CheckBoxEvent(
newValue: newValue));
},
),
),
SizedBox(
width: size.width * 0.14,
child: RichText(
text: TextSpan(
text: 'Agree to ',
style: const TextStyle(
color: Colors.white),
children: [
TextSpan(
text:
'(Terms of Service)',
style: const TextStyle(
color: Colors.black,
),
recognizer:
TapGestureRecognizer()
..onTap = () {
loginBloc.launchURL(
'https://example.com/terms');
},
),
TextSpan(
text:
' (Legal Statement)',
style: const TextStyle(
color: Colors.black),
recognizer:
TapGestureRecognizer()
..onTap = () {
loginBloc.launchURL(
'https://example.com/legal');
},
),
TextSpan(
text:
' (Privacy Statement)',
style: const TextStyle(
color: Colors.black),
recognizer:
TapGestureRecognizer()
..onTap = () {
loginBloc.launchURL(
'https://example.com/privacy');
},
),
],
),
),
),
],
),
const SizedBox(height: 20.0),
Row(
crossAxisAlignment:
CrossAxisAlignment.center,
mainAxisAlignment:
MainAxisAlignment.center,
children: [
SizedBox(
width: size.width * 0.2,
child: DefaultButton(
enabled:
loginBloc.checkValidate,
child: Text('Sign in',
style: Theme.of(context)
.textTheme
.labelLarge!
.copyWith(
fontSize: 14,
color: loginBloc
.checkValidate
? ColorsManager
.whiteColors
: ColorsManager
.whiteColors
.withOpacity(
0.2),
)),
onPressed: () {
if (loginBloc.loginFormKey
.currentState!
.validate()) {
loginBloc
.add(LoginButtonPressed(
regionUuid:
loginBloc.regionUuid,
username: loginBloc
.loginEmailController
.text,
password: loginBloc
.loginPasswordController
.text,
));
} else {
loginBloc.add(
ChangeValidateEvent());
}
},
),
),
],
),
const SizedBox(height: 15.0),
Row(
crossAxisAlignment:
CrossAxisAlignment.center,
mainAxisAlignment:
MainAxisAlignment.center,
children: [
SizedBox(
child: Text(
loginBloc.validate,
style: const TextStyle(
fontWeight: FontWeight.w700,
color: ColorsManager.red),
),
)
],
)
],
),
),
))),
const Spacer(),
],
),
),
),
],
),
),
),
if (state is AuthLoading)
const Center(child: CircularProgressIndicator())
],
);
}
}