login Enhancements

This commit is contained in:
mohammad
2024-09-02 16:59:25 +03:00
parent 00bce2d0ab
commit 418f5d5406
3 changed files with 221 additions and 87 deletions

View File

@ -1,3 +1,4 @@
import 'package:dropdown_button2/dropdown_button2.dart';
import 'package:flutter/gestures.dart'; import 'package:flutter/gestures.dart';
import 'package:flutter/material.dart'; import 'package:flutter/material.dart';
import 'package:flutter_bloc/flutter_bloc.dart'; import 'package:flutter_bloc/flutter_bloc.dart';
@ -23,7 +24,8 @@ class LoginWebPage extends StatefulWidget {
State<LoginWebPage> createState() => _LoginWebPageState(); State<LoginWebPage> createState() => _LoginWebPageState();
} }
class _LoginWebPageState extends State<LoginWebPage> with HelperResponsiveLayout { class _LoginWebPageState extends State<LoginWebPage>
with HelperResponsiveLayout {
@override @override
Widget build(BuildContext context) { Widget build(BuildContext context) {
return Scaffold( return Scaffold(
@ -58,7 +60,8 @@ class _LoginWebPageState extends State<LoginWebPage> with HelperResponsiveLayout
_scrollController = ScrollController(); _scrollController = ScrollController();
void _scrollToCenter() { void _scrollToCenter() {
final double middlePosition = _scrollController.position.maxScrollExtent / 2; final double middlePosition =
_scrollController.position.maxScrollExtent / 2;
_scrollController.animateTo( _scrollController.animateTo(
middlePosition, middlePosition,
duration: const Duration(seconds: 1), duration: const Duration(seconds: 1),
@ -120,7 +123,8 @@ class _LoginWebPageState extends State<LoginWebPage> with HelperResponsiveLayout
const Spacer(), const Spacer(),
Expanded( Expanded(
flex: 2, flex: 2,
child: _buildLoginFormFields(context, loginBloc, size), child: _buildLoginFormFields(
context, loginBloc, size),
), ),
const Spacer(), const Spacer(),
], ],
@ -131,12 +135,14 @@ class _LoginWebPageState extends State<LoginWebPage> with HelperResponsiveLayout
), ),
), ),
), ),
if (state is AuthLoading) const Center(child: CircularProgressIndicator()) if (state is AuthLoading)
const Center(child: CircularProgressIndicator())
], ],
); );
} }
Widget _buildLoginFormFields(BuildContext context, AuthBloc loginBloc, Size size) { Widget _buildLoginFormFields(
BuildContext context, AuthBloc loginBloc, Size size) {
return Container( return Container(
decoration: BoxDecoration( decoration: BoxDecoration(
color: Colors.white.withOpacity(0.1), color: Colors.white.withOpacity(0.1),
@ -146,8 +152,8 @@ class _LoginWebPageState extends State<LoginWebPage> with HelperResponsiveLayout
child: Form( child: Form(
key: loginBloc.loginFormKey, key: loginBloc.loginFormKey,
child: Padding( child: Padding(
padding: padding: EdgeInsets.symmetric(
EdgeInsets.symmetric(horizontal: size.width * 0.02, vertical: size.width * 0.003), horizontal: size.width * 0.02, vertical: size.width * 0.003),
child: Column( child: Column(
mainAxisAlignment: MainAxisAlignment.spaceEvenly, mainAxisAlignment: MainAxisAlignment.spaceEvenly,
crossAxisAlignment: CrossAxisAlignment.start, crossAxisAlignment: CrossAxisAlignment.start,
@ -175,82 +181,190 @@ class _LoginWebPageState extends State<LoginWebPage> with HelperResponsiveLayout
); );
} }
Widget _buildDropdownField(BuildContext context, AuthBloc loginBloc, Size size) { // Widget _buildDropdownField(BuildContext context, AuthBloc loginBloc, Size size) {
// return 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(
// width: size.width * 0.8,
// child: LayoutBuilder(
// builder: (context, constraints) {
// return DropdownButtonFormField<String>(
// value: loginBloc.regionList!.any((region) => region.id == loginBloc.regionUuid)
// ? loginBloc.regionUuid
// : null,
// validator: loginBloc.validateRegion,
// icon: const Icon(
// Icons.keyboard_arrow_down_outlined,
// size: 20,
// ),
// decoration: textBoxDecoration()!.copyWith(
// errorStyle: const TextStyle(height: 0),
// contentPadding: const EdgeInsets.symmetric(
// vertical: 12,
// horizontal: 10,
// ),
// ),
// hint: Text(
// 'Select your region/country',
// 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: Container(
// constraints: BoxConstraints(maxWidth: constraints.maxWidth - 40),
// child: Text(
// region.name,
// overflow: TextOverflow.ellipsis,
// maxLines: 1,
// ),
// ),
// );
// }).toList(),
// onChanged: (String? value) {
// loginBloc.add(CheckEnableEvent());
// loginBloc.add(SelectRegionEvent(val: value!));
// },
// dropdownColor: Colors.white,
// menuMaxHeight: size.height * 0.45,
// selectedItemBuilder: (context) {
// return loginBloc.regionList!.map<Widget>((region) {
// return Container(
// constraints: BoxConstraints(maxWidth: constraints.maxWidth - 40),
// child: Text(
// region.name,
// overflow: TextOverflow.ellipsis,
// maxLines: 1,
// ),
// );
// }).toList();
// },
// );
// },
// ),
// ),
// ],
// );
// }
Widget _buildDropdownField(
BuildContext context, AuthBloc loginBloc, Size size) {
final TextEditingController textEditingController = TextEditingController();
return Column( return Column(
crossAxisAlignment: CrossAxisAlignment.start, crossAxisAlignment: CrossAxisAlignment.start,
mainAxisAlignment: MainAxisAlignment.start, mainAxisAlignment: MainAxisAlignment.start,
children: [ children: [
Text( Text(
"Country/Region", "Country/Region",
style: Theme.of(context) style: Theme.of(context).textTheme.bodySmall!.copyWith(
.textTheme fontSize: 14,
.bodySmall! fontWeight: FontWeight.w400,
.copyWith(fontSize: 14, fontWeight: FontWeight.w400), ),
), ),
const SizedBox(height: 10), const SizedBox(height: 10),
SizedBox( Container(
width: size.width * 0.8, height: size.height * 0.05,
child: LayoutBuilder( decoration:const BoxDecoration(
builder: (context, constraints) { color: ColorsManager.boxColor,
return DropdownButtonFormField<String>( borderRadius: BorderRadius.all(Radius.circular(8))),
value: loginBloc.regionList!.any((region) => region.id == loginBloc.regionUuid) width: size.width * 0.9,
? loginBloc.regionUuid child: DropdownButtonHideUnderline(
: null, child: DropdownButton2<String>(
validator: loginBloc.validateRegion, isExpanded: true,
icon: const Icon( hint: Text(
Icons.keyboard_arrow_down_outlined, 'Select your region/country',
size: 20, style: Theme.of(context).textTheme.bodySmall!.copyWith(
), color: ColorsManager.grayColor,
decoration: textBoxDecoration()!.copyWith( fontWeight: FontWeight.w400,
errorStyle: const TextStyle(height: 0), ),
contentPadding: const EdgeInsets.symmetric( overflow: TextOverflow.ellipsis,
vertical: 12, ),
horizontal: 10, items: loginBloc.regionList!.map((RegionModel region) {
return DropdownMenuItem<String>(
value: region.id,
child: Text(
region.name,
overflow: TextOverflow.ellipsis,
maxLines: 1,
), ),
), );
hint: Text( }).toList(),
'Select your region/country', value: loginBloc.regionList!.any(
style: Theme.of(context) (region) => region.id == loginBloc.regionUuid,
.textTheme )
.bodySmall! ? loginBloc.regionUuid
.copyWith(color: ColorsManager.grayColor, fontWeight: FontWeight.w400), : null,
overflow: TextOverflow.ellipsis, onChanged: (String? value) {
), if (value != null) {
isDense: true, loginBloc.add(CheckEnableEvent());
style: const TextStyle(color: Colors.black), loginBloc.add(SelectRegionEvent(val: value));
items: loginBloc.regionList!.map((RegionModel region) { }
return DropdownMenuItem<String>( },
value: region.id, buttonStyleData: const ButtonStyleData(
child: Container( padding: EdgeInsets.symmetric(horizontal: 16),
constraints: BoxConstraints(maxWidth: constraints.maxWidth - 40), height: 40,
child: Text( width: double.infinity,
region.name, ),
overflow: TextOverflow.ellipsis, dropdownStyleData: DropdownStyleData(
maxLines: 1, maxHeight: size.height * 0.45,
),
menuItemStyleData: const MenuItemStyleData(
height: 40,
),
dropdownSearchData: DropdownSearchData(
searchController: textEditingController,
searchInnerWidgetHeight: 50,
searchInnerWidget: Container(
height: 50,
padding: const EdgeInsets.symmetric(horizontal: 8, vertical: 4),
child: TextFormField(
style: TextStyle(color: Colors.black),
controller: textEditingController,
decoration: textBoxDecoration()!.copyWith(
errorStyle: const TextStyle(height: 0),
contentPadding: const EdgeInsets.symmetric(
vertical: 12,
horizontal: 10,
), ),
), ),
); ),
}).toList(), ),
onChanged: (String? value) {
loginBloc.add(CheckEnableEvent()); searchMatchFn: (item, searchValue) {
loginBloc.add(SelectRegionEvent(val: value!)); // Ensure both item value and search value are compared in lowercase for a case-insensitive match.
final itemValue = item.value?.toLowerCase() ?? '';
final search = searchValue.toLowerCase().trim();
// Debugging print statement to ensure values are captured correctly.
print('searchValue == $search');
// Return true if the item value contains the search term.
return itemValue.contains(search);
}, },
dropdownColor: Colors.white,
menuMaxHeight: size.height * 0.45, ),
selectedItemBuilder: (context) { onMenuStateChange: (isOpen) {
return loginBloc.regionList!.map<Widget>((region) { if (!isOpen) {
return Container( textEditingController.clear();
constraints: BoxConstraints(maxWidth: constraints.maxWidth - 40), }
child: Text( },
region.name, ),
overflow: TextOverflow.ellipsis,
maxLines: 1,
),
);
}).toList();
},
);
},
), ),
), ),
], ],
@ -280,10 +394,9 @@ class _LoginWebPageState extends State<LoginWebPage> with HelperResponsiveLayout
decoration: textBoxDecoration()!.copyWith( decoration: textBoxDecoration()!.copyWith(
errorStyle: const TextStyle(height: 0), errorStyle: const TextStyle(height: 0),
hintText: 'Enter your email address', hintText: 'Enter your email address',
hintStyle: Theme.of(context) hintStyle: Theme.of(context).textTheme.bodySmall!.copyWith(
.textTheme color: ColorsManager.grayColor,
.bodySmall! fontWeight: FontWeight.w400)),
.copyWith(color: ColorsManager.grayColor, fontWeight: FontWeight.w400)),
style: const TextStyle(color: Colors.black), style: const TextStyle(color: Colors.black),
), ),
), ),
@ -315,17 +428,18 @@ class _LoginWebPageState extends State<LoginWebPage> with HelperResponsiveLayout
controller: loginBloc.loginPasswordController, controller: loginBloc.loginPasswordController,
decoration: textBoxDecoration()!.copyWith( decoration: textBoxDecoration()!.copyWith(
hintText: 'At least 8 characters', hintText: 'At least 8 characters',
hintStyle: Theme.of(context) hintStyle: Theme.of(context).textTheme.bodySmall!.copyWith(
.textTheme color: ColorsManager.grayColor, fontWeight: FontWeight.w400),
.bodySmall!
.copyWith(color: ColorsManager.grayColor, fontWeight: FontWeight.w400),
suffixIcon: IconButton( suffixIcon: IconButton(
onPressed: () { onPressed: () {
loginBloc.add(PasswordVisibleEvent(newValue: loginBloc.obscureText)); loginBloc.add(
PasswordVisibleEvent(newValue: loginBloc.obscureText));
}, },
icon: SizedBox( icon: SizedBox(
child: SvgPicture.asset( child: SvgPicture.asset(
loginBloc.obscureText ? Assets.visiblePassword : Assets.invisiblePassword, loginBloc.obscureText
? Assets.visiblePassword
: Assets.invisiblePassword,
height: 15, height: 15,
width: 15, width: 15,
), ),
@ -353,10 +467,10 @@ class _LoginWebPageState extends State<LoginWebPage> with HelperResponsiveLayout
}, },
child: Text( child: Text(
"Forgot Password?", "Forgot Password?",
style: Theme.of(context) style: Theme.of(context).textTheme.bodySmall!.copyWith(
.textTheme color: Colors.black,
.bodySmall! fontSize: 14,
.copyWith(color: Colors.black, fontSize: 14, fontWeight: FontWeight.w400), fontWeight: FontWeight.w400),
), ),
), ),
], ],
@ -419,7 +533,8 @@ class _LoginWebPageState extends State<LoginWebPage> with HelperResponsiveLayout
); );
} }
Widget _buildSignInButton(BuildContext context, AuthBloc loginBloc, Size size) { Widget _buildSignInButton(
BuildContext context, AuthBloc loginBloc, Size size) {
return Row( return Row(
crossAxisAlignment: CrossAxisAlignment.center, crossAxisAlignment: CrossAxisAlignment.center,
mainAxisAlignment: MainAxisAlignment.center, mainAxisAlignment: MainAxisAlignment.center,
@ -460,7 +575,8 @@ class _LoginWebPageState extends State<LoginWebPage> with HelperResponsiveLayout
SizedBox( SizedBox(
child: Text( child: Text(
loginBloc.validate, loginBloc.validate,
style: const TextStyle(fontWeight: FontWeight.w700, color: ColorsManager.red), style: const TextStyle(
fontWeight: FontWeight.w700, color: ColorsManager.red),
), ),
) )
], ],

View File

@ -89,6 +89,22 @@ packages:
url: "https://pub.dev" url: "https://pub.dev"
source: hosted source: hosted
version: "1.0.1" version: "1.0.1"
dropdown_button2:
dependency: "direct main"
description:
name: dropdown_button2
sha256: b0fe8d49a030315e9eef6c7ac84ca964250155a6224d491c1365061bc974a9e1
url: "https://pub.dev"
source: hosted
version: "2.3.9"
dropdown_search:
dependency: "direct main"
description:
name: dropdown_search
sha256: "55106e8290acaa97ed15bea1fdad82c3cf0c248dd410e651f5a8ac6870f783ab"
url: "https://pub.dev"
source: hosted
version: "5.0.6"
equatable: equatable:
dependency: "direct main" dependency: "direct main"
description: description:

View File

@ -43,9 +43,11 @@ dependencies:
get_it: ^7.6.7 get_it: ^7.6.7
flutter_secure_storage: ^9.2.2 flutter_secure_storage: ^9.2.2
shared_preferences: ^2.3.0 shared_preferences: ^2.3.0
dropdown_button2: ^2.3.9
data_table_2: ^2.5.15 data_table_2: ^2.5.15
go_router: go_router:
intl: ^0.19.0 intl: ^0.19.0
dropdown_search: ^5.0.6
dev_dependencies: dev_dependencies:
flutter_test: flutter_test: