Compare commits
	
		
			7 Commits
		
	
	
		
			main
			...
			4b4b42beae
		
	
	| Author | SHA1 | Date | |
|---|---|---|---|
| 4b4b42beae | |||
| dacf5461f3 | |||
| 5d4bc47adf | |||
| 80e4657240 | |||
| ff1886cec1 | |||
| 1616f22925 | |||
| 0b754bf939 | 
							
								
								
									
										
											BIN
										
									
								
								assets/icons/icon-shield.png
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										
											BIN
										
									
								
								assets/icons/icon-shield.png
									
									
									
									
									
										Normal file
									
								
							
										
											Binary file not shown.
										
									
								
							| After Width: | Height: | Size: 1.6 KiB | 
							
								
								
									
										
											BIN
										
									
								
								assets/images/img-success-signup.png
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										
											BIN
										
									
								
								assets/images/img-success-signup.png
									
									
									
									
									
										Normal file
									
								
							
										
											Binary file not shown.
										
									
								
							| After Width: | Height: | Size: 88 KiB | 
| @@ -10,6 +10,7 @@ class PathAssets { | ||||
|   static const String iconGoogle = 'assets/icons/icon-google.png'; | ||||
|   static const String icon1 = 'assets/icons/icon-1.png'; | ||||
|   static const String iconConnect = 'assets/icons/icon-connect.png'; | ||||
|   static const String iconShield = 'assets/icons/icon-shield.png'; | ||||
|  | ||||
|   /// IMAGE | ||||
|   static const String imgSplashLogo = 'assets/images/splash-logo.png'; | ||||
| @@ -22,4 +23,5 @@ class PathAssets { | ||||
|   static const String imgKtpCropped = 'assets/images/img-ktp-cropped.png'; | ||||
|   static const String imgKtpClear = 'assets/images/img-ktp-clear.png'; | ||||
|   static const String imgKtpBlur = 'assets/images/img-ktp-blur.png'; | ||||
|   static const String imgSuccessSignup = 'assets/images/img-success-signup.png'; | ||||
| } | ||||
|   | ||||
| @@ -55,78 +55,80 @@ class ButtonView extends StatelessWidget { | ||||
|     final widthPrefix = | ||||
|         this.widthPrefix ?? (heightWrapContent ? width! / 4.7 : _widthBtn / 16); | ||||
|  | ||||
|     return Container( | ||||
|       margin: EdgeInsets.symmetric(vertical: marginVertical ?? 32.0), | ||||
|       width: width ?? _widthBtn, | ||||
|       height: heightWrapContent ? null : height ?? _heightBtn, | ||||
|       child: ElevatedButton( | ||||
|         style: ElevatedButton.styleFrom( | ||||
|           disabledBackgroundColor: isOutlined ? Colors.white : color.surface, | ||||
|           padding: contentPadding, | ||||
|           backgroundColor: backgroundColor ?? | ||||
|               (isOutlined | ||||
|                   ? Colors.white | ||||
|                   : isSecondaryColor | ||||
|                       ? ColorPalette.grey | ||||
|                       : ColorPalette.primary), | ||||
|           elevation: 0, | ||||
|           shape: RoundedRectangleBorder( | ||||
|             borderRadius: BorderRadius.circular(sizeBorderRadius ?? 48), | ||||
|             side: isOutlined | ||||
|                 ? BorderSide( | ||||
|                     color: disabled | ||||
|                         ? color.surface | ||||
|                         : isSecondaryColor | ||||
|                             ? ColorPalette.greyBorder | ||||
|                             : ColorPalette.primary, | ||||
|                   ) | ||||
|                 : BorderSide.none, | ||||
|     return Center( | ||||
|       child: Container( | ||||
|         margin: EdgeInsets.symmetric(vertical: marginVertical ?? 24.0), | ||||
|         width: width ?? _widthBtn, | ||||
|         height: heightWrapContent ? null : height ?? _heightBtn, | ||||
|         child: ElevatedButton( | ||||
|           style: ElevatedButton.styleFrom( | ||||
|             disabledBackgroundColor: isOutlined ? Colors.white : color.surface, | ||||
|             padding: contentPadding, | ||||
|             backgroundColor: backgroundColor ?? | ||||
|                 (isOutlined | ||||
|                     ? Colors.white | ||||
|                     : isSecondaryColor | ||||
|                         ? ColorPalette.grey | ||||
|                         : ColorPalette.primary), | ||||
|             elevation: 0, | ||||
|             shape: RoundedRectangleBorder( | ||||
|               borderRadius: BorderRadius.circular(sizeBorderRadius ?? 48), | ||||
|               side: isOutlined | ||||
|                   ? BorderSide( | ||||
|                       color: disabled | ||||
|                           ? ColorPalette.greyBorder | ||||
|                           : isSecondaryColor | ||||
|                               ? ColorPalette.greyBorder | ||||
|                               : ColorPalette.primary, | ||||
|                     ) | ||||
|                   : BorderSide.none, | ||||
|             ), | ||||
|           ), | ||||
|         ), | ||||
|         onPressed: disabled ? null : onPressed, | ||||
|         child: Row( | ||||
|           mainAxisAlignment: mainAxisAlignmentContent ?? | ||||
|               (prefixIcon != null | ||||
|                   ? MainAxisAlignment.center | ||||
|                   : suffixIcon != null | ||||
|                       ? MainAxisAlignment.end | ||||
|                       : MainAxisAlignment.center), | ||||
|           children: [ | ||||
|             if (prefixIcon != null) ...[ | ||||
|               prefixIcon!, | ||||
|               SizedBox(width: widthPrefix), | ||||
|             ] else | ||||
|               Container(), | ||||
|             Flexible( | ||||
|               child: Text( | ||||
|                 name, | ||||
|                 textAlign: TextAlign.center, | ||||
|                 maxLines: maxLines, | ||||
|                 overflow: TextOverflow.ellipsis, | ||||
|                 style: TextStyle( | ||||
|                   fontSize: textSize ?? 16, | ||||
|                   fontWeight: textWeight, | ||||
|                   color: textColor ?? | ||||
|                       (disabled && isOutlined | ||||
|                           ? color.primary | ||||
|                           : disabled | ||||
|                               ? Colors.white | ||||
|                               : isOutlined && isSecondaryColor | ||||
|                                   ? ColorPalette.blackFont | ||||
|                                   : isOutlined | ||||
|                                       ? color.primary | ||||
|                                       : isSecondaryColor | ||||
|                                           ? Colors.white | ||||
|                                           : Colors.white), | ||||
|           onPressed: disabled ? null : onPressed, | ||||
|           child: Row( | ||||
|             mainAxisAlignment: mainAxisAlignmentContent ?? | ||||
|                 (prefixIcon != null | ||||
|                     ? MainAxisAlignment.center | ||||
|                     : suffixIcon != null | ||||
|                         ? MainAxisAlignment.end | ||||
|                         : MainAxisAlignment.center), | ||||
|             children: [ | ||||
|               if (prefixIcon != null) ...[ | ||||
|                 prefixIcon!, | ||||
|                 SizedBox(width: widthPrefix), | ||||
|               ] else | ||||
|                 Container(), | ||||
|               Flexible( | ||||
|                 child: Text( | ||||
|                   name, | ||||
|                   textAlign: TextAlign.center, | ||||
|                   maxLines: maxLines, | ||||
|                   overflow: TextOverflow.ellipsis, | ||||
|                   style: TextStyle( | ||||
|                     fontSize: textSize ?? 16, | ||||
|                     fontWeight: textWeight, | ||||
|                     color: textColor ?? | ||||
|                         (disabled && isOutlined | ||||
|                             ? color.primary | ||||
|                             : disabled | ||||
|                                 ? Colors.white | ||||
|                                 : isOutlined && isSecondaryColor | ||||
|                                     ? ColorPalette.blackFont | ||||
|                                     : isOutlined | ||||
|                                         ? color.primary | ||||
|                                         : isSecondaryColor | ||||
|                                             ? Colors.white | ||||
|                                             : Colors.white), | ||||
|                   ), | ||||
|                 ), | ||||
|               ), | ||||
|             ), | ||||
|             if (suffixIcon != null) ...[ | ||||
|               SizedBox(width: widthSuffix), | ||||
|               suffixIcon! | ||||
|             ] else | ||||
|               Container() | ||||
|           ], | ||||
|               if (suffixIcon != null) ...[ | ||||
|                 SizedBox(width: widthSuffix), | ||||
|                 suffixIcon! | ||||
|               ] else | ||||
|                 Container() | ||||
|             ], | ||||
|           ), | ||||
|         ), | ||||
|       ), | ||||
|     ); | ||||
|   | ||||
							
								
								
									
										123
									
								
								lib/application/component/otp/otp_view.dart
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										123
									
								
								lib/application/component/otp/otp_view.dart
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1,123 @@ | ||||
| import 'package:cims_apps/application/component/button/button_view.dart'; | ||||
| import 'package:cims_apps/application/component/otp/otp_viewmodel.dart'; | ||||
| import 'package:cims_apps/application/component/text_caption/text_caption.dart'; | ||||
| import 'package:cims_apps/application/theme/color_palette.dart'; | ||||
| import 'package:cims_apps/core/route/route.dart'; | ||||
| import 'package:cims_apps/core/utils/size_config.dart'; | ||||
| import 'package:cims_apps/features/auth/registration/view/registration_password_view.dart'; | ||||
| import 'package:flutter/material.dart'; | ||||
| import 'package:pinput/pinput.dart'; | ||||
| import 'package:provider/provider.dart'; | ||||
|  | ||||
| class OtpView extends StatelessWidget { | ||||
|   final String title; | ||||
|   final String? contentTitle, contentSubtitle; | ||||
|   const OtpView({ | ||||
|     Key? key, | ||||
|     required this.title, | ||||
|     this.contentTitle, | ||||
|     this.contentSubtitle, | ||||
|   }) : super(key: key); | ||||
|  | ||||
|   Widget _otpContent(BuildContext context, OtpViewModel provider) { | ||||
|     return Form( | ||||
|         key: provider.formKey, | ||||
|         child: Column( | ||||
|           children: [ | ||||
|             Pinput( | ||||
|               length: 4, | ||||
|               controller: provider.ctrlPin, | ||||
|               focusNode: provider.focusNode, | ||||
|               mainAxisAlignment: MainAxisAlignment.spaceBetween, | ||||
|               validator: (value) { | ||||
|                 if (value!.isEmpty) { | ||||
|                   return 'Pin must be complete'; | ||||
|                 } | ||||
|                 return null; | ||||
|               }, | ||||
|               defaultPinTheme: PinTheme( | ||||
|                 textStyle: const TextStyle( | ||||
|                   color: ColorPalette.slate800, | ||||
|                   fontSize: 24, | ||||
|                   fontWeight: FontWeight.bold, | ||||
|                 ), | ||||
|                 width: SizeConfig.width * .19, | ||||
|                 height: SizeConfig.height * .08, | ||||
|                 decoration: BoxDecoration( | ||||
|                   border: Border.all(color: const Color(0xFFE2E8F0)), | ||||
|                   borderRadius: BorderRadius.circular(8), | ||||
|                 ), | ||||
|               ), | ||||
|               errorPinTheme: PinTheme( | ||||
|                 textStyle: const TextStyle( | ||||
|                   color: ColorPalette.slate800, | ||||
|                   fontSize: 24, | ||||
|                   fontWeight: FontWeight.bold, | ||||
|                 ), | ||||
|                 width: SizeConfig.width * .19, | ||||
|                 height: SizeConfig.height * .08, | ||||
|                 decoration: BoxDecoration( | ||||
|                   border: Border.all(color: Colors.redAccent), | ||||
|                   borderRadius: BorderRadius.circular(8), | ||||
|                 ), | ||||
|               ), | ||||
|             ), | ||||
|             ButtonView( | ||||
|               name: 'Verify', | ||||
|               // disabled: !provider.buttonIsActive, | ||||
|               // backgroundColor: ColorPalette.grey, | ||||
|               onPressed: () { | ||||
|                 if (provider.formKey.currentState!.validate()) { | ||||
|                   final pin = provider.ctrlPin.text; | ||||
|                   provider.validateOtp(pin).then((value) { | ||||
|                     if (value) { | ||||
|                       routePush(context, | ||||
|                           page: const RegistrationPasswordView(), | ||||
|                           routeType: RouteType.pushReplace); | ||||
|                     } else { | ||||
|                       provider.ctrlPin.clear(); | ||||
|                     } | ||||
|                   }); | ||||
|                 } | ||||
|               }, | ||||
|             ), | ||||
|           ], | ||||
|         )); | ||||
|   } | ||||
|  | ||||
|   @override | ||||
|   Widget build(BuildContext context) { | ||||
|     return ChangeNotifierProvider( | ||||
|         create: (context) => OtpViewModel(), | ||||
|         builder: (context, child) { | ||||
|           return Scaffold( | ||||
|             appBar: AppBar( | ||||
|               title: Text(title), | ||||
|             ), | ||||
|             body: Container( | ||||
|               padding: const EdgeInsets.all(16.0), | ||||
|               child: | ||||
|                   Consumer<OtpViewModel>(builder: (context, provider, child) { | ||||
|                 return Column( | ||||
|                   children: [ | ||||
|                     TextCaption( | ||||
|                       title: contentTitle ?? '', | ||||
|                       subtitle: contentSubtitle ?? '', | ||||
|                     ), | ||||
|                     _otpContent(context, provider), | ||||
|                     TextButton( | ||||
|                         onPressed: () {}, | ||||
|                         child: const Text( | ||||
|                           'Resend Code', | ||||
|                           style: TextStyle( | ||||
|                             fontWeight: FontWeight.w700, | ||||
|                           ), | ||||
|                         )) | ||||
|                   ], | ||||
|                 ); | ||||
|               }), | ||||
|             ), | ||||
|           ); | ||||
|         }); | ||||
|   } | ||||
| } | ||||
							
								
								
									
										17
									
								
								lib/application/component/otp/otp_viewmodel.dart
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										17
									
								
								lib/application/component/otp/otp_viewmodel.dart
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1,17 @@ | ||||
| import 'package:flutter/material.dart'; | ||||
|  | ||||
| class OtpViewModel extends ChangeNotifier { | ||||
|   var formKey = GlobalKey<FormState>(); | ||||
|   var focusNode = FocusNode(); | ||||
|   bool buttonIsActive = false; | ||||
|  | ||||
|   TextEditingController ctrlPin = TextEditingController(); | ||||
|  | ||||
|   Future<bool> validateOtp(String pin) async { | ||||
|     final pinLength = pin.length; | ||||
|     if (pinLength == 4) { | ||||
|       return true; | ||||
|     } | ||||
|     return false; | ||||
|   } | ||||
| } | ||||
							
								
								
									
										176
									
								
								lib/application/component/select_form/select_form_view.dart
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										176
									
								
								lib/application/component/select_form/select_form_view.dart
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1,176 @@ | ||||
| import 'package:cims_apps/application/component/button/button_view.dart'; | ||||
| import 'package:cims_apps/application/component/text_form/text_form_view.dart'; | ||||
| import 'package:cims_apps/application/theme/color_palette.dart'; | ||||
| import 'package:cims_apps/core/utils/size_config.dart'; | ||||
| import 'package:flutter/material.dart'; | ||||
|  | ||||
| class ItemSelectForm { | ||||
|   final String key; | ||||
|   final String text; | ||||
|   final String? description; | ||||
|   final bool isOther; | ||||
|   final String image; | ||||
|  | ||||
|   ItemSelectForm( | ||||
|     this.key, | ||||
|     this.text, { | ||||
|     this.isOther = false, | ||||
|     this.image = "", | ||||
|     this.description, | ||||
|   }); | ||||
| } | ||||
|  | ||||
| class SelectFormView extends StatelessWidget { | ||||
|   final String name; | ||||
|   final String? hintText; | ||||
|   final TextStyle? hintTextStyle; | ||||
|   final TextEditingController? ctrl; | ||||
|   final Widget? bottomSheetTitle; | ||||
|   final List<ItemSelectForm> listItem; | ||||
|   final ValueChanged<String> onSelect; | ||||
|   final FormFieldValidator<String>? validator; | ||||
|   final _borderRadius = const Radius.circular(24); | ||||
|   final bool? enabled; | ||||
|   const SelectFormView( | ||||
|       {Key? key, | ||||
|       required this.name, | ||||
|       this.hintText, | ||||
|       this.hintTextStyle, | ||||
|       this.ctrl, | ||||
|       this.bottomSheetTitle, | ||||
|       required this.listItem, | ||||
|       required this.onSelect, | ||||
|       this.validator, | ||||
|       this.enabled}) | ||||
|       : super(key: key); | ||||
|  | ||||
|   @override | ||||
|   Widget build(BuildContext context) { | ||||
|     bottomSheet() { | ||||
|       showModalBottomSheet<void>( | ||||
|         context: context, | ||||
|         shape: RoundedRectangleBorder( | ||||
|           borderRadius: BorderRadius.only( | ||||
|             topLeft: _borderRadius, | ||||
|             topRight: _borderRadius, | ||||
|           ), | ||||
|         ), | ||||
|         builder: (BuildContext context) { | ||||
|           ItemSelectForm? selectedForm; | ||||
|           String? selectedKey; | ||||
|           if (listItem.isNotEmpty) { | ||||
|             var res = listItem.where((element) => element.key == selectedKey); | ||||
|             if (res.isNotEmpty) { | ||||
|               selectedForm = res.first; | ||||
|             } | ||||
|           } | ||||
|           return StatefulBuilder(builder: ( | ||||
|             BuildContext context, | ||||
|             StateSetter stateSetter, | ||||
|           ) { | ||||
|             return Container( | ||||
|               height: SizeConfig.height * .45, | ||||
|               padding: const EdgeInsets.all(16), | ||||
|               child: Column( | ||||
|                 crossAxisAlignment: CrossAxisAlignment.start, | ||||
|                 children: [ | ||||
|                   bottomSheetTitle ?? Container(), | ||||
|                   // const SizedBox(height: 16), | ||||
|                   Expanded( | ||||
|                     child: SingleChildScrollView( | ||||
|                       scrollDirection: Axis.vertical, | ||||
|                       child: Column( | ||||
|                         children: [ | ||||
|                           ...listItem.map( | ||||
|                             (e) => Card( | ||||
|                               elevation: 0, | ||||
|                               color: Colors.transparent, | ||||
|                               shape: const RoundedRectangleBorder( | ||||
|                                 side: BorderSide( | ||||
|                                   color: ColorPalette.greyBorder, | ||||
|                                 ), | ||||
|                                 borderRadius: | ||||
|                                     BorderRadius.all(Radius.circular(12)), | ||||
|                               ), | ||||
|                               child: ListTile( | ||||
|                                 title: Text( | ||||
|                                   e.text, | ||||
|                                   style: const TextStyle( | ||||
|                                     fontSize: 14, | ||||
|                                   ), | ||||
|                                 ), | ||||
|                                 subtitle: e.description != null | ||||
|                                     ? Text( | ||||
|                                         e.description!, | ||||
|                                         maxLines: 2, | ||||
|                                         overflow: TextOverflow.ellipsis, | ||||
|                                       ) | ||||
|                                     : null, | ||||
|                                 // trailing: const Icon( | ||||
|                                 //   Icons.check_circle, | ||||
|                                 //   color: ColorPalette.primary, | ||||
|                                 // ), | ||||
|                                 trailing: Radio( | ||||
|                                   focusColor: ColorPalette.primary, | ||||
|                                   activeColor: ColorPalette.primary, | ||||
|                                   visualDensity: const VisualDensity( | ||||
|                                     horizontal: VisualDensity.minimumDensity, | ||||
|                                     vertical: VisualDensity.minimumDensity, | ||||
|                                   ), | ||||
|                                   materialTapTargetSize: | ||||
|                                       MaterialTapTargetSize.shrinkWrap, | ||||
|                                   value: e.key, | ||||
|                                   groupValue: selectedKey, | ||||
|                                   onChanged: (value) { | ||||
|                                     // selectedForm = | ||||
|                                     //     ItemSelectForm(e.key, e.text); | ||||
|                                     // stateSetter(() { | ||||
|                                     //   selectedKey = selectedForm!.key; | ||||
|                                     // }); | ||||
|                                   }, | ||||
|                                 ), | ||||
|                                 onTap: () { | ||||
|                                   ctrl?.text = e.text; | ||||
|                                   onSelect(e.key); | ||||
|                                   Navigator.of(context).pop(); | ||||
|                                 }, | ||||
|                               ), | ||||
|                             ), | ||||
|                           ), | ||||
|                         ], | ||||
|                       ), | ||||
|                     ), | ||||
|                   ), | ||||
|                   ButtonView( | ||||
|                     name: 'Select', | ||||
|                     marginVertical: 4.0, | ||||
|                     onPressed: () { | ||||
|                       // print('object $') | ||||
|                     }, | ||||
|                   ) | ||||
|                 ], | ||||
|               ), | ||||
|             ); | ||||
|           }); | ||||
|         }, | ||||
|       ); | ||||
|     } | ||||
|  | ||||
|     return TextFormView( | ||||
|       name: name, | ||||
|       readOnly: true, | ||||
|       enabled: enabled ?? true, | ||||
|       onTap: () { | ||||
|         if (listItem.isNotEmpty) bottomSheet(); | ||||
|       }, | ||||
|       validator: validator, | ||||
|       hintText: hintText, | ||||
|       hintTextStyle: hintTextStyle, | ||||
|       ctrl: ctrl, | ||||
|       suffixIcon: Icon( | ||||
|         Icons.keyboard_arrow_down, | ||||
|         size: SizeConfig.width * .07, | ||||
|       ), | ||||
|     ); | ||||
|   } | ||||
| } | ||||
| @@ -3,10 +3,14 @@ import 'package:flutter/material.dart'; | ||||
|  | ||||
| class TextCaption extends StatelessWidget { | ||||
|   final String title, subtitle; | ||||
|   final TextAlign? textAlignSubtitle; | ||||
|   final CrossAxisAlignment? crossAxisAlignment; | ||||
|   const TextCaption({ | ||||
|     Key? key, | ||||
|     required this.title, | ||||
|     this.subtitle = '', | ||||
|     this.textAlignSubtitle, | ||||
|     this.crossAxisAlignment, | ||||
|   }) : super(key: key); | ||||
|  | ||||
|   @override | ||||
| @@ -14,7 +18,7 @@ class TextCaption extends StatelessWidget { | ||||
|     return Padding( | ||||
|       padding: const EdgeInsets.only(bottom: 32.0), | ||||
|       child: Column( | ||||
|         crossAxisAlignment: CrossAxisAlignment.start, | ||||
|         crossAxisAlignment: crossAxisAlignment ?? CrossAxisAlignment.start, | ||||
|         mainAxisAlignment: MainAxisAlignment.spaceBetween, | ||||
|         children: [ | ||||
|           Text( | ||||
| @@ -30,10 +34,11 @@ class TextCaption extends StatelessWidget { | ||||
|                   padding: const EdgeInsets.only(top: 8.0), | ||||
|                   child: Text( | ||||
|                     subtitle, | ||||
|                     textAlign: textAlignSubtitle ?? TextAlign.start, | ||||
|                     style: const TextStyle( | ||||
|                       fontSize: 16, | ||||
|                       fontWeight: FontWeight.w500, | ||||
|                       color: ColorPalette.slate800, | ||||
|                       color: ColorPalette.slate500, | ||||
|                     ), | ||||
|                   ), | ||||
|                 ) | ||||
|   | ||||
| @@ -94,12 +94,12 @@ class TextFormView extends StatelessWidget { | ||||
|                             name, | ||||
|                             style: const TextStyle( | ||||
|                               fontSize: 16, | ||||
|                               color: ColorPalette.greyLight, | ||||
|                               // color: ColorPalette.greyLight, | ||||
|                             ), | ||||
|                           ), | ||||
|                           suffixLable ?? | ||||
|                               const Text( | ||||
|                                 " * ", | ||||
|                                 "", | ||||
|                                 style: TextStyle( | ||||
|                                   fontSize: 16, | ||||
|                                   color: Colors.red, | ||||
| @@ -155,7 +155,7 @@ class TextFormView extends StatelessWidget { | ||||
|             hintStyle: hintTextStyle ?? | ||||
|                 const TextStyle( | ||||
|                   fontSize: 14, | ||||
|                   color: Colors.grey, | ||||
|                   color: ColorPalette.greyFont, | ||||
|                   fontWeight: FontWeight.normal, | ||||
|                 ), | ||||
|             isDense: true, | ||||
| @@ -167,19 +167,19 @@ class TextFormView extends StatelessWidget { | ||||
|             disabledBorder: OutlineInputBorder( | ||||
|               borderRadius: _borderRadius, | ||||
|               borderSide: BorderSide( | ||||
|                 color: disabledborderColor ?? ColorPalette.greyFont, | ||||
|                 color: disabledborderColor ?? ColorPalette.greyBorder, | ||||
|               ), | ||||
|             ), | ||||
|             enabledBorder: OutlineInputBorder( | ||||
|               borderRadius: _borderRadius, | ||||
|               borderSide: BorderSide( | ||||
|                 color: enabledborderColor ?? ColorPalette.greyBase, | ||||
|                 color: enabledborderColor ?? ColorPalette.greyBorder, | ||||
|               ), | ||||
|             ), | ||||
|             focusedBorder: OutlineInputBorder( | ||||
|               borderRadius: _borderRadius, | ||||
|               borderSide: BorderSide( | ||||
|                 color: focusedBorderColor ?? ColorPalette.greyBase, | ||||
|                 color: focusedBorderColor ?? ColorPalette.greyBorder, | ||||
|               ), | ||||
|             ), | ||||
|             border: OutlineInputBorder(borderRadius: _borderRadius), | ||||
|   | ||||
| @@ -73,5 +73,6 @@ class ColorPalette { | ||||
|   static const Color chathamsBlue = Color(0xFF285BB9); | ||||
|   static const Color background = Color(0xFFDADADA); | ||||
|   static const Color backgroundBlueLight = Color(0xFFEBF3FD); | ||||
|   static const Color slate500 = Color(0xFF64748B); | ||||
|   static const Color slate800 = Color(0xFF1E293B); | ||||
| } | ||||
|   | ||||
							
								
								
									
										16
									
								
								lib/core/utils/string_utils.dart
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										16
									
								
								lib/core/utils/string_utils.dart
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1,16 @@ | ||||
| class StringUtils { | ||||
|   static bool emailValidation(String email) { | ||||
|     return RegExp( | ||||
|             r'^(([^<>()[\]\\.,;:\s@\"]+(\.[^<>()[\]\\.,;:\s@\"]+)*)|(\".+\"))@((\[[0-9]{1,3}\.[0-9]{1,3}\.[0-9]{1,3}\.[0-9]{1,3}\])|(([a-zA-Z\-0-9]+\.)+[a-zA-Z]{2,}))$') | ||||
|         .hasMatch(email); | ||||
|   } | ||||
|  | ||||
|   static bool phoneValidation(String phone) { | ||||
|     return RegExp(r'^(\+62|62|0)8[1-9][0-9]{6,10}$').hasMatch(phone); | ||||
|   } | ||||
|  | ||||
|   static bool passwordValidation(String password) { | ||||
|     return RegExp(r'^(?=.*[a-z])(?=.*[A-Z])(?=.*[0-9])(?=.*?[\W_])(?=.{8,})') | ||||
|         .hasMatch(password); | ||||
|   } | ||||
| } | ||||
| @@ -0,0 +1,151 @@ | ||||
| import 'package:cims_apps/application/assets/path_assets.dart'; | ||||
| import 'package:cims_apps/application/component/button/button_view.dart'; | ||||
| import 'package:cims_apps/application/component/image/image_view.dart'; | ||||
| import 'package:cims_apps/application/component/text_caption/text_caption.dart'; | ||||
| import 'package:cims_apps/application/component/text_form/text_form_view.dart'; | ||||
| import 'package:cims_apps/application/theme/color_palette.dart'; | ||||
| import 'package:cims_apps/core/route/route.dart'; | ||||
| import 'package:cims_apps/core/utils/size_config.dart'; | ||||
| import 'package:cims_apps/features/auth/registration/view/submission_data/submission_parent.dart'; | ||||
| import 'package:cims_apps/features/auth/registration/viewmodel/registration_viewmodel.dart'; | ||||
| import 'package:flutter/material.dart'; | ||||
| import 'package:provider/provider.dart'; | ||||
|  | ||||
| class RegistrationPasswordView extends StatelessWidget { | ||||
|   const RegistrationPasswordView({Key? key}) : super(key: key); | ||||
|  | ||||
|   @override | ||||
|   Widget build(BuildContext context) { | ||||
|     return ChangeNotifierProvider( | ||||
|         create: (context) => RegistrationViewModel(), | ||||
|         builder: (context, child) { | ||||
|           return Scaffold( | ||||
|             appBar: AppBar( | ||||
|               title: const Text('Sign Up'), | ||||
|             ), | ||||
|             body: SingleChildScrollView( | ||||
|               padding: const EdgeInsets.all(16.0), | ||||
|               child: Consumer<RegistrationViewModel>( | ||||
|                   builder: (context, provider, child) { | ||||
|                 return Form( | ||||
|                   key: provider.formKey, | ||||
|                   child: Column( | ||||
|                     crossAxisAlignment: CrossAxisAlignment.start, | ||||
|                     children: [ | ||||
|                       const TextCaption( | ||||
|                         title: 'Create your password', | ||||
|                         subtitle: | ||||
|                             'The password you create serves as your login', | ||||
|                       ), | ||||
|                       TextFormView( | ||||
|                         name: 'Password', | ||||
|                         hintText: 'Input password', | ||||
|                         ctrl: provider.passwordCtrl, | ||||
|                         obscureText: !provider.showPassword, | ||||
|                         validator: (value) { | ||||
|                           if (value!.isEmpty) { | ||||
|                             return 'Password must filled'; | ||||
|                           } else { | ||||
|                             return null; | ||||
|                           } | ||||
|                         }, | ||||
|                         suffixIcon: GestureDetector( | ||||
|                           onTap: () { | ||||
|                             provider.toggleVisibility(); | ||||
|                           }, | ||||
|                           child: Icon( | ||||
|                             provider.showPassword | ||||
|                                 ? Icons.visibility_off_outlined | ||||
|                                 : Icons.visibility_off_outlined, | ||||
|                             color: ColorPalette.greyDarker, | ||||
|                           ), | ||||
|                         ), | ||||
|                       ), | ||||
|                       const SizedBox( | ||||
|                         height: 32.0, | ||||
|                       ), | ||||
|                       TextFormView( | ||||
|                         name: 'Confirm Password', | ||||
|                         hintText: 'Input password', | ||||
|                         ctrl: provider.confirmPasswordCtrl, | ||||
|                         obscureText: !provider.showPasswordConfirm, | ||||
|                         validator: (value) { | ||||
|                           if (value!.isEmpty) { | ||||
|                             return 'Password must filled'; | ||||
|                           } else if (value != provider.passwordCtrl.text) { | ||||
|                             return 'Password must be same'; | ||||
|                           } else { | ||||
|                             return null; | ||||
|                           } | ||||
|                         }, | ||||
|                         suffixIcon: GestureDetector( | ||||
|                           onTap: () { | ||||
|                             provider.toggleVisibilityConfirm(); | ||||
|                           }, | ||||
|                           child: Icon( | ||||
|                             provider.showPasswordConfirm | ||||
|                                 ? Icons.visibility_outlined | ||||
|                                 : Icons.visibility_off_outlined, | ||||
|                             color: ColorPalette.greyDarker, | ||||
|                           ), | ||||
|                         ), | ||||
|                       ), | ||||
|                       ButtonView( | ||||
|                         name: 'Confirm', | ||||
|                         onPressed: () { | ||||
|                           if (provider.formKey.currentState!.validate()) { | ||||
|                             routePush(context, page: const DialogSuccess()); | ||||
|                           } | ||||
|                         }, | ||||
|                       ) | ||||
|                     ], | ||||
|                   ), | ||||
|                 ); | ||||
|               }), | ||||
|             ), | ||||
|           ); | ||||
|         }); | ||||
|   } | ||||
| } | ||||
|  | ||||
| class DialogSuccess extends StatelessWidget { | ||||
|   const DialogSuccess({Key? key}) : super(key: key); | ||||
|  | ||||
|   @override | ||||
|   Widget build(BuildContext context) { | ||||
|     return Scaffold( | ||||
|       body: Container( | ||||
|         padding: const EdgeInsets.all(24.0), | ||||
|         child: Column( | ||||
|           mainAxisAlignment: MainAxisAlignment.end, | ||||
|           crossAxisAlignment: CrossAxisAlignment.center, | ||||
|           children: [ | ||||
|             ImageView( | ||||
|               image: PathAssets.imgSuccessSignup, | ||||
|               width: SizeConfig.width * .8, | ||||
|             ), | ||||
|             const TextCaption( | ||||
|               title: 'Success', | ||||
|               subtitle: | ||||
|                   'Congratulations, your account creation was successful!', | ||||
|               crossAxisAlignment: CrossAxisAlignment.center, | ||||
|               textAlignSubtitle: TextAlign.center, | ||||
|             ), | ||||
|             SizedBox( | ||||
|               height: SizeConfig.height * .2, | ||||
|             ), | ||||
|             ButtonView( | ||||
|               name: 'Next', | ||||
|               marginVertical: 8.0, | ||||
|               onPressed: () { | ||||
|                 routePush(context, | ||||
|                     page: const SubmissionParent(), | ||||
|                     routeType: RouteType.pushReplace); | ||||
|               }, | ||||
|             ) | ||||
|           ], | ||||
|         ), | ||||
|       ), | ||||
|     ); | ||||
|   } | ||||
| } | ||||
| @@ -1,9 +1,7 @@ | ||||
| import 'package:cims_apps/application/component/button/button_view.dart'; | ||||
| import 'package:cims_apps/application/component/otp/otp_view.dart'; | ||||
| import 'package:cims_apps/application/component/text_caption/text_caption.dart'; | ||||
| import 'package:cims_apps/application/component/text_form/text_form_view.dart'; | ||||
| import 'package:cims_apps/core/route/route.dart'; | ||||
| import 'package:cims_apps/features/auth/registration/view/initial_registration_step.dart'; | ||||
| import 'package:cims_apps/features/bottom_navigation_view.dart'; | ||||
| import 'package:flutter/gestures.dart'; | ||||
| import 'package:flutter/material.dart'; | ||||
|  | ||||
| @@ -13,6 +11,30 @@ class RegistrationView extends StatelessWidget { | ||||
|  | ||||
|   @override | ||||
|   Widget build(BuildContext context) { | ||||
|     _showOtpWidget() { | ||||
|       Navigator.of(context).pop(); | ||||
|       showModalBottomSheet( | ||||
|         context: context, | ||||
|         isScrollControlled: true, | ||||
|         enableDrag: false, | ||||
|         builder: (BuildContext context) { | ||||
|           return Padding( | ||||
|             padding: EdgeInsets.only( | ||||
|               top: MediaQueryData.fromView( | ||||
|                 WidgetsBinding.instance.window, | ||||
|               ).padding.top, | ||||
|             ), | ||||
|             child: const OtpView( | ||||
|               title: 'Sign Up', | ||||
|               contentTitle: 'Check your SMS', | ||||
|               contentSubtitle: | ||||
|                   'Enter 4 digit code We’ve sent to verify your phone number', | ||||
|             ), | ||||
|           ); | ||||
|         }, | ||||
|       ); | ||||
|     } | ||||
|  | ||||
|     return Scaffold( | ||||
|       appBar: AppBar( | ||||
|         title: const Text('Sign Up'), | ||||
| @@ -30,7 +52,9 @@ class RegistrationView extends StatelessWidget { | ||||
|             ButtonView( | ||||
|               name: 'Next', | ||||
|               onPressed: () { | ||||
|                 routePush(context, page: const InitialRegistrationStep()); | ||||
|                 _showOtpWidget(); | ||||
|  | ||||
|                 // routePush(context, page: const RegistrationPasswordView()); | ||||
|               }, | ||||
|             ), | ||||
|             Align( | ||||
| @@ -42,7 +66,7 @@ class RegistrationView extends StatelessWidget { | ||||
|                     text: 'Already have an account? ', | ||||
|                     style: TextStyle( | ||||
|                       color: Colors.black, | ||||
|                       decoration: TextDecoration.underline, | ||||
|                       decoration: TextDecoration.none, | ||||
|                     ), | ||||
|                   ), | ||||
|                   TextSpan( | ||||
|   | ||||
| @@ -0,0 +1,91 @@ | ||||
| import 'package:cims_apps/application/assets/path_assets.dart'; | ||||
| import 'package:cims_apps/application/component/button/button_view.dart'; | ||||
| import 'package:cims_apps/application/component/image/image_view.dart'; | ||||
| import 'package:cims_apps/application/component/text_caption/text_caption.dart'; | ||||
| import 'package:cims_apps/application/theme/color_palette.dart'; | ||||
| import 'package:cims_apps/core/utils/size_config.dart'; | ||||
| import 'package:flutter/material.dart'; | ||||
|  | ||||
| class InitialTakePhoto extends StatelessWidget { | ||||
|   const InitialTakePhoto({Key? key}) : super(key: key); | ||||
|  | ||||
|   @override | ||||
|   Widget build(BuildContext context) { | ||||
|     List listImg = [ | ||||
|       {'urlImg': PathAssets.imgKtpBlur, 'tag': 'Blurry Photo'}, | ||||
|       {'urlImg': PathAssets.imgKtpLight, 'tag': 'Light Reflection'}, | ||||
|       {'urlImg': PathAssets.imgKtpCropped, 'tag': 'Cropped Photo'}, | ||||
|       {'urlImg': PathAssets.imgKtpClear, 'tag': 'Clear Photo'}, | ||||
|     ]; | ||||
|     return SizedBox( | ||||
|       height: SizeConfig.height * .75, | ||||
|       child: Column( | ||||
|         mainAxisAlignment: MainAxisAlignment.spaceBetween, | ||||
|         children: [ | ||||
|           const TextCaption( | ||||
|             title: 'Take a photo your ID card', | ||||
|             subtitle: | ||||
|                 'Make sure your photo is clearly legible for identity verification purposes', | ||||
|           ), | ||||
|           SizedBox( | ||||
|             width: SizeConfig.height, | ||||
|             child: Wrap( | ||||
|               alignment: WrapAlignment.spaceBetween, | ||||
|               spacing: 10, | ||||
|               runSpacing: 10, | ||||
|               children: List.generate(listImg.length, (index) { | ||||
|                 final urlList = listImg[index]['urlImg']; | ||||
|                 final tag = listImg[index]['tag']; | ||||
|                 return Column( | ||||
|                   children: [ | ||||
|                     ImageView( | ||||
|                       image: urlList, | ||||
|                       width: SizeConfig.width * .42, | ||||
|                     ), | ||||
|                     const SizedBox( | ||||
|                       height: 8, | ||||
|                     ), | ||||
|                     Text( | ||||
|                       tag, | ||||
|                       style: const TextStyle( | ||||
|                           color: ColorPalette.slate800, | ||||
|                           fontWeight: FontWeight.w600), | ||||
|                     ), | ||||
|                   ], | ||||
|                 ); | ||||
|               }), | ||||
|             ), | ||||
|           ), | ||||
|           // const Spacer(), | ||||
|           const Row( | ||||
|             mainAxisAlignment: MainAxisAlignment.spaceBetween, | ||||
|             children: [ | ||||
|               ImageView( | ||||
|                 image: PathAssets.iconShield, | ||||
|                 width: 20, | ||||
|                 height: 22, | ||||
|               ), | ||||
|               SizedBox( | ||||
|                 width: 8, | ||||
|               ), | ||||
|               Expanded( | ||||
|                 child: Text( | ||||
|                   'In accordance with OJK regulations, an ID card is required to purchase mutual funds.', | ||||
|                   style: TextStyle( | ||||
|                     fontWeight: FontWeight.w600, | ||||
|                     color: ColorPalette.primary, | ||||
|                   ), | ||||
|                 ), | ||||
|               ) | ||||
|             ], | ||||
|           ), | ||||
|           ButtonView( | ||||
|             name: 'Take a Photo', | ||||
|             marginVertical: 16.0, | ||||
|             onPressed: () {}, | ||||
|           ) | ||||
|         ], | ||||
|       ), | ||||
|     ); | ||||
|   } | ||||
| } | ||||
| @@ -1,9 +1,14 @@ | ||||
| import 'package:cims_apps/application/component/button/button_view.dart'; | ||||
| import 'package:cims_apps/application/theme/color_palette.dart'; | ||||
| import 'package:cims_apps/core/route/route.dart'; | ||||
| import 'package:cims_apps/core/utils/size_config.dart'; | ||||
| import 'package:cims_apps/features/auth/registration/view/submission_data/initial_take_photo.dart'; | ||||
| import 'package:cims_apps/features/auth/registration/view/submission_data/submit_email.dart'; | ||||
| import 'package:cims_apps/features/auth/registration/view/submission_data/submit_personal_data.dart'; | ||||
| import 'package:cims_apps/features/auth/registration/viewmodel/submission_data_viewmodel.dart'; | ||||
| import 'package:cims_apps/features/bottom_navigation_view.dart'; | ||||
| import 'package:flutter/material.dart'; | ||||
| import 'package:provider/provider.dart'; | ||||
|  | ||||
| class SubmissionParent extends StatefulWidget { | ||||
|   static const routeName = '/SubmissionParent'; | ||||
| @@ -14,29 +19,16 @@ class SubmissionParent extends StatefulWidget { | ||||
| } | ||||
|  | ||||
| class _SubmissionParentState extends State<SubmissionParent> { | ||||
|   int _currentStep = 1; | ||||
|   final int _stepAmount = 9; | ||||
|   Widget _stepItem({bool isCurrentStep = false, bool isDone = false}) { | ||||
|     return GestureDetector( | ||||
|       onTap: () { | ||||
|         setState(() { | ||||
|           if (_currentStep > 1) { | ||||
|             _currentStep--; | ||||
|           } else if (_currentStep == 1) { | ||||
|             _currentStep++; | ||||
|           } | ||||
|         }); | ||||
|       }, | ||||
|       child: Container( | ||||
|         margin: const EdgeInsets.only(right: 4.0, left: 4.0), | ||||
|         height: 6, | ||||
|         width: SizeConfig.width * .08, | ||||
|         decoration: BoxDecoration( | ||||
|           color: isCurrentStep || isDone | ||||
|               ? ColorPalette.primary | ||||
|               : ColorPalette.greyBorderNeutrals, | ||||
|           borderRadius: BorderRadius.circular(50), | ||||
|         ), | ||||
|     return Container( | ||||
|       margin: const EdgeInsets.only(right: 4.0, left: 4.0), | ||||
|       height: 6, | ||||
|       width: SizeConfig.width * .08, | ||||
|       decoration: BoxDecoration( | ||||
|         color: isCurrentStep || isDone | ||||
|             ? ColorPalette.primary | ||||
|             : ColorPalette.greyBorderNeutrals, | ||||
|         borderRadius: BorderRadius.circular(50), | ||||
|       ), | ||||
|     ); | ||||
|   } | ||||
| @@ -48,9 +40,7 @@ class _SubmissionParentState extends State<SubmissionParent> { | ||||
|       case 2: | ||||
|         return const SubmitEmail(); | ||||
|       case 3: | ||||
|         return Container( | ||||
|           child: Text("Step 3"), | ||||
|         ); | ||||
|         return const InitialTakePhoto(); | ||||
|       case 4: | ||||
|         return Container( | ||||
|           child: Text("Step 4"), | ||||
| @@ -80,48 +70,68 @@ class _SubmissionParentState extends State<SubmissionParent> { | ||||
|  | ||||
|   @override | ||||
|   Widget build(BuildContext context) { | ||||
|     return Scaffold( | ||||
|       appBar: AppBar( | ||||
|         title: const Text('Registration'), | ||||
|       ), | ||||
|       body: Stack( | ||||
|         children: [ | ||||
|           Column( | ||||
|             crossAxisAlignment: CrossAxisAlignment.start, | ||||
|             children: [ | ||||
|               Padding( | ||||
|                 padding: const EdgeInsets.symmetric( | ||||
|                     horizontal: 16.0, vertical: 16.0), | ||||
|                 child: Row( | ||||
|                   mainAxisAlignment: MainAxisAlignment.spaceBetween, | ||||
|                   children: List.generate( | ||||
|                     _stepAmount, | ||||
|                     (index) => _stepItem( | ||||
|                       isCurrentStep: _currentStep == index + 1, | ||||
|                     ), | ||||
|                   ), | ||||
|                 ), | ||||
|     return ChangeNotifierProvider( | ||||
|         create: (context) => SubmissionDataViewModel(), | ||||
|         builder: (context, child) { | ||||
|           return WillPopScope( | ||||
|             onWillPop: () async { | ||||
|               await routePush(context, | ||||
|                   page: const BottomNavigationView(), | ||||
|                   routeType: RouteType.pushReplace); | ||||
|               return false; | ||||
|             }, | ||||
|             child: Scaffold( | ||||
|               appBar: AppBar( | ||||
|                 title: const Text('Registration'), | ||||
|               ), | ||||
|               body: Stack( | ||||
|                 children: [ | ||||
|                   Consumer<SubmissionDataViewModel>( | ||||
|                       builder: (context, provider, child) { | ||||
|                     return Column( | ||||
|                       crossAxisAlignment: CrossAxisAlignment.start, | ||||
|                       mainAxisAlignment: MainAxisAlignment.spaceBetween, | ||||
|                       children: [ | ||||
|                         Padding( | ||||
|                           padding: const EdgeInsets.symmetric( | ||||
|                               horizontal: 16.0, vertical: 16.0), | ||||
|                           child: Row( | ||||
|                             mainAxisAlignment: MainAxisAlignment.spaceBetween, | ||||
|                             children: List.generate( | ||||
|                               provider.stepAmount, | ||||
|                               (index) => _stepItem( | ||||
|                                 isCurrentStep: | ||||
|                                     provider.currentStep == index + 1, | ||||
|                               ), | ||||
|                             ), | ||||
|                           ), | ||||
|                         ), | ||||
|                         Expanded( | ||||
|                           child: Container( | ||||
|                             padding: | ||||
|                                 const EdgeInsets.symmetric(horizontal: 16.0), | ||||
|                             child: _content(provider.currentStep), | ||||
|                           ), | ||||
|                         ), | ||||
|                         provider.currentStep == 3 | ||||
|                             ? const SizedBox() | ||||
|                             : Align( | ||||
|                                 alignment: Alignment.bottomCenter, | ||||
|                                 child: ButtonView( | ||||
|                                   name: 'Next', | ||||
|                                   marginVertical: 16.0, | ||||
|                                   onPressed: () { | ||||
|                                     provider.nextSubmission(context); | ||||
|                                   }, | ||||
|                                 ), | ||||
|                               ) | ||||
|                       ], | ||||
|                     ); | ||||
|                   }), | ||||
|                 ], | ||||
|               ), | ||||
|               Container( | ||||
|                 padding: const EdgeInsets.symmetric(horizontal: 16.0), | ||||
|                 child: _content(_currentStep), | ||||
|               ) | ||||
|             ], | ||||
|           ), | ||||
|           Align( | ||||
|             alignment: Alignment.bottomCenter, | ||||
|             child: ButtonView( | ||||
|               name: 'Next', | ||||
|               marginVertical: 16.0, | ||||
|               onPressed: () { | ||||
|                 setState(() { | ||||
|                   _currentStep++; | ||||
|                 }); | ||||
|               }, | ||||
|             ), | ||||
|           ) | ||||
|         ], | ||||
|       ), | ||||
|     ); | ||||
|           ); | ||||
|         }); | ||||
|   } | ||||
| } | ||||
|   | ||||
| @@ -1,21 +1,81 @@ | ||||
| import 'package:cims_apps/application/assets/path_assets.dart'; | ||||
| import 'package:cims_apps/application/component/image/image_view.dart'; | ||||
| import 'package:cims_apps/application/component/text_caption/text_caption.dart'; | ||||
| import 'package:cims_apps/application/component/text_form/text_form_view.dart'; | ||||
| import 'package:cims_apps/features/auth/registration/viewmodel/submission_data_viewmodel.dart'; | ||||
| import 'package:flutter/gestures.dart'; | ||||
| import 'package:flutter/material.dart'; | ||||
| import 'package:provider/provider.dart'; | ||||
|  | ||||
| class SubmitEmail extends StatelessWidget { | ||||
|   const SubmitEmail({Key? key}) : super(key: key); | ||||
|  | ||||
|   @override | ||||
|   Widget build(BuildContext context) { | ||||
|   Widget _emailVerify() { | ||||
|     return Column( | ||||
|       crossAxisAlignment: CrossAxisAlignment.start, | ||||
|       children: [ | ||||
|         const TextCaption(title: 'Enter your e-mail'), | ||||
|         TextFormView( | ||||
|           name: 'E-mail Address', | ||||
|           hintText: 'Input e-mail address', | ||||
|         const ImageView(image: PathAssets.imgEmail), | ||||
|         Align( | ||||
|           alignment: Alignment.center, | ||||
|           child: RichText( | ||||
|             textAlign: TextAlign.center, | ||||
|             text: TextSpan(children: [ | ||||
|               const TextSpan( | ||||
|                 text: | ||||
|                     'We have sent a verification link to your e-mail. \nPlease check your email for ', | ||||
|                 style: TextStyle( | ||||
|                   color: Colors.black, | ||||
|                   decoration: TextDecoration.none, | ||||
|                 ), | ||||
|               ), | ||||
|               TextSpan( | ||||
|                 recognizer: TapGestureRecognizer() | ||||
|                   ..onTap = () { | ||||
|                     print('object'); | ||||
|                   }, | ||||
|                 text: 'verification', | ||||
|                 style: const TextStyle( | ||||
|                   color: Colors.blue, | ||||
|                 ), | ||||
|               ), | ||||
|               const TextSpan( | ||||
|                 text: ' to \ncontinue registration.', | ||||
|                 style: TextStyle( | ||||
|                   color: Colors.black, | ||||
|                   decoration: TextDecoration.none, | ||||
|                 ), | ||||
|               ), | ||||
|             ]), | ||||
|           ), | ||||
|         ), | ||||
|       ], | ||||
|     ); | ||||
|   } | ||||
|  | ||||
|   @override | ||||
|   Widget build(BuildContext context) { | ||||
|     return ChangeNotifierProvider( | ||||
|         create: (context) => SubmissionDataViewModel(), | ||||
|         builder: (context, child) { | ||||
|           return Consumer<SubmissionDataViewModel>( | ||||
|               builder: (context, provider, child) { | ||||
|             return Column( | ||||
|               crossAxisAlignment: CrossAxisAlignment.start, | ||||
|               children: [ | ||||
|                 !provider.isEmailVerify | ||||
|                     ? const TextCaption(title: 'Enter your e-mail') | ||||
|                     : const TextCaption(title: 'Check your e-mail '), | ||||
|                 !provider.isEmailVerify | ||||
|                     ? TextFormView( | ||||
|                         name: 'E-mail Address', | ||||
|                         hintText: 'Input e-mail address', | ||||
|                         onTap: () { | ||||
|                           provider.submitEmail(); | ||||
|                         }, | ||||
|                       ) | ||||
|                     : _emailVerify(), | ||||
|               ], | ||||
|             ); | ||||
|           }); | ||||
|         }); | ||||
|   } | ||||
| } | ||||
|   | ||||
| @@ -1,16 +1,56 @@ | ||||
| import 'package:cims_apps/application/component/select_form/select_form_view.dart'; | ||||
| import 'package:cims_apps/application/component/text_caption/text_caption.dart'; | ||||
| import 'package:cims_apps/application/theme/color_palette.dart'; | ||||
| import 'package:cims_apps/features/auth/registration/viewmodel/submission_data_viewmodel.dart'; | ||||
| import 'package:flutter/material.dart'; | ||||
| import 'package:provider/provider.dart'; | ||||
|  | ||||
| class SubmitPersonalData extends StatelessWidget { | ||||
|   const SubmitPersonalData({Key? key}) : super(key: key); | ||||
|  | ||||
|   @override | ||||
|   Widget build(BuildContext context) { | ||||
|     return Column( | ||||
|       crossAxisAlignment: CrossAxisAlignment.start, | ||||
|       children: [ | ||||
|         TextCaption(title: 'Your personal details'), | ||||
|       ], | ||||
|     ); | ||||
|     List<ItemSelectForm> listForm = [ | ||||
|       ItemSelectForm('key1', 'text'), | ||||
|       ItemSelectForm('key2', 'text'), | ||||
|       ItemSelectForm('key3', 'text'), | ||||
|       ItemSelectForm('key4', 'text'), | ||||
|       ItemSelectForm('key5', 'text'), | ||||
|     ]; | ||||
|     return ChangeNotifierProvider( | ||||
|         create: (context) => SubmissionDataViewModel(), | ||||
|         builder: (context, child) { | ||||
|           return Consumer<SubmissionDataViewModel>( | ||||
|               builder: (context, provider, child) { | ||||
|             return SingleChildScrollView( | ||||
|               child: Column( | ||||
|                 crossAxisAlignment: CrossAxisAlignment.start, | ||||
|                 // mainAxisAlignment: MainAxisAlignment.spaceBetween, | ||||
|                 children: [ | ||||
|                   const TextCaption(title: 'Your personal details'), | ||||
|                   SelectFormView( | ||||
|                     name: 'Occupation', | ||||
|                     hintText: 'Select occupation ', | ||||
|                     bottomSheetTitle: Row( | ||||
|                       mainAxisAlignment: MainAxisAlignment.spaceBetween, | ||||
|                       children: [ | ||||
|                         const Text('Occupation'), | ||||
|                         IconButton( | ||||
|                             onPressed: () => Navigator.pop(context), | ||||
|                             icon: const Icon( | ||||
|                               Icons.clear, | ||||
|                               size: 20, | ||||
|                               color: ColorPalette.greyBase, | ||||
|                             )), | ||||
|                       ], | ||||
|                     ), | ||||
|                     listItem: listForm, | ||||
|                     onSelect: (value) {}, | ||||
|                   ), | ||||
|                 ], | ||||
|               ), | ||||
|             ); | ||||
|           }); | ||||
|         }); | ||||
|   } | ||||
| } | ||||
|   | ||||
| @@ -0,0 +1,19 @@ | ||||
| import 'package:flutter/material.dart'; | ||||
|  | ||||
| class RegistrationViewModel extends ChangeNotifier { | ||||
|   TextEditingController passwordCtrl = TextEditingController(); | ||||
|   TextEditingController confirmPasswordCtrl = TextEditingController(); | ||||
|   var formKey = GlobalKey<FormState>(); | ||||
|   bool showPassword = false; | ||||
|   bool showPasswordConfirm = false; | ||||
|  | ||||
|   void toggleVisibility() { | ||||
|     showPassword = !showPassword; | ||||
|     notifyListeners(); | ||||
|   } | ||||
|  | ||||
|   void toggleVisibilityConfirm() { | ||||
|     showPasswordConfirm = !showPasswordConfirm; | ||||
|     notifyListeners(); | ||||
|   } | ||||
| } | ||||
| @@ -0,0 +1,31 @@ | ||||
| import 'package:flutter/material.dart'; | ||||
|  | ||||
| class SubmissionDataViewModel extends ChangeNotifier { | ||||
|   int currentStep = 1; | ||||
|   int stepAmount = 9; | ||||
|   bool _isEmailVerify = false; | ||||
|   bool get isEmailVerify => _isEmailVerify; | ||||
|  | ||||
|   submitEmail() { | ||||
|     _isEmailVerify = !_isEmailVerify; | ||||
|     notifyListeners(); | ||||
|   } | ||||
|  | ||||
|   onWillPopSubmission(BuildContext context) { | ||||
|     if (currentStep != 1) { | ||||
|       currentStep--; | ||||
|       notifyListeners(); | ||||
|     } else { | ||||
|       Navigator.of(context).pop(true); | ||||
|     } | ||||
|   } | ||||
|  | ||||
|   nextSubmission(BuildContext context) { | ||||
|     if (currentStep < stepAmount) { | ||||
|       currentStep++; | ||||
|     } else { | ||||
|       //ToDo : Go To next step after completing the submission | ||||
|     } | ||||
|     notifyListeners(); | ||||
|   } | ||||
| } | ||||
							
								
								
									
										45
									
								
								pubspec.lock
									
									
									
									
									
								
							
							
						
						
									
										45
									
								
								pubspec.lock
									
									
									
									
									
								
							| @@ -163,6 +163,11 @@ packages: | ||||
|     description: flutter | ||||
|     source: sdk | ||||
|     version: "0.0.0" | ||||
|   flutter_web_plugins: | ||||
|     dependency: transitive | ||||
|     description: flutter | ||||
|     source: sdk | ||||
|     version: "0.0.0" | ||||
|   http: | ||||
|     dependency: transitive | ||||
|     description: | ||||
| @@ -227,6 +232,14 @@ packages: | ||||
|       url: "https://pub.dev" | ||||
|     source: hosted | ||||
|     version: "1.10.0" | ||||
|   nested: | ||||
|     dependency: transitive | ||||
|     description: | ||||
|       name: nested | ||||
|       sha256: "03bac4c528c64c95c722ec99280375a6f2fc708eec17c7b3f07253b626cd2a20" | ||||
|       url: "https://pub.dev" | ||||
|     source: hosted | ||||
|     version: "1.0.0" | ||||
|   octo_image: | ||||
|     dependency: transitive | ||||
|     description: | ||||
| @@ -315,6 +328,14 @@ packages: | ||||
|       url: "https://pub.dev" | ||||
|     source: hosted | ||||
|     version: "6.0.2" | ||||
|   pinput: | ||||
|     dependency: "direct main" | ||||
|     description: | ||||
|       name: pinput | ||||
|       sha256: "543da5bfdefd9e06914a12100f8c9156f84cef3efc14bca507c49e966c5b813b" | ||||
|       url: "https://pub.dev" | ||||
|     source: hosted | ||||
|     version: "2.3.0" | ||||
|   platform: | ||||
|     dependency: transitive | ||||
|     description: | ||||
| @@ -339,6 +360,14 @@ packages: | ||||
|       url: "https://pub.dev" | ||||
|     source: hosted | ||||
|     version: "3.7.4" | ||||
|   provider: | ||||
|     dependency: "direct main" | ||||
|     description: | ||||
|       name: provider | ||||
|       sha256: "9a96a0a19b594dbc5bf0f1f27d2bc67d5f95957359b461cd9feb44ed6ae75096" | ||||
|       url: "https://pub.dev" | ||||
|     source: hosted | ||||
|     version: "6.1.1" | ||||
|   remove_emoji_input_formatter: | ||||
|     dependency: "direct main" | ||||
|     description: | ||||
| @@ -360,6 +389,14 @@ packages: | ||||
|     description: flutter | ||||
|     source: sdk | ||||
|     version: "0.0.99" | ||||
|   smart_auth: | ||||
|     dependency: transitive | ||||
|     description: | ||||
|       name: smart_auth | ||||
|       sha256: a25229b38c02f733d0a4e98d941b42bed91a976cb589e934895e60ccfa674cf6 | ||||
|       url: "https://pub.dev" | ||||
|     source: hosted | ||||
|     version: "1.1.1" | ||||
|   source_span: | ||||
|     dependency: transitive | ||||
|     description: | ||||
| @@ -448,6 +485,14 @@ packages: | ||||
|       url: "https://pub.dev" | ||||
|     source: hosted | ||||
|     version: "1.3.2" | ||||
|   universal_platform: | ||||
|     dependency: transitive | ||||
|     description: | ||||
|       name: universal_platform | ||||
|       sha256: d315be0f6641898b280ffa34e2ddb14f3d12b1a37882557869646e0cc363d0cc | ||||
|       url: "https://pub.dev" | ||||
|     source: hosted | ||||
|     version: "1.0.0+1" | ||||
|   uuid: | ||||
|     dependency: transitive | ||||
|     description: | ||||
|   | ||||
| @@ -39,6 +39,9 @@ dependencies: | ||||
|   flutter_svg: ^1.1.6 | ||||
|   cached_network_image: ^3.2.3 | ||||
|   remove_emoji_input_formatter: ^0.0.1+1 | ||||
|   provider: ^6.1.1 | ||||
|   pinput: ^2.2.21 | ||||
|  | ||||
|  | ||||
|  | ||||
|  | ||||
|   | ||||
		Reference in New Issue
	
	Block a user