Compare commits
	
		
			47 Commits
		
	
	
		
			83211e76f9
			...
			yoga
		
	
	| Author | SHA1 | Date | |
|---|---|---|---|
| e441c56bab | |||
| e513df325c | |||
| 23e1a6628f | |||
| 4b07219928 | |||
| 9cdda42b8b | |||
| 6f5d3ccca8 | |||
| eb99ad9d7f | |||
| ff515e2621 | |||
| f057a346c2 | |||
| f84fe1017d | |||
| 27ba55314b | |||
| 59e046bd92 | |||
| 4461b78565 | |||
| f2f688f9f3 | |||
| d1adfd2ab0 | |||
| 33b2ab85e3 | |||
| 6a43a3dcaf | |||
| db1280b272 | |||
| ae4f9c25c4 | |||
| a87afe16cb | |||
| 1904e9a4a3 | |||
| d79959c47f | |||
| 38837bd4f8 | |||
| d966108e9e | |||
| 506f364b87 | |||
| 506480d812 | |||
| a6ea9a2314 | |||
| 176261923d | |||
| a3148d8210 | |||
| 6e03fa5fa7 | |||
| de1782c2c2 | |||
| 89a79276a6 | |||
| 4737a91ab1 | |||
| ff135dd47b | |||
| 2e98c1a234 | |||
| c4c0479341 | |||
| e510aaefd7 | |||
| dfb947dce5 | |||
| 9761dc369c | |||
| 9e2304990c | |||
| 8b1b3e950f | |||
| aa987fe320 | |||
| ad6195061d | |||
| b5a382ce96 | |||
| fdca27233b | |||
| bd065242e6 | |||
| a35110af71 | 
							
								
								
									
										
											BIN
										
									
								
								assets/icons/icon-card.png
									
									
									
									
									
										Normal file
									
								
							
							
						
						| After Width: | Height: | Size: 1.0 KiB | 
							
								
								
									
										
											BIN
										
									
								
								assets/icons/icon-cat.png
									
									
									
									
									
										Normal file
									
								
							
							
						
						| After Width: | Height: | Size: 7.7 KiB | 
							
								
								
									
										
											BIN
										
									
								
								assets/icons/icon-education.png
									
									
									
									
									
										Normal file
									
								
							
							
						
						| After Width: | Height: | Size: 3.8 KiB | 
							
								
								
									
										
											BIN
										
									
								
								assets/icons/icon-faqs.png
									
									
									
									
									
										Normal file
									
								
							
							
						
						| After Width: | Height: | Size: 1.7 KiB | 
							
								
								
									
										
											BIN
										
									
								
								assets/icons/icon-fund.png
									
									
									
									
									
										Normal file
									
								
							
							
						
						| After Width: | Height: | Size: 3.3 KiB | 
							
								
								
									
										
											BIN
										
									
								
								assets/icons/icon-gadget-outline.png
									
									
									
									
									
										Normal file
									
								
							
							
						
						| After Width: | Height: | Size: 2.7 KiB | 
							
								
								
									
										
											BIN
										
									
								
								assets/icons/icon-home.png
									
									
									
									
									
										Normal file
									
								
							
							
						
						| After Width: | Height: | Size: 2.7 KiB | 
							
								
								
									
										
											BIN
										
									
								
								assets/icons/icon-logout.png
									
									
									
									
									
										Normal file
									
								
							
							
						
						| After Width: | Height: | Size: 1.5 KiB | 
							
								
								
									
										
											BIN
										
									
								
								assets/icons/icon-navigation-home.png
									
									
									
									
									
										Normal file
									
								
							
							
						
						| After Width: | Height: | Size: 1.2 KiB | 
							
								
								
									
										
											BIN
										
									
								
								assets/icons/icon-navigation-plan.png
									
									
									
									
									
										Normal file
									
								
							
							
						
						| After Width: | Height: | Size: 1.4 KiB | 
							
								
								
									
										
											BIN
										
									
								
								assets/icons/icon-navigation-portfolio.png
									
									
									
									
									
										Normal file
									
								
							
							
						
						| After Width: | Height: | Size: 2.3 KiB | 
							
								
								
									
										
											BIN
										
									
								
								assets/icons/icon-navigation-profile.png
									
									
									
									
									
										Normal file
									
								
							
							
						
						| After Width: | Height: | Size: 2.3 KiB | 
							
								
								
									
										
											BIN
										
									
								
								assets/icons/icon-navigation-transaction.png
									
									
									
									
									
										Normal file
									
								
							
							
						
						| After Width: | Height: | Size: 899 B | 
							
								
								
									
										
											BIN
										
									
								
								assets/icons/icon-padlock.png
									
									
									
									
									
										Normal file
									
								
							
							
						
						| After Width: | Height: | Size: 1.2 KiB | 
							
								
								
									
										
											BIN
										
									
								
								assets/icons/icon-profile.png
									
									
									
									
									
										Normal file
									
								
							
							
						
						| After Width: | Height: | Size: 1.8 KiB | 
							
								
								
									
										
											BIN
										
									
								
								assets/icons/icon-remove.png
									
									
									
									
									
										Normal file
									
								
							
							
						
						| After Width: | Height: | Size: 1.2 KiB | 
							
								
								
									
										
											BIN
										
									
								
								assets/icons/icon-setting.png
									
									
									
									
									
										Normal file
									
								
							
							
						
						| After Width: | Height: | Size: 2.2 KiB | 
							
								
								
									
										
											BIN
										
									
								
								assets/icons/icon-shop.png
									
									
									
									
									
										Normal file
									
								
							
							
						
						| After Width: | Height: | Size: 3.7 KiB | 
							
								
								
									
										
											BIN
										
									
								
								assets/images/img-dashboard-profile.png
									
									
									
									
									
										Normal file
									
								
							
							
						
						| After Width: | Height: | Size: 4.0 MiB | 
							
								
								
									
										
											BIN
										
									
								
								assets/images/img-empty-transaction.png
									
									
									
									
									
										Normal file
									
								
							
							
						
						| After Width: | Height: | Size: 70 KiB | 
| @@ -49,6 +49,30 @@ class PathAssets { | |||||||
|   static const String iconTicket = 'assets/icons/icon-ticket.png'; |   static const String iconTicket = 'assets/icons/icon-ticket.png'; | ||||||
|   static const String iconGadget = 'assets/icons/icon-gadget.png'; |   static const String iconGadget = 'assets/icons/icon-gadget.png'; | ||||||
|   static const String iconCar = 'assets/icons/icon-car.png'; |   static const String iconCar = 'assets/icons/icon-car.png'; | ||||||
|  |   static const String iconNavigationHome = | ||||||
|  |       'assets/icons/icon-navigation-home.png'; | ||||||
|  |   static const String iconNavigationPlan = | ||||||
|  |       'assets/icons/icon-navigation-plan.png'; | ||||||
|  |   static const String iconNavigationTransaction = | ||||||
|  |       'assets/icons/icon-navigation-transaction.png'; | ||||||
|  |   static const String iconNavigationPortfolio = | ||||||
|  |       'assets/icons/icon-navigation-portfolio.png'; | ||||||
|  |   static const String iconNavigationProfile = | ||||||
|  |       'assets/icons/icon-navigation-profile.png'; | ||||||
|  |   static const String iconRemove = 'assets/icons/icon-remove.png'; | ||||||
|  |   static const String iconCat = 'assets/icons/icon-cat.png'; | ||||||
|  |   static const String iconProfile = 'assets/icons/icon-profile.png'; | ||||||
|  |   static const String iconPadlock = 'assets/icons/icon-padlock.png'; | ||||||
|  |   static const String iconCard = 'assets/icons/icon-card.png'; | ||||||
|  |   static const String iconSetting = 'assets/icons/icon-setting.png'; | ||||||
|  |   static const String iconFaqs = 'assets/icons/icon-faqs.png'; | ||||||
|  |   static const String iconLogout = 'assets/icons/icon-logout.png'; | ||||||
|  |   static const String iconEducation = 'assets/icons/icon-education.png'; | ||||||
|  |   static const String iconFund = 'assets/icons/icon-fund.png'; | ||||||
|  |   static const String iconHome = 'assets/icons/icon-home.png'; | ||||||
|  |   static const String iconShop = 'assets/icons/icon-shop.png'; | ||||||
|  |   static const String iconGadgetOutline = | ||||||
|  |       'assets/icons/icon-gadget-outline.png'; | ||||||
|  |  | ||||||
|   /// IMAGE |   /// IMAGE | ||||||
|   static const String imgSplashLogo = 'assets/images/splash-logo.png'; |   static const String imgSplashLogo = 'assets/images/splash-logo.png'; | ||||||
| @@ -83,7 +107,28 @@ class PathAssets { | |||||||
|   static const String imgGuide1 = 'assets/images/img-guide1.png'; |   static const String imgGuide1 = 'assets/images/img-guide1.png'; | ||||||
|   static const String imgGuide2 = 'assets/images/img-guide2.png'; |   static const String imgGuide2 = 'assets/images/img-guide2.png'; | ||||||
|   static const String imgOpenShopping = 'assets/images/img-open-shopping.png'; |   static const String imgOpenShopping = 'assets/images/img-open-shopping.png'; | ||||||
|   static const String imgPaymentSuccess = 'assets/images/img-payment-success.png'; |   static const String imgPaymentSuccess = | ||||||
|  |       'assets/images/img-payment-success.png'; | ||||||
|   static const String frameSignature = 'assets/images/frame-signature.png'; |   static const String frameSignature = 'assets/images/frame-signature.png'; | ||||||
|   static const String imgFinish = 'assets/images/img-finish.png'; |   static const String imgFinish = 'assets/images/img-finish.png'; | ||||||
|  |   static const String imgDashboardProfile = | ||||||
|  |       'assets/images/img-dashboard-profile.png'; | ||||||
|  |   static const String imgEmptyTransaction = | ||||||
|  |       'assets/images/img-empty-transaction.png'; | ||||||
|  |  | ||||||
|  |   static const Map<String, String> goalInvestIcon = { | ||||||
|  |     'Education': iconToga, | ||||||
|  |     'Marriage': iconCake, | ||||||
|  |     'Old age days': iconHouse, | ||||||
|  |     'Home': iconHouse, | ||||||
|  |     'Other Plan': iconCreatePlan, | ||||||
|  |     'Create Plan': iconCreatePlan, | ||||||
|  |     'Entertainment': iconTicket, | ||||||
|  |     'Gadget': iconGadget, | ||||||
|  |     'Business': iconMarket, | ||||||
|  |     'Fashion': iconBag, | ||||||
|  |     'Shop': iconBag, | ||||||
|  |     'Vehicle': iconCar, | ||||||
|  |     'Holiday': iconPlane, | ||||||
|  |   }; | ||||||
| } | } | ||||||
|   | |||||||
| @@ -0,0 +1,100 @@ | |||||||
|  | import 'package:cims_apps/application/component/image/image_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 CardTransactionView extends StatelessWidget { | ||||||
|  |   final VoidCallback onTap; | ||||||
|  |   final String iconPath, type, amount, subs, step; | ||||||
|  |   final String? timeTransaction; | ||||||
|  |   const CardTransactionView({ | ||||||
|  |     Key? key, | ||||||
|  |     required this.step, | ||||||
|  |     required this.type, | ||||||
|  |     required this.amount, | ||||||
|  |     required this.iconPath, | ||||||
|  |     required this.subs, | ||||||
|  |     required this.onTap, | ||||||
|  |     this.timeTransaction, | ||||||
|  |   }) : super(key: key); | ||||||
|  |  | ||||||
|  |   @override | ||||||
|  |   Widget build(BuildContext context) { | ||||||
|  |     TextTheme textTheme = Theme.of(context).textTheme; | ||||||
|  |     return GestureDetector( | ||||||
|  |       onTap: onTap, | ||||||
|  |       child: Container( | ||||||
|  |         margin: const EdgeInsets.symmetric(vertical: 16.0), | ||||||
|  |         padding: const EdgeInsets.symmetric(vertical: 16.0, horizontal: 16.0), | ||||||
|  |         decoration: BoxDecoration( | ||||||
|  |           color: Colors.white, | ||||||
|  |           border: Border.all(width: 1, color: ColorPalette.slate200), | ||||||
|  |           borderRadius: const BorderRadius.all(Radius.circular(12)), | ||||||
|  |         ), | ||||||
|  |         child: Row( | ||||||
|  |           mainAxisAlignment: MainAxisAlignment.spaceBetween, | ||||||
|  |           crossAxisAlignment: CrossAxisAlignment.center, | ||||||
|  |           children: [ | ||||||
|  |             SizedBox( | ||||||
|  |                 width: SizeConfig.width * .4, | ||||||
|  |                 child: Column( | ||||||
|  |                   crossAxisAlignment: CrossAxisAlignment.start, | ||||||
|  |                   children: [ | ||||||
|  |                     Row( | ||||||
|  |                       children: [ | ||||||
|  |                         ImageView( | ||||||
|  |                             image: iconPath, width: SizeConfig.width * .12), | ||||||
|  |                         Padding( | ||||||
|  |                           padding: const EdgeInsets.only(left: 8.0), | ||||||
|  |                           child: Text( | ||||||
|  |                             type, | ||||||
|  |                             style: textTheme.headlineSmall, | ||||||
|  |                           ), | ||||||
|  |                         ), | ||||||
|  |                       ], | ||||||
|  |                     ), | ||||||
|  |                     Padding( | ||||||
|  |                       padding: const EdgeInsets.only(top: 16.0), | ||||||
|  |                       child: Text( | ||||||
|  |                         amount, | ||||||
|  |                         style: textTheme.headlineSmall, | ||||||
|  |                       ), | ||||||
|  |                     ), | ||||||
|  |                   ], | ||||||
|  |                 )), | ||||||
|  |             SizedBox( | ||||||
|  |                 width: SizeConfig.width * .4, | ||||||
|  |                 child: Column( | ||||||
|  |                   crossAxisAlignment: CrossAxisAlignment.end, | ||||||
|  |                   mainAxisAlignment: MainAxisAlignment.spaceBetween, | ||||||
|  |                   children: [ | ||||||
|  |                     SizedBox( | ||||||
|  |                         height: SizeConfig.height * .08, | ||||||
|  |                         child: Text( | ||||||
|  |                           subs, | ||||||
|  |                           style: const TextStyle(color: ColorPalette.primary), | ||||||
|  |                         )), | ||||||
|  |                     Row( | ||||||
|  |                       mainAxisAlignment: MainAxisAlignment.end, | ||||||
|  |                       children: [ | ||||||
|  |                         step == 'waiting' | ||||||
|  |                             ? const Icon(Icons.access_time_sharp, | ||||||
|  |                                 color: ColorPalette.slate400) | ||||||
|  |                             : const SizedBox(), | ||||||
|  |                         step == 'waiting' | ||||||
|  |                             ? Text(timeTransaction.toString()) | ||||||
|  |                             : const SizedBox(), | ||||||
|  |                         const Padding( | ||||||
|  |                           padding: EdgeInsets.only(left: 16.0), | ||||||
|  |                           child: Icon(Icons.arrow_forward_ios), | ||||||
|  |                         ), | ||||||
|  |                       ], | ||||||
|  |                     ), | ||||||
|  |                   ], | ||||||
|  |                 )), | ||||||
|  |           ], | ||||||
|  |         ), | ||||||
|  |       ), | ||||||
|  |     ); | ||||||
|  |   } | ||||||
|  | } | ||||||
| @@ -0,0 +1,44 @@ | |||||||
|  | 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/core/utils/size_config.dart'; | ||||||
|  | import 'package:flutter/material.dart'; | ||||||
|  |  | ||||||
|  | class EmptyCardTransaction extends StatelessWidget { | ||||||
|  |   final VoidCallback onPressedButton; | ||||||
|  |   const EmptyCardTransaction({Key? key, required this.onPressedButton}) | ||||||
|  |       : super(key: key); | ||||||
|  |  | ||||||
|  |   @override | ||||||
|  |   Widget build(BuildContext context) { | ||||||
|  |     TextTheme textTheme = Theme.of(context).textTheme; | ||||||
|  |     return Container( | ||||||
|  |       padding: const EdgeInsets.symmetric(vertical: 8.0), | ||||||
|  |       child: Center( | ||||||
|  |         child: Column( | ||||||
|  |           mainAxisAlignment: MainAxisAlignment.spaceAround, | ||||||
|  |           children: [ | ||||||
|  |             ImageView( | ||||||
|  |               image: PathAssets.imgEmptyTransaction, | ||||||
|  |               width: SizeConfig.width * .4, | ||||||
|  |             ), | ||||||
|  |             Text( | ||||||
|  |               'No Transaction Yet', | ||||||
|  |               style: textTheme.headlineSmall, | ||||||
|  |             ), | ||||||
|  |             Text( | ||||||
|  |               "Let's keep building your investment for even greater financial growth!", | ||||||
|  |               style: textTheme.bodyMedium, | ||||||
|  |               textAlign: TextAlign.center, | ||||||
|  |             ), | ||||||
|  |             ButtonView( | ||||||
|  |               name: 'Investing Now', | ||||||
|  |               width: SizeConfig.width * .5, | ||||||
|  |               onPressed: onPressedButton, | ||||||
|  |             ), | ||||||
|  |           ], | ||||||
|  |         ), | ||||||
|  |       ), | ||||||
|  |     ); | ||||||
|  |   } | ||||||
|  | } | ||||||
| @@ -11,9 +11,9 @@ class CustomAppBar extends StatelessWidget implements PreferredSizeWidget { | |||||||
|   const CustomAppBar({ |   const CustomAppBar({ | ||||||
|     Key? key, |     Key? key, | ||||||
|     required this.height, |     required this.height, | ||||||
|     this.leading, |  | ||||||
|     required this.title, |     required this.title, | ||||||
|     this.trailing, |     this.trailing, | ||||||
|  |     this.leading, | ||||||
|   }) : super(key: key); |   }) : super(key: key); | ||||||
|  |  | ||||||
|   @override |   @override | ||||||
|   | |||||||
							
								
								
									
										144
									
								
								lib/application/component/date_picker/date_picker_view.dart
									
									
									
									
									
										Normal file
									
								
							
							
						
						| @@ -0,0 +1,144 @@ | |||||||
|  | import 'package:calendar_date_picker2/calendar_date_picker2.dart'; | ||||||
|  | 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'; | ||||||
|  | import 'package:intl/intl.dart'; | ||||||
|  |  | ||||||
|  | class DatePickerView extends StatelessWidget { | ||||||
|  |   final String name; | ||||||
|  |   final TextEditingController ctrl; | ||||||
|  |   final DateTime? minDate, maxDate; | ||||||
|  |   final String? hintText, buttonName; | ||||||
|  |   final bool isMultipleSelection, enabled; | ||||||
|  |   final List<DateTime>? initialValue; | ||||||
|  |   final ValueChanged<OnChangedDatePickerModel>? onChanged; | ||||||
|  |   final ValueChanged<List<DateTime?>>? onFinish; | ||||||
|  |   final FormFieldValidator<String>? validatorDate; | ||||||
|  |   const DatePickerView( | ||||||
|  |       {Key? key, | ||||||
|  |       required this.name, | ||||||
|  |       required this.ctrl, | ||||||
|  |       this.minDate, | ||||||
|  |       this.maxDate, | ||||||
|  |       this.hintText, | ||||||
|  |       this.buttonName, | ||||||
|  |       required this.isMultipleSelection, | ||||||
|  |       required this.enabled, | ||||||
|  |       this.initialValue, | ||||||
|  |       this.onChanged, | ||||||
|  |       this.onFinish, | ||||||
|  |       this.validatorDate}) | ||||||
|  |       : super(key: key); | ||||||
|  |  | ||||||
|  |   String _dateFormat(DateTime? dateTime) => | ||||||
|  |       dateTime != null ? DateFormat('dd/MM/yyyy').format(dateTime) : ""; | ||||||
|  |  | ||||||
|  |   @override | ||||||
|  |   Widget build(BuildContext context) { | ||||||
|  |     List<DateTime?> initData = initialValue ?? []; | ||||||
|  |     List<DateTime?> dateList = []; | ||||||
|  |  | ||||||
|  |     String dateLabel() { | ||||||
|  |       return dateList.map((e) => _dateFormat(e)).join(" - "); | ||||||
|  |     } | ||||||
|  |  | ||||||
|  |     onChangedDatePicker(List<DateTime?> value) { | ||||||
|  |       if (isMultipleSelection) { | ||||||
|  |         final pickerDateRange = PickerDateRange( | ||||||
|  |           startDate: value[0] ?? DateTime.now(), | ||||||
|  |           endDate: | ||||||
|  |               value.length > 1 ? value[1] ?? DateTime.now() : DateTime.now(), | ||||||
|  |         ); | ||||||
|  |         onChanged | ||||||
|  |             ?.call(OnChangedDatePickerModel(pickerDateRange: pickerDateRange)); | ||||||
|  |       } else { | ||||||
|  |         onChanged?.call(OnChangedDatePickerModel(dateTime: value[0])); | ||||||
|  |       } | ||||||
|  |       dateList = value; | ||||||
|  |     } | ||||||
|  |  | ||||||
|  |     dialogDatePicker() { | ||||||
|  |       showModalBottomSheet( | ||||||
|  |         context: context, | ||||||
|  |         isScrollControlled: true, | ||||||
|  |         builder: (BuildContext context) { | ||||||
|  |           return Container( | ||||||
|  |             padding: const EdgeInsets.only(top: 16.0), | ||||||
|  |             height: SizeConfig.height * .65, | ||||||
|  |             child: Column( | ||||||
|  |               // mainAxisAlignment: MainAxisAlignment.spaceBetween, | ||||||
|  |               mainAxisSize: MainAxisSize.min, | ||||||
|  |               children: [ | ||||||
|  |                 CalendarDatePicker2( | ||||||
|  |                   value: [...initData], | ||||||
|  |                   config: CalendarDatePicker2Config( | ||||||
|  |                     centerAlignModePicker: true, | ||||||
|  |                     calendarType: isMultipleSelection | ||||||
|  |                         ? CalendarDatePicker2Type.range | ||||||
|  |                         : CalendarDatePicker2Type.single, | ||||||
|  |                     customModePickerIcon: const SizedBox(), | ||||||
|  |                     firstDate: minDate ?? DateTime(1900), | ||||||
|  |                     lastDate: maxDate, | ||||||
|  |                   ), | ||||||
|  |                   // initialValue: [...initData], | ||||||
|  |                   onValueChanged: (value) { | ||||||
|  |                     onChangedDatePicker(value); | ||||||
|  |                   }, | ||||||
|  |                 ), | ||||||
|  |                 Padding( | ||||||
|  |                   padding: const EdgeInsets.symmetric(horizontal: 16), | ||||||
|  |                   child: ButtonView( | ||||||
|  |                     width: SizeConfig.width, | ||||||
|  |                     onPressed: () { | ||||||
|  |                       if (dateList.isNotEmpty) { | ||||||
|  |                         onFinish?.call(dateList); | ||||||
|  |                         ctrl.text = dateLabel(); | ||||||
|  |                         initData = dateList; | ||||||
|  |                       } | ||||||
|  |                       Navigator.pop(context); | ||||||
|  |                     }, | ||||||
|  |                     name: 'OK', | ||||||
|  |                   ), | ||||||
|  |                 ), | ||||||
|  |               ], | ||||||
|  |             ), | ||||||
|  |           ); | ||||||
|  |         }, | ||||||
|  |       ); | ||||||
|  |     } | ||||||
|  |  | ||||||
|  |     return TextFormView( | ||||||
|  |       name: name, | ||||||
|  |       hintText: hintText, | ||||||
|  |       readOnly: true, | ||||||
|  |       ctrl: ctrl, | ||||||
|  |       validator: validatorDate, | ||||||
|  |       enabled: enabled, | ||||||
|  |       onTap: () { | ||||||
|  |         if (enabled) dialogDatePicker(); | ||||||
|  |       }, | ||||||
|  |       suffixIcon: const UnconstrainedBox( | ||||||
|  |         child: Icon( | ||||||
|  |           Icons.calendar_today_rounded, | ||||||
|  |           color: ColorPalette.slate400, | ||||||
|  |         ), | ||||||
|  |       ), | ||||||
|  |     ); | ||||||
|  |   } | ||||||
|  | } | ||||||
|  |  | ||||||
|  | class OnChangedDatePickerModel { | ||||||
|  |   final DateTime? dateTime; | ||||||
|  |   final PickerDateRange? pickerDateRange; | ||||||
|  |  | ||||||
|  |   OnChangedDatePickerModel({this.dateTime, this.pickerDateRange}); | ||||||
|  | } | ||||||
|  |  | ||||||
|  | class PickerDateRange { | ||||||
|  |   final DateTime startDate; | ||||||
|  |   final DateTime endDate; | ||||||
|  |  | ||||||
|  |   PickerDateRange({required this.startDate, required this.endDate}); | ||||||
|  | } | ||||||
| @@ -0,0 +1,119 @@ | |||||||
|  | import 'package:cims_apps/application/component/expandable_widget/see_more_less_widget.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 ExpandableWidget extends StatelessWidget { | ||||||
|  |   final String? content; | ||||||
|  |   final double? fontSize; | ||||||
|  |   final int maxLinesToShow; | ||||||
|  |   final Alignment? alignmentMore; | ||||||
|  |   final bool? hideTextMore; | ||||||
|  |   final bool? hideIconMore; | ||||||
|  |  | ||||||
|  |   ExpandableWidget({ | ||||||
|  |     super.key, | ||||||
|  |     required this.content, | ||||||
|  |     this.fontSize, | ||||||
|  |     this.maxLinesToShow = 1, | ||||||
|  |     this.alignmentMore, | ||||||
|  |     this.hideTextMore = false, | ||||||
|  |     this.hideIconMore = true, | ||||||
|  |   }); | ||||||
|  |  | ||||||
|  |   ValueNotifier<bool> expanded = ValueNotifier(false); | ||||||
|  |  | ||||||
|  |   @override | ||||||
|  |   Widget build(BuildContext context) { | ||||||
|  |     final TextSpan textSpan = TextSpan( | ||||||
|  |       text: content ?? "", | ||||||
|  |       style: TextStyle( | ||||||
|  |         fontSize: fontSize ?? 16.0, | ||||||
|  |         color: ColorPalette.slate400, | ||||||
|  |       ), | ||||||
|  |     ); | ||||||
|  |  | ||||||
|  |     final TextPainter textPainter = TextPainter( | ||||||
|  |       text: textSpan, | ||||||
|  |       maxLines: expanded.value ? null : maxLinesToShow, | ||||||
|  |       textDirection: TextDirection.ltr, | ||||||
|  |       strutStyle: StrutStyle( | ||||||
|  |         fontSize: fontSize ?? 16.0, | ||||||
|  |       ) | ||||||
|  |     ); | ||||||
|  |  | ||||||
|  |     textPainter.layout(maxWidth: SizeConfig.width); | ||||||
|  |  | ||||||
|  |     final int numberOfLines = textPainter.computeLineMetrics().length; | ||||||
|  |     return ValueListenableBuilder( | ||||||
|  |       valueListenable: expanded, | ||||||
|  |       builder: (context, values, _) { | ||||||
|  |         return Column( | ||||||
|  |           crossAxisAlignment: CrossAxisAlignment.start, | ||||||
|  |           children: [ | ||||||
|  |             LayoutBuilder( | ||||||
|  |               builder: (BuildContext context, BoxConstraints constraints) { | ||||||
|  |                 if (!expanded.value && numberOfLines >= maxLinesToShow) { | ||||||
|  |                   return Column( | ||||||
|  |                     crossAxisAlignment: CrossAxisAlignment.start, | ||||||
|  |                     children: [ | ||||||
|  |                       Text( | ||||||
|  |                         content ?? "", | ||||||
|  |                         maxLines: maxLinesToShow, | ||||||
|  |                         overflow: TextOverflow.ellipsis, | ||||||
|  |                         style: TextStyle( | ||||||
|  |                           fontSize: fontSize ?? 16.0, | ||||||
|  |                           color: ColorPalette.slate400, | ||||||
|  |                         ), | ||||||
|  |                       ), | ||||||
|  |                       /* See More :: type 1 - See More | 2 - See Less */ | ||||||
|  |                       SeeMoreLessWidget( | ||||||
|  |                         textData: 'See More', | ||||||
|  |                         type: 1, | ||||||
|  |                         section: 1, | ||||||
|  |                         onSeeMoreLessTap: () { | ||||||
|  |                           expanded.value = true; | ||||||
|  |                         }, | ||||||
|  |                         alignment: alignmentMore, | ||||||
|  |                         hideIconMore: hideIconMore!, | ||||||
|  |                         hideTextMore: hideTextMore!, | ||||||
|  |                       ), | ||||||
|  |                       /* See More :: type 1 - See More | 2 - See Less */ | ||||||
|  |                     ], | ||||||
|  |                   ); | ||||||
|  |                 } else { | ||||||
|  |                   return Column( | ||||||
|  |                     crossAxisAlignment: CrossAxisAlignment.start, | ||||||
|  |                     children: [ | ||||||
|  |                       Text( | ||||||
|  |                         content ?? "", | ||||||
|  |                         style: TextStyle( | ||||||
|  |                           fontSize: fontSize ?? 16.0, | ||||||
|  |                           color: ColorPalette.slate400, | ||||||
|  |                         ), | ||||||
|  |                       ), | ||||||
|  |                       if (expanded.value && numberOfLines >= maxLinesToShow) | ||||||
|  |                       /* See Less :: type 1 - See More | 2 - See Less */ | ||||||
|  |                         SeeMoreLessWidget( | ||||||
|  |                           textData: 'See Less', | ||||||
|  |                           type: 2, | ||||||
|  |                           section: 1, | ||||||
|  |                           onSeeMoreLessTap: () { | ||||||
|  |                             expanded.value = false; | ||||||
|  |                           }, | ||||||
|  |                           alignment: alignmentMore, | ||||||
|  |                           hideIconMore: hideIconMore!, | ||||||
|  |                           hideTextMore: hideTextMore!, | ||||||
|  |                         ), | ||||||
|  |                       /* See Less :: type 1 - See More | 2 - See Less */ | ||||||
|  |                     ], | ||||||
|  |                   ); | ||||||
|  |                 } | ||||||
|  |               }, | ||||||
|  |             ), | ||||||
|  |           ], | ||||||
|  |         ); | ||||||
|  |       }, | ||||||
|  |     ); | ||||||
|  |   } | ||||||
|  | } | ||||||
| @@ -0,0 +1,74 @@ | |||||||
|  | import 'package:cims_apps/application/theme/color_palette.dart'; | ||||||
|  | import 'package:flutter/material.dart'; | ||||||
|  |  | ||||||
|  | class SeeMoreLessWidget extends StatelessWidget { | ||||||
|  |   final String? textData; | ||||||
|  |   final int? type; /* type 1 - See More | 2 - See Less */ | ||||||
|  |   final Function? onSeeMoreLessTap; | ||||||
|  |   final int? | ||||||
|  |   section; /* 1: About the course | 2 - Who can take up this course? | 3 - Mentors | 4 - Course Video Reviews */ | ||||||
|  |   final Alignment? alignment; | ||||||
|  |   final bool hideTextMore; | ||||||
|  |   final bool hideIconMore; | ||||||
|  |  | ||||||
|  |   const SeeMoreLessWidget({ | ||||||
|  |     super.key, | ||||||
|  |     required this.textData, | ||||||
|  |     required this.type, | ||||||
|  |     required this.onSeeMoreLessTap, | ||||||
|  |     required this.section, | ||||||
|  |     required this.alignment, | ||||||
|  |     required this.hideTextMore, | ||||||
|  |     required this.hideIconMore, | ||||||
|  |   }); | ||||||
|  |  | ||||||
|  |   @override | ||||||
|  |   Widget build(BuildContext context) { | ||||||
|  |     return Align( | ||||||
|  |       alignment: alignment ?? Alignment.centerLeft, | ||||||
|  |       child: InkWell( | ||||||
|  |         onTap: () { | ||||||
|  |           if (onSeeMoreLessTap != null) { | ||||||
|  |             onSeeMoreLessTap!(); | ||||||
|  |           } | ||||||
|  |         }, | ||||||
|  |         child: Text.rich( | ||||||
|  |           softWrap: true, | ||||||
|  |           style: const TextStyle( | ||||||
|  |             color: ColorPalette.primary, | ||||||
|  |           ), | ||||||
|  |           textAlign: TextAlign.start, | ||||||
|  |           TextSpan( | ||||||
|  |             text: "", | ||||||
|  |             children: [ | ||||||
|  |               if(!hideTextMore) | ||||||
|  |                 TextSpan( | ||||||
|  |                   text: textData, | ||||||
|  |                   style: const TextStyle( | ||||||
|  |                       color: ColorPalette.primary, | ||||||
|  |                       decoration: TextDecoration.underline, | ||||||
|  |                   ), | ||||||
|  |                 ), | ||||||
|  |               if(!hideTextMore && !hideIconMore) | ||||||
|  |                 const WidgetSpan( | ||||||
|  |                   child: SizedBox( | ||||||
|  |                     width: 3.0, | ||||||
|  |                   ), | ||||||
|  |                 ), | ||||||
|  |               if(!hideIconMore) | ||||||
|  |                 WidgetSpan( | ||||||
|  |                   child: Icon( | ||||||
|  |                     (type == 1) | ||||||
|  |                         ? Icons.keyboard_arrow_down | ||||||
|  |                         : Icons.keyboard_arrow_up, | ||||||
|  |                     color: ColorPalette.slate300, | ||||||
|  |                     size: 28, | ||||||
|  |                   ), | ||||||
|  |                 ), | ||||||
|  |             ], | ||||||
|  |           ), | ||||||
|  |         ), | ||||||
|  |       ), | ||||||
|  |     ); | ||||||
|  |   } | ||||||
|  | } | ||||||
| @@ -84,7 +84,7 @@ class NumericPad extends StatelessWidget { | |||||||
|   } |   } | ||||||
|  |  | ||||||
|   Widget spaceWidget() { |   Widget spaceWidget() { | ||||||
|     return Expanded( |     return const Expanded( | ||||||
|         child: SizedBox() |         child: SizedBox() | ||||||
|     ); |     ); | ||||||
|   } |   } | ||||||
| @@ -96,13 +96,15 @@ class NumericPad extends StatelessWidget { | |||||||
|             onNumberSelected(number); |             onNumberSelected(number); | ||||||
|           }, |           }, | ||||||
|           child: Container( |           child: Container( | ||||||
|  |             color: Colors.transparent, | ||||||
|             padding: EdgeInsets.symmetric(vertical: SizeConfig.height * .028), |             padding: EdgeInsets.symmetric(vertical: SizeConfig.height * .028), | ||||||
|             child: Text( |             child: Text( | ||||||
|               number, |               number, | ||||||
|               textAlign: TextAlign.center, |               textAlign: TextAlign.center, | ||||||
|               style: TextStyle( |               style: const TextStyle( | ||||||
|                   fontSize: 28, |                 fontSize: 28, | ||||||
|                   fontWeight: FontWeight.bold |                 fontWeight: FontWeight.bold, | ||||||
|  |                 color: ColorPalette.slate800 | ||||||
|               ), |               ), | ||||||
|             ), |             ), | ||||||
|           ), |           ), | ||||||
| @@ -116,9 +118,14 @@ class NumericPad extends StatelessWidget { | |||||||
|           onTap: () { |           onTap: () { | ||||||
|             onNumberSelected(''); |             onNumberSelected(''); | ||||||
|           }, |           }, | ||||||
|           child: Icon( |           child: Container( | ||||||
|             Icons.highlight_remove, |             color: Colors.transparent, | ||||||
|             size: 28, |             padding: EdgeInsets.symmetric(vertical: SizeConfig.height * .028), | ||||||
|  |             child: const Icon( | ||||||
|  |               Icons.backspace_outlined, | ||||||
|  |               size: 28, | ||||||
|  |               color: ColorPalette.slate800, | ||||||
|  |             ), | ||||||
|           ), |           ), | ||||||
|         ) |         ) | ||||||
|     ); |     ); | ||||||
|   | |||||||
							
								
								
									
										57
									
								
								lib/application/component/radio_agreement.dart
									
									
									
									
									
										Normal file
									
								
							
							
						
						| @@ -0,0 +1,57 @@ | |||||||
|  | import 'package:cims_apps/application/component/expandable_widget/expandable_widget.dart'; | ||||||
|  | import 'package:cims_apps/application/theme/color_palette.dart'; | ||||||
|  | import 'package:flutter/material.dart'; | ||||||
|  |  | ||||||
|  | class RadioAgreement extends StatelessWidget { | ||||||
|  |   final void Function() onTap; | ||||||
|  |   final bool isAgree; | ||||||
|  |   final String desc; | ||||||
|  |   const RadioAgreement({super.key, required this.isAgree, required this.desc, required this.onTap,}); | ||||||
|  |  | ||||||
|  |   @override | ||||||
|  |   Widget build(BuildContext context) { | ||||||
|  |     return Padding( | ||||||
|  |       padding: const EdgeInsets.symmetric(horizontal: 24, vertical: 16), | ||||||
|  |       child: Row( | ||||||
|  |         crossAxisAlignment: CrossAxisAlignment.start, | ||||||
|  |         children: [ | ||||||
|  |           GestureDetector( | ||||||
|  |             onTap: onTap, | ||||||
|  |             child: AnimatedContainer( | ||||||
|  |               margin: const EdgeInsets.only(top: 4), | ||||||
|  |               duration: const Duration(milliseconds: 200), | ||||||
|  |               height: 16, | ||||||
|  |               width: 16, | ||||||
|  |               padding: const EdgeInsets.all(1), | ||||||
|  |               alignment: Alignment.center, | ||||||
|  |               decoration: BoxDecoration( | ||||||
|  |                   shape: BoxShape.circle, | ||||||
|  |                   border: Border.all( | ||||||
|  |                       color: isAgree | ||||||
|  |                           ? ColorPalette.primary | ||||||
|  |                           : ColorPalette.slate200)), | ||||||
|  |               child: AnimatedContainer( | ||||||
|  |                 duration: const Duration(milliseconds: 200), | ||||||
|  |                 child: Container( | ||||||
|  |                   decoration: BoxDecoration( | ||||||
|  |                       color: | ||||||
|  |                       isAgree ? ColorPalette.primary : ColorPalette.white, | ||||||
|  |                       shape: BoxShape.circle), | ||||||
|  |                 ), | ||||||
|  |               ), | ||||||
|  |             ), | ||||||
|  |           ), | ||||||
|  |           const SizedBox( | ||||||
|  |             width: 12, | ||||||
|  |           ), | ||||||
|  |           Expanded( | ||||||
|  |             child: ExpandableWidget( | ||||||
|  |               content: desc, | ||||||
|  |               maxLinesToShow: 3, | ||||||
|  |             ) | ||||||
|  |           ) | ||||||
|  |         ], | ||||||
|  |       ), | ||||||
|  |     ); | ||||||
|  |   } | ||||||
|  | } | ||||||
| @@ -1,4 +1,5 @@ | |||||||
| import 'package:cims_apps/application/assets/path_assets.dart'; | import 'package:cims_apps/application/assets/path_assets.dart'; | ||||||
|  | import 'package:cims_apps/application/component/expandable_widget/expandable_widget.dart'; | ||||||
| import 'package:cims_apps/application/theme/color_palette.dart'; | import 'package:cims_apps/application/theme/color_palette.dart'; | ||||||
| import 'package:cims_apps/core/utils/size_config.dart'; | import 'package:cims_apps/core/utils/size_config.dart'; | ||||||
| import 'package:cims_apps/features/auth/registration/view/submission_data/risk_profile/risk_profile_view_model/risk_profile_view_model.dart'; | import 'package:cims_apps/features/auth/registration/view/submission_data/risk_profile/risk_profile_view_model/risk_profile_view_model.dart'; | ||||||
| @@ -73,20 +74,20 @@ class RiskProfile extends StatelessWidget { | |||||||
|               mainAxisAlignment: MainAxisAlignment.spaceBetween, |               mainAxisAlignment: MainAxisAlignment.spaceBetween, | ||||||
|               children: [ |               children: [ | ||||||
|                 Container( |                 Container( | ||||||
|                   padding: EdgeInsets.all(24), |                   padding: const EdgeInsets.all(24), | ||||||
|                   child: Column( |                   child: Column( | ||||||
|                     crossAxisAlignment: CrossAxisAlignment.start, |                     crossAxisAlignment: CrossAxisAlignment.start, | ||||||
|                     children: [ |                     children: [ | ||||||
|                       Text( |                       Text( | ||||||
|                         riskProfile.type, |                         riskProfile.type, | ||||||
|                         style: TextStyle( |                         style: const TextStyle( | ||||||
|                             fontWeight: FontWeight.bold, |                             fontWeight: FontWeight.bold, | ||||||
|                             fontSize: 24, |                             fontSize: 24, | ||||||
|                             color: ColorPalette.white |                             color: ColorPalette.white | ||||||
|                         ), |                         ), | ||||||
|                       ), |                       ), | ||||||
|                       SizedBox(height: 16,), |                       const SizedBox(height: 16,), | ||||||
|                       Text('Total Score :', |                       const Text('Total Score :', | ||||||
|                         style: TextStyle( |                         style: TextStyle( | ||||||
|                             fontWeight: FontWeight.bold, |                             fontWeight: FontWeight.bold, | ||||||
|                             fontSize: 16, |                             fontSize: 16, | ||||||
| @@ -94,7 +95,7 @@ class RiskProfile extends StatelessWidget { | |||||||
|                         ), |                         ), | ||||||
|                       ), |                       ), | ||||||
|                       Text('$totalScore', |                       Text('$totalScore', | ||||||
|                         style: TextStyle( |                         style: const TextStyle( | ||||||
|                             fontWeight: FontWeight.bold, |                             fontWeight: FontWeight.bold, | ||||||
|                             fontSize: 28, |                             fontSize: 28, | ||||||
|                             color: ColorPalette.white |                             color: ColorPalette.white | ||||||
| @@ -107,20 +108,20 @@ class RiskProfile extends StatelessWidget { | |||||||
|             ), |             ), | ||||||
|           ), |           ), | ||||||
|         ), |         ), | ||||||
|         SizedBox( |         const SizedBox( | ||||||
|           height: 24, |           height: 24, | ||||||
|         ), |         ), | ||||||
|         Text( |         ExpandableWidget( | ||||||
|             riskProfile.desc, |           content: riskProfile.desc, | ||||||
|             style: TextStyle( |           hideTextMore: true, | ||||||
|                 color: ColorPalette.slate500, |           hideIconMore: false, | ||||||
|                 fontSize: 16 |           maxLinesToShow: 4, | ||||||
|             ) |           alignmentMore: Alignment.center, | ||||||
|         ), |         ), | ||||||
|         SizedBox( |         const SizedBox( | ||||||
|           height: 24, |           height: 24, | ||||||
|         ), |         ), | ||||||
|         Text( |         const Text( | ||||||
|           'Suitable Product', |           'Suitable Product', | ||||||
|           style: TextStyle( |           style: TextStyle( | ||||||
|               color: ColorPalette.slate800, |               color: ColorPalette.slate800, | ||||||
| @@ -128,7 +129,7 @@ class RiskProfile extends StatelessWidget { | |||||||
|               fontSize: 18 |               fontSize: 18 | ||||||
|           ), |           ), | ||||||
|         ), |         ), | ||||||
|         SizedBox( |         const SizedBox( | ||||||
|           height: 16, |           height: 16, | ||||||
|         ), |         ), | ||||||
|         rowSuitableProduct ? |         rowSuitableProduct ? | ||||||
| @@ -137,7 +138,7 @@ class RiskProfile extends StatelessWidget { | |||||||
|               return Expanded( |               return Expanded( | ||||||
|                 child: Container( |                 child: Container( | ||||||
|                   margin: EdgeInsets.only(left: e.key != 0 ? 12 : 0), |                   margin: EdgeInsets.only(left: e.key != 0 ? 12 : 0), | ||||||
|                   padding: EdgeInsets.all(16), |                   padding: const EdgeInsets.all(16), | ||||||
|                   decoration: BoxDecoration( |                   decoration: BoxDecoration( | ||||||
|                     border: Border.all(color: ColorPalette.slate200), |                     border: Border.all(color: ColorPalette.slate200), | ||||||
|                     borderRadius: BorderRadius.circular(6) |                     borderRadius: BorderRadius.circular(6) | ||||||
| @@ -146,18 +147,18 @@ class RiskProfile extends StatelessWidget { | |||||||
|                     crossAxisAlignment: CrossAxisAlignment.start, |                     crossAxisAlignment: CrossAxisAlignment.start, | ||||||
|                     children: [ |                     children: [ | ||||||
|                       Container( |                       Container( | ||||||
|                           padding: EdgeInsets.all(8), |                           padding: const EdgeInsets.all(8), | ||||||
|                           decoration: BoxDecoration( |                           decoration: BoxDecoration( | ||||||
|                               shape: BoxShape.circle, |                               shape: BoxShape.circle, | ||||||
|                               color: riskProfile.color.withOpacity(0.1) |                               color: riskProfile.color.withOpacity(0.1) | ||||||
|                           ), |                           ), | ||||||
|                           child: Image.asset(e.value['icon'], width: SizeConfig.width * 0.07, color: riskProfile.color) |                           child: Image.asset(e.value['icon'], width: SizeConfig.width * 0.07, color: riskProfile.color) | ||||||
|                       ), |                       ), | ||||||
|                       SizedBox( |                       const SizedBox( | ||||||
|                         height: 12, |                         height: 12, | ||||||
|                       ), |                       ), | ||||||
|                       Text(e.value['desc'], |                       Text(e.value['desc'], | ||||||
|                         style: TextStyle( |                         style: const TextStyle( | ||||||
|                             fontSize: 16, |                             fontSize: 16, | ||||||
|                             fontWeight: FontWeight.bold, |                             fontWeight: FontWeight.bold, | ||||||
|                             color: ColorPalette.slate800 |                             color: ColorPalette.slate800 | ||||||
| @@ -173,7 +174,7 @@ class RiskProfile extends StatelessWidget { | |||||||
|           runSpacing: 16, |           runSpacing: 16, | ||||||
|           children: riskProfile.suitableProduct.map((e) { |           children: riskProfile.suitableProduct.map((e) { | ||||||
|             return Container( |             return Container( | ||||||
|               padding: EdgeInsets.all(16), |               padding: const EdgeInsets.all(16), | ||||||
|               decoration: BoxDecoration( |               decoration: BoxDecoration( | ||||||
|                 borderRadius: BorderRadius.circular(6), |                 borderRadius: BorderRadius.circular(6), | ||||||
|                 border: Border.all(color: ColorPalette.slate200), |                 border: Border.all(color: ColorPalette.slate200), | ||||||
| @@ -181,7 +182,7 @@ class RiskProfile extends StatelessWidget { | |||||||
|               child: Row( |               child: Row( | ||||||
|                 children: [ |                 children: [ | ||||||
|                   Container( |                   Container( | ||||||
|                       padding: EdgeInsets.all(8), |                       padding: const EdgeInsets.all(8), | ||||||
|                       alignment: Alignment.center, |                       alignment: Alignment.center, | ||||||
|                       decoration: BoxDecoration( |                       decoration: BoxDecoration( | ||||||
|                           shape: BoxShape.circle, |                           shape: BoxShape.circle, | ||||||
| @@ -189,12 +190,12 @@ class RiskProfile extends StatelessWidget { | |||||||
|                       ), |                       ), | ||||||
|                       child: Image.asset(e['icon'], width: SizeConfig.width * 0.07, color: riskProfile.color) |                       child: Image.asset(e['icon'], width: SizeConfig.width * 0.07, color: riskProfile.color) | ||||||
|                   ), |                   ), | ||||||
|                   SizedBox( |                   const SizedBox( | ||||||
|                     width: 12, |                     width: 12, | ||||||
|                   ), |                   ), | ||||||
|                   Expanded( |                   Expanded( | ||||||
|                     child: Text(e['desc'], |                     child: Text(e['desc'], | ||||||
|                       style: TextStyle( |                       style: const TextStyle( | ||||||
|                           fontSize: 18, |                           fontSize: 18, | ||||||
|                           fontWeight: FontWeight.bold, |                           fontWeight: FontWeight.bold, | ||||||
|                           color: ColorPalette.slate800 |                           color: ColorPalette.slate800 | ||||||
|   | |||||||
| @@ -47,6 +47,7 @@ class SelectFormView extends StatelessWidget { | |||||||
|     bottomSheet() { |     bottomSheet() { | ||||||
|       showModalBottomSheet<void>( |       showModalBottomSheet<void>( | ||||||
|         context: context, |         context: context, | ||||||
|  |         isDismissible: false, | ||||||
|         shape: RoundedRectangleBorder( |         shape: RoundedRectangleBorder( | ||||||
|           borderRadius: BorderRadius.only( |           borderRadius: BorderRadius.only( | ||||||
|             topLeft: _borderRadius, |             topLeft: _borderRadius, | ||||||
| @@ -82,7 +83,10 @@ class SelectFormView extends StatelessWidget { | |||||||
|                         ), |                         ), | ||||||
|                       ), |                       ), | ||||||
|                       IconButton( |                       IconButton( | ||||||
|                           onPressed: () => Navigator.pop(context), |                           onPressed: () { | ||||||
|  |                             ctrl?.clear(); | ||||||
|  |                             Navigator.pop(context); | ||||||
|  |                           }, | ||||||
|                           icon: const Icon( |                           icon: const Icon( | ||||||
|                             Icons.clear, |                             Icons.clear, | ||||||
|                             size: 26, |                             size: 26, | ||||||
| @@ -134,7 +138,7 @@ class SelectFormView extends StatelessWidget { | |||||||
|                                 onTap: () { |                                 onTap: () { | ||||||
|                                   stateSetter(() { |                                   stateSetter(() { | ||||||
|                                     ctrl?.text = e.text; |                                     ctrl?.text = e.text; | ||||||
|                                     onSelect(e.key); |                                     onSelect(e.text); | ||||||
|                                   }); |                                   }); | ||||||
|                                 }, |                                 }, | ||||||
|                               ), |                               ), | ||||||
| @@ -148,7 +152,9 @@ class SelectFormView extends StatelessWidget { | |||||||
|                     name: 'Select', |                     name: 'Select', | ||||||
|                     marginVertical: 4.0, |                     marginVertical: 4.0, | ||||||
|                     onPressed: () { |                     onPressed: () { | ||||||
|                       Navigator.pop(context); |                       if (ctrl!.text.isNotEmpty) { | ||||||
|  |                         Navigator.pop(context); | ||||||
|  |                       } | ||||||
|                     }, |                     }, | ||||||
|                   ) |                   ) | ||||||
|                 ], |                 ], | ||||||
|   | |||||||
| @@ -36,8 +36,8 @@ class GoalInvestingView extends StatelessWidget { | |||||||
|                   routePush( |                   routePush( | ||||||
|                     context, |                     context, | ||||||
|                     page: OtherPlanView( |                     page: OtherPlanView( | ||||||
|                       selectedPlan: (value) { |                       selectedPlan: (val) { | ||||||
|                         onListSelected(e.value.title); |                         onListSelected(val); | ||||||
|                       }, |                       }, | ||||||
|                     ) |                     ) | ||||||
|                   ); |                   ); | ||||||
|   | |||||||
| @@ -1,3 +1,5 @@ | |||||||
|  | import 'dart:math'; | ||||||
|  |  | ||||||
| import 'package:cims_apps/application/component/button/button_view.dart'; | import 'package:cims_apps/application/component/button/button_view.dart'; | ||||||
| import 'package:cims_apps/application/component/numeric_pad/numeric_pad.dart'; | import 'package:cims_apps/application/component/numeric_pad/numeric_pad.dart'; | ||||||
| import 'package:cims_apps/application/theme/color_palette.dart'; | import 'package:cims_apps/application/theme/color_palette.dart'; | ||||||
| @@ -6,9 +8,13 @@ import 'package:cims_apps/core/utils/size_config.dart'; | |||||||
| import 'package:flutter/material.dart'; | import 'package:flutter/material.dart'; | ||||||
|  |  | ||||||
| class InputInvestmentView extends StatefulWidget { | class InputInvestmentView extends StatefulWidget { | ||||||
|   final String selectedPlan; |   final String? currentPlan; | ||||||
|  |   final void Function()? changePlan; | ||||||
|  |   final int? currentPrice; | ||||||
|  |   final int? minimumPrice; | ||||||
|  |   final int? maximumPrice; | ||||||
|   final void Function(String value) nextMove; |   final void Function(String value) nextMove; | ||||||
|   const InputInvestmentView({super.key, required this.selectedPlan, required this.nextMove}); |   const InputInvestmentView({super.key, required this.nextMove, this.currentPlan, this.minimumPrice, this.maximumPrice, this.currentPrice, this.changePlan}); | ||||||
|  |  | ||||||
|   @override |   @override | ||||||
|   State<InputInvestmentView> createState() => _InputInvestmentViewState(); |   State<InputInvestmentView> createState() => _InputInvestmentViewState(); | ||||||
| @@ -17,10 +23,35 @@ class InputInvestmentView extends StatefulWidget { | |||||||
| class _InputInvestmentViewState extends State<InputInvestmentView> { | class _InputInvestmentViewState extends State<InputInvestmentView> { | ||||||
|   TextEditingController inputController = TextEditingController(); |   TextEditingController inputController = TextEditingController(); | ||||||
|  |  | ||||||
|  |   void validationInputValue(String currentValue) { | ||||||
|  |     currentValue = currentValue.replaceAll('Rp ', '').replaceAll('.', ''); | ||||||
|  |     if(currentValue.isEmpty){ | ||||||
|  |       currentValue = '0'; | ||||||
|  |     } | ||||||
|  |     double parseValue = double.parse(currentValue); | ||||||
|  |     if(widget.minimumPrice != null){ | ||||||
|  |       if(parseValue <= widget.minimumPrice!){ | ||||||
|  |         parseValue = widget.minimumPrice!.toDouble(); | ||||||
|  |       } | ||||||
|  |     } | ||||||
|  |  | ||||||
|  |     if(widget.maximumPrice != null){ | ||||||
|  |       if(parseValue >= widget.maximumPrice!){ | ||||||
|  |         parseValue = widget.maximumPrice!.toDouble(); | ||||||
|  |       } | ||||||
|  |     } | ||||||
|  |  | ||||||
|  |     inputController.text = NumberFormatter.numberCurrency(parseValue, 'Rp ', 'id_ID', decimalDigits: 0); | ||||||
|  |   } | ||||||
|  |  | ||||||
|   @override |   @override | ||||||
|   void initState() { |   void initState() { | ||||||
|     // TODO: implement initState |     // TODO: implement initState | ||||||
|     inputController.text = 'Rp 0'; |     if(widget.currentPrice != null){ | ||||||
|  |       inputController.text = NumberFormatter.numberCurrency(widget.currentPrice, 'Rp ', 'id_ID', decimalDigits: 0); | ||||||
|  |     }else{ | ||||||
|  |       inputController.text = 'Rp 0'; | ||||||
|  |     } | ||||||
|     super.initState(); |     super.initState(); | ||||||
|   } |   } | ||||||
|  |  | ||||||
| @@ -41,56 +72,53 @@ class _InputInvestmentViewState extends State<InputInvestmentView> { | |||||||
|       child: Column( |       child: Column( | ||||||
|         mainAxisSize: MainAxisSize.min, |         mainAxisSize: MainAxisSize.min, | ||||||
|         children: [ |         children: [ | ||||||
|           SizedBox(height: 16), |  | ||||||
|           Padding( |           Padding( | ||||||
|             padding: EdgeInsets.symmetric(horizontal: 24, vertical: 12), |             padding: const EdgeInsets.symmetric(horizontal: 24, vertical: 12), | ||||||
|             child: Column( |             child: Column( | ||||||
|               crossAxisAlignment: CrossAxisAlignment.start, |               crossAxisAlignment: CrossAxisAlignment.start, | ||||||
|               children: [ |               children: [ | ||||||
|                 Row( |                 if(widget.currentPlan != null) | ||||||
|                   mainAxisAlignment: MainAxisAlignment.spaceBetween, |                   Row( | ||||||
|                   children: [ |                     mainAxisAlignment: MainAxisAlignment.spaceBetween, | ||||||
|                     Text(widget.selectedPlan, |                     children: [ | ||||||
|                       style: TextStyle( |                       Text(widget.currentPlan ?? '', | ||||||
|                         fontSize: 20, |                         style: const TextStyle( | ||||||
|                         fontWeight: FontWeight.w700, |                           fontSize: 20, | ||||||
|  |                           fontWeight: FontWeight.w700, | ||||||
|  |                         ), | ||||||
|                       ), |                       ), | ||||||
|                     ), |                       InkWell( | ||||||
|                     Row( |                         borderRadius: BorderRadius.circular(16), | ||||||
|                       children: [ |                         onTap: widget.changePlan, | ||||||
|                         Icon(Icons.change_circle_outlined, color: ColorPalette.primary, size: 20), |                         child: const Row( | ||||||
|                         SizedBox(width: 4), |                           children: [ | ||||||
|                         Text('Change', |                             Icon(Icons.change_circle_outlined, color: ColorPalette.primary, size: 20), | ||||||
|                           style: TextStyle( |                             SizedBox(width: 4), | ||||||
|                               fontSize: 16, |                             Text('Change', | ||||||
|                               fontWeight: FontWeight.w600, |                               style: TextStyle( | ||||||
|                               color: ColorPalette.primary |                                   fontSize: 16, | ||||||
|                           ), |                                   fontWeight: FontWeight.w600, | ||||||
|                         ) |                                   color: ColorPalette.primary | ||||||
|                       ], |                               ), | ||||||
|                     ) |                             ) | ||||||
|                   ], |                           ], | ||||||
|                 ), |                         ), | ||||||
|  |                       ) | ||||||
|  |                     ], | ||||||
|  |                   ), | ||||||
|                 TextField( |                 TextField( | ||||||
|                   controller: inputController, |                   controller: inputController, | ||||||
|                   textAlign: TextAlign.center, |                   textAlign: TextAlign.center, | ||||||
|                   style: TextStyle( |                   style: const TextStyle( | ||||||
|                       fontSize: 28, |                       fontSize: 28, | ||||||
|                       fontWeight: FontWeight.w600, |                       fontWeight: FontWeight.w600, | ||||||
|                       color: ColorPalette.slate800 |                       color: ColorPalette.slate800 | ||||||
|                   ), |                   ), | ||||||
|                   keyboardType: TextInputType.number, |                   keyboardType: TextInputType.number, | ||||||
|                   onChanged: (value) { |                   onChanged: (value) { | ||||||
|                     value = value.replaceAll('Rp ', '').replaceAll('.', ''); |                     validationInputValue(value); | ||||||
|                     double parseValue = double.parse(value); |  | ||||||
|                     if(value.isNotEmpty){ |  | ||||||
|                       inputController.text = NumberFormatter.numberCurrency(parseValue, 'Rp ', 'id_ID', decimalDigits: 0); |  | ||||||
|                     }else{ |  | ||||||
|                       inputController.text = NumberFormatter.numberCurrency(0, 'Rp ', 'id_ID', decimalDigits: 0); |  | ||||||
|                     } |  | ||||||
|                   }, |                   }, | ||||||
|                   decoration: InputDecoration( |                   decoration: const InputDecoration( | ||||||
|                       enabledBorder: UnderlineInputBorder( |                       enabledBorder: UnderlineInputBorder( | ||||||
|                         borderSide: BorderSide( |                         borderSide: BorderSide( | ||||||
|                             color: ColorPalette.primary, |                             color: ColorPalette.primary, | ||||||
| @@ -99,30 +127,36 @@ class _InputInvestmentViewState extends State<InputInvestmentView> { | |||||||
|                       ) |                       ) | ||||||
|                   ), |                   ), | ||||||
|                 ), |                 ), | ||||||
|                 SizedBox(height: 12), |                 const SizedBox(height: 12), | ||||||
|                 Text('Minimum Budget Rp1,000,000', |                 if(widget.minimumPrice != null) | ||||||
|                   style: TextStyle( |                   Text('Minimum ${NumberFormatter.numberCurrency(widget.minimumPrice, 'Rp ', 'id_ID')}', | ||||||
|                       color: ColorPalette.slate400, |                     style: const TextStyle( | ||||||
|                       fontSize: 16, |                         color: ColorPalette.slate400, | ||||||
|                       fontWeight: FontWeight.w600 |                         fontSize: 16, | ||||||
|  |                         fontWeight: FontWeight.w600 | ||||||
|  |                     ), | ||||||
|                   ), |                   ), | ||||||
|                 ), |                 if(widget.maximumPrice != null) | ||||||
|                 SizedBox(height: 16), |                   Text('Maximum ${NumberFormatter.numberCurrency(widget.maximumPrice, 'Rp ', 'id_ID')}', | ||||||
|  |                     style: const TextStyle( | ||||||
|  |                         color: ColorPalette.slate400, | ||||||
|  |                         fontSize: 16, | ||||||
|  |                         fontWeight: FontWeight.w600 | ||||||
|  |                     ), | ||||||
|  |                   ), | ||||||
|  |                 const SizedBox(height: 16), | ||||||
|                 NumericPad(onNumberSelected: (p0) { |                 NumericPad(onNumberSelected: (p0) { | ||||||
|                   String checkIsZeroInput = inputController.text.replaceAll('Rp ', '').replaceAll(',', ''); |                   String currentValue = inputController.text; | ||||||
|                   String getNumeric = p0; |  | ||||||
|                   if(p0.isNotEmpty){ |                   if(p0.isNotEmpty){ | ||||||
|                     if(checkIsZeroInput != '0'){ |                     if(currentValue != '0'){ | ||||||
|                       getNumeric = checkIsZeroInput + getNumeric; |                       currentValue = currentValue + p0; | ||||||
|                     } |                     } | ||||||
|                   }else{ |                   }else{ | ||||||
|                     getNumeric = checkIsZeroInput.substring(0, checkIsZeroInput.length - 1); |                     currentValue = currentValue.substring(0, currentValue.length - 1); | ||||||
|                   } |                   } | ||||||
|                   String formatNumeric = NumberFormatter.numberCurrency( |                   validationInputValue(currentValue); | ||||||
|                       double.parse(getNumeric), 'Rp ', 'id_ID', decimalDigits: 0).replaceAll('.', ','); |  | ||||||
|                   inputController.text = formatNumeric; |  | ||||||
|                 }), |                 }), | ||||||
|                 SizedBox(height: 8), |                 const SizedBox(height: 24), | ||||||
|                 ButtonView( |                 ButtonView( | ||||||
|                   name: 'Next', |                   name: 'Next', | ||||||
|                   onPressed: () { |                   onPressed: () { | ||||||
| @@ -130,7 +164,7 @@ class _InputInvestmentViewState extends State<InputInvestmentView> { | |||||||
|                   }, |                   }, | ||||||
|                   width: SizeConfig.width, |                   width: SizeConfig.width, | ||||||
|                   heightWrapContent: true, |                   heightWrapContent: true, | ||||||
|                   contentPadding: EdgeInsets.symmetric(vertical: 16), |                   contentPadding: const EdgeInsets.symmetric(vertical: 16), | ||||||
|                   marginVertical: 0, |                   marginVertical: 0, | ||||||
|                 ) |                 ) | ||||||
|               ], |               ], | ||||||
| @@ -138,6 +172,6 @@ class _InputInvestmentViewState extends State<InputInvestmentView> { | |||||||
|           ), |           ), | ||||||
|         ], |         ], | ||||||
|       ), |       ), | ||||||
|     );; |     ); | ||||||
|   } |   } | ||||||
| } | } | ||||||
|   | |||||||
| @@ -1,3 +1,5 @@ | |||||||
|  | import 'dart:math'; | ||||||
|  |  | ||||||
| import 'package:cims_apps/application/assets/path_assets.dart'; | 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/button/button_view.dart'; | ||||||
| import 'package:cims_apps/application/component/custom_app_bar/custom_app_bar.dart'; | import 'package:cims_apps/application/component/custom_app_bar/custom_app_bar.dart'; | ||||||
| @@ -72,6 +74,8 @@ class _OtherPlanViewState extends State<OtherPlanView> { | |||||||
|           disabled: !(selectedPlan.img != ''), |           disabled: !(selectedPlan.img != ''), | ||||||
|           onPressed: () { |           onPressed: () { | ||||||
|             Navigator.pop(context); |             Navigator.pop(context); | ||||||
|  |             print('haloo'); | ||||||
|  |             print(selectedPlan.name); | ||||||
|             widget.selectedPlan(selectedPlan.name); |             widget.selectedPlan(selectedPlan.name); | ||||||
|           }, |           }, | ||||||
|           heightWrapContent: true, |           heightWrapContent: true, | ||||||
| @@ -91,6 +95,7 @@ class _OtherPlanViewState extends State<OtherPlanView> { | |||||||
|         if(plan.name == 'Create Plan'){ |         if(plan.name == 'Create Plan'){ | ||||||
|           showModalBottomSheet( |           showModalBottomSheet( | ||||||
|             context: context, |             context: context, | ||||||
|  |             isDismissible: false, | ||||||
|             builder: (context) => modalCreatePlan(), |             builder: (context) => modalCreatePlan(), | ||||||
|           ); |           ); | ||||||
|         } |         } | ||||||
| @@ -150,6 +155,9 @@ class _OtherPlanViewState extends State<OtherPlanView> { | |||||||
|               GestureDetector( |               GestureDetector( | ||||||
|                 onTap: () { |                 onTap: () { | ||||||
|                   Navigator.pop(context); |                   Navigator.pop(context); | ||||||
|  |                   setState(() { | ||||||
|  |                     selectedPlan = Plan('', ''); | ||||||
|  |                   }); | ||||||
|                 }, |                 }, | ||||||
|                 child: Icon(Icons.close_rounded), |                 child: Icon(Icons.close_rounded), | ||||||
|               ) |               ) | ||||||
| @@ -161,12 +169,12 @@ class _OtherPlanViewState extends State<OtherPlanView> { | |||||||
|           ), |           ), | ||||||
|           SizedBox(height: 24), |           SizedBox(height: 24), | ||||||
|           ButtonView( |           ButtonView( | ||||||
|             name: 'Select', |             name: 'Next', | ||||||
|             marginVertical: 0, |             marginVertical: 0, | ||||||
|             disabled: !(createController.text != ''), |             disabled: !(createController.text != ''), | ||||||
|             onPressed: () { |             onPressed: () { | ||||||
|               Navigator.of(context)..pop()..pop(); |               Navigator.of(context)..pop()..pop(); | ||||||
|               widget.selectedPlan(selectedPlan.name); |               widget.selectedPlan(createController.text); | ||||||
|             }, |             }, | ||||||
|             heightWrapContent: true, |             heightWrapContent: true, | ||||||
|             width: SizeConfig.width, |             width: SizeConfig.width, | ||||||
|   | |||||||
| @@ -1,4 +1,5 @@ | |||||||
| import 'package:cims_apps/application/component/button/button_view.dart'; | import 'package:cims_apps/application/component/button/button_view.dart'; | ||||||
|  | import 'package:cims_apps/application/component/radio_agreement.dart'; | ||||||
| import 'package:cims_apps/application/theme/color_palette.dart'; | import 'package:cims_apps/application/theme/color_palette.dart'; | ||||||
| import 'package:cims_apps/core/route/route.dart'; | import 'package:cims_apps/core/route/route.dart'; | ||||||
| import 'package:cims_apps/core/utils/number_formatter.dart'; | import 'package:cims_apps/core/utils/number_formatter.dart'; | ||||||
| @@ -6,249 +7,249 @@ import 'package:cims_apps/features/dashboard/dashboard_account/view/product/view | |||||||
| import 'package:cims_apps/features/dashboard/dashboard_account/view/product/view_model/product_view_model.dart'; | import 'package:cims_apps/features/dashboard/dashboard_account/view/product/view_model/product_view_model.dart'; | ||||||
| import 'package:flutter/material.dart'; | import 'package:flutter/material.dart'; | ||||||
|  |  | ||||||
| class TotalPaymentView extends StatefulWidget { | class TotalPaymentView extends StatelessWidget { | ||||||
|   final int totalInvest; |   final int totalInvest; | ||||||
|   final List<Product> listProduct; |   final List<Product> listProduct; | ||||||
|  |   final bool isAgree; | ||||||
|  |   final void Function() onTapAgree; | ||||||
|   const TotalPaymentView({ |   const TotalPaymentView({ | ||||||
|     super.key, |     super.key, | ||||||
|     required this.listProduct, |     required this.listProduct, | ||||||
|     required this.totalInvest, |     required this.totalInvest, | ||||||
|  |     required this.isAgree, | ||||||
|  |     required this.onTapAgree, | ||||||
|   }); |   }); | ||||||
|  |  | ||||||
|   @override |  | ||||||
|   State<TotalPaymentView> createState() => _TotalPaymentViewState(); |  | ||||||
| } |  | ||||||
|  |  | ||||||
| class _TotalPaymentViewState extends State<TotalPaymentView> { |  | ||||||
|   bool isAgreement = false; |  | ||||||
|  |  | ||||||
|   @override |   @override | ||||||
|   Widget build(BuildContext context) { |   Widget build(BuildContext context) { | ||||||
|     return Container( |     return SingleChildScrollView( | ||||||
|       decoration: BoxDecoration( |       child: Container( | ||||||
|           color: Colors.white, |         decoration: BoxDecoration( | ||||||
|           borderRadius: BorderRadius.circular(16) |             color: Colors.white, borderRadius: BorderRadius.circular(16)), | ||||||
|       ), |         child: Column( | ||||||
|       child: Column( |           mainAxisSize: MainAxisSize.min, | ||||||
|         mainAxisSize: MainAxisSize.min, |           children: [ | ||||||
|         children: [ |             Padding( | ||||||
|           Padding( |               padding: const EdgeInsets.all(24.0), | ||||||
|             padding: const EdgeInsets.all(24.0), |  | ||||||
|             child: Row( |  | ||||||
|               mainAxisAlignment: MainAxisAlignment.spaceBetween, |  | ||||||
|               children: [ |  | ||||||
|                 const Text('Your Investment Today', |  | ||||||
|                   style: TextStyle( |  | ||||||
|                       color: ColorPalette.slate800, |  | ||||||
|                       fontWeight: FontWeight.w600, |  | ||||||
|                       fontSize: 16 |  | ||||||
|                   ), |  | ||||||
|                 ), |  | ||||||
|                 GestureDetector( |  | ||||||
|                     onTap: () => Navigator.pop(context), |  | ||||||
|                     child: const Icon(Icons.close_rounded) |  | ||||||
|                 ) |  | ||||||
|               ], |  | ||||||
|             ), |  | ||||||
|           ), |  | ||||||
|           ...widget.listProduct.asMap().entries.map((e) { |  | ||||||
|             return Container( |  | ||||||
|               padding: const EdgeInsets.only(left: 16, right: 24, bottom: 16, top: 16), |  | ||||||
|               decoration: BoxDecoration( |  | ||||||
|                   border: Border( |  | ||||||
|                       left: BorderSide( |  | ||||||
|                         width: 8, |  | ||||||
|                         color: ColorPalette.investTypeColor[e.value.type]! |  | ||||||
|                       ) |  | ||||||
|                   ) |  | ||||||
|               ), |  | ||||||
|               child: Row( |               child: Row( | ||||||
|                 mainAxisAlignment: MainAxisAlignment.spaceBetween, |                 mainAxisAlignment: MainAxisAlignment.spaceBetween, | ||||||
|                 children: [ |                 children: [ | ||||||
|                   Expanded( |                   const Text( | ||||||
|                       flex: 5, |                     'Your Investment Today', | ||||||
|                       child: Text(e.value.name ?? '', |  | ||||||
|                         style: const TextStyle( |  | ||||||
|                             color: ColorPalette.slate400, |  | ||||||
|                             fontWeight: FontWeight.w600, |  | ||||||
|                             fontSize: 16 |  | ||||||
|                         ), |  | ||||||
|                       ) |  | ||||||
|                   ), |  | ||||||
|                   Expanded( |  | ||||||
|                       flex: 7, |  | ||||||
|                       child: Text( |  | ||||||
|                         NumberFormatter.numberCurrency(widget.totalInvest * e.value.totalPercent!, 'Rp ', 'id_ID'), |  | ||||||
|                         textAlign: TextAlign.end, |  | ||||||
|                         style: const TextStyle( |  | ||||||
|                             fontWeight: FontWeight.w700, |  | ||||||
|                             fontSize: 18, |  | ||||||
|                             color: ColorPalette.slate800 |  | ||||||
|                         ), |  | ||||||
|                       ) |  | ||||||
|                   ) |  | ||||||
|                 ], |  | ||||||
|               ), |  | ||||||
|             ); |  | ||||||
|           }).toList(), |  | ||||||
|           const SizedBox(height: 16), |  | ||||||
|           const Padding( |  | ||||||
|             padding: EdgeInsets.symmetric(horizontal: 24), |  | ||||||
|             child: Row( |  | ||||||
|               mainAxisAlignment: MainAxisAlignment.spaceBetween, |  | ||||||
|               children: [ |  | ||||||
|                 Text('Purchase Commission', |  | ||||||
|                   style: TextStyle( |  | ||||||
|                       color: ColorPalette.slate400, |  | ||||||
|                       fontWeight: FontWeight.w600, |  | ||||||
|                       fontSize: 16 |  | ||||||
|                   ), |  | ||||||
|                 ), |  | ||||||
|                 Text('Free', |  | ||||||
|                   style: TextStyle( |  | ||||||
|                       color: ColorPalette.primary, |  | ||||||
|                       fontSize: 18, |  | ||||||
|                       fontWeight: FontWeight.w700 |  | ||||||
|                   ), |  | ||||||
|                 ) |  | ||||||
|               ], |  | ||||||
|             ), |  | ||||||
|           ), |  | ||||||
|           const SizedBox(height: 16,), |  | ||||||
|           Container( |  | ||||||
|             color: ColorPalette.slate200.withOpacity(0.5), |  | ||||||
|             padding: const EdgeInsets.symmetric(horizontal: 24, vertical: 16), |  | ||||||
|             child: Row( |  | ||||||
|               mainAxisAlignment: MainAxisAlignment.spaceBetween, |  | ||||||
|               children: [ |  | ||||||
|                 const Text('Total', |  | ||||||
|                   style: TextStyle( |  | ||||||
|                       color: ColorPalette.slate400, |  | ||||||
|                       fontWeight: FontWeight.w600, |  | ||||||
|                       fontSize: 16 |  | ||||||
|                   ), |  | ||||||
|                 ), |  | ||||||
|                 Text(NumberFormatter.numberCurrency(widget.totalInvest, 'Rp ', 'id_ID'), |  | ||||||
|                   textAlign: TextAlign.end, |  | ||||||
|                   style: const TextStyle( |  | ||||||
|                       fontWeight: FontWeight.w700, |  | ||||||
|                       fontSize: 18, |  | ||||||
|                       color: ColorPalette.slate800 |  | ||||||
|                   ), |  | ||||||
|                 ) |  | ||||||
|               ], |  | ||||||
|             ), |  | ||||||
|           ), |  | ||||||
|           buttonAgreement(), |  | ||||||
|           Container( |  | ||||||
|             padding: const EdgeInsets.symmetric(horizontal: 24, vertical: 16), |  | ||||||
|             child: Row( |  | ||||||
|               mainAxisAlignment: MainAxisAlignment.spaceBetween, |  | ||||||
|               children: [ |  | ||||||
|                 const Text('Total Payment', |  | ||||||
|                   style: TextStyle( |  | ||||||
|                       color: ColorPalette.slate400, |  | ||||||
|                       fontWeight: FontWeight.w600, |  | ||||||
|                       fontSize: 16 |  | ||||||
|                   ), |  | ||||||
|                 ), |  | ||||||
|                 Text(NumberFormatter.numberCurrency(widget.totalInvest, 'Rp ', 'id_ID'), |  | ||||||
|                   textAlign: TextAlign.end, |  | ||||||
|                   style: const TextStyle( |  | ||||||
|                       fontWeight: FontWeight.w700, |  | ||||||
|                       fontSize: 18, |  | ||||||
|                       color: ColorPalette.slate800 |  | ||||||
|                   ), |  | ||||||
|                 ) |  | ||||||
|               ], |  | ||||||
|             ), |  | ||||||
|           ), |  | ||||||
|           ButtonView( |  | ||||||
|             disabled: !isAgreement, |  | ||||||
|             name: 'Subscribe Now', |  | ||||||
|             onPressed: () { |  | ||||||
|               routePush(context, page: PaymentMethodView( |  | ||||||
|                 totalInvest: widget.totalInvest, |  | ||||||
|               )); |  | ||||||
|             }, |  | ||||||
|             disabledBgColor: ColorPalette.slate200.withOpacity(0.5), |  | ||||||
|             textColor: isAgreement ? Colors.white : ColorPalette.slate400, |  | ||||||
|             textWeight: FontWeight.w700, |  | ||||||
|             textSize: 20, |  | ||||||
|             backgroundColor: ColorPalette.primary, |  | ||||||
|           ) |  | ||||||
|         ], |  | ||||||
|       ), |  | ||||||
|     ); |  | ||||||
|   } |  | ||||||
|  |  | ||||||
|   Widget buttonAgreement() { |  | ||||||
|     bool isAgree = isAgreement; |  | ||||||
|     return Padding( |  | ||||||
|       padding: const EdgeInsets.symmetric(horizontal: 24, vertical: 16), |  | ||||||
|       child: Row( |  | ||||||
|         crossAxisAlignment: CrossAxisAlignment.start, |  | ||||||
|         children: [ |  | ||||||
|           GestureDetector( |  | ||||||
|             onTap: () { |  | ||||||
|               setState(() { |  | ||||||
|                 isAgreement = !isAgreement; |  | ||||||
|               }); |  | ||||||
|             }, |  | ||||||
|             child: AnimatedContainer( |  | ||||||
|               margin: const EdgeInsets.only(top: 4), |  | ||||||
|               duration: const Duration(milliseconds: 200), |  | ||||||
|               height: 16, |  | ||||||
|               width: 16, |  | ||||||
|               padding: const EdgeInsets.all(1), |  | ||||||
|               alignment: Alignment.center, |  | ||||||
|               decoration: BoxDecoration( |  | ||||||
|                   shape: BoxShape.circle, |  | ||||||
|                   border: Border.all( |  | ||||||
|                       color: isAgree ? ColorPalette.primary : ColorPalette.slate200 |  | ||||||
|                   ) |  | ||||||
|               ), |  | ||||||
|               child: AnimatedContainer( |  | ||||||
|                 duration: const Duration(milliseconds: 200), |  | ||||||
|                 child: Container( |  | ||||||
|                   decoration: BoxDecoration( |  | ||||||
|                       color: isAgree ? ColorPalette.primary : ColorPalette.white, |  | ||||||
|                       shape: BoxShape.circle |  | ||||||
|                   ), |  | ||||||
|                 ), |  | ||||||
|               ), |  | ||||||
|             ), |  | ||||||
|           ), |  | ||||||
|           const SizedBox(width: 12,), |  | ||||||
|           Expanded( |  | ||||||
|               child: Column( |  | ||||||
|                 crossAxisAlignment: CrossAxisAlignment.start, |  | ||||||
|                 children: [ |  | ||||||
|                   const Text('I agree to buy the mutual fund on this page and have read and agreed to all the contents of the Prospectus and summary information and understand the risks of my investment decision.', |  | ||||||
|                     style: TextStyle( |                     style: TextStyle( | ||||||
|                         fontSize: 16, |                         color: ColorPalette.slate800, | ||||||
|                         fontWeight: FontWeight.w600, |                         fontWeight: FontWeight.w600, | ||||||
|                         color: ColorPalette.slate400 |                         fontSize: 16), | ||||||
|                     ), |  | ||||||
|                   ), |                   ), | ||||||
|                   GestureDetector( |                   GestureDetector( | ||||||
|                       onTap: () { |                       onTap: () => Navigator.pop(context), | ||||||
|  |                       child: const Icon(Icons.close_rounded)) | ||||||
|                       }, |                 ], | ||||||
|                       child: const Text('Read More', |               ), | ||||||
|                         style: TextStyle( |             ), | ||||||
|                             fontSize: 16, |             ...listProduct.asMap().entries.map((e) { | ||||||
|                             fontWeight: FontWeight.w600, |               return Container( | ||||||
|                             decoration: TextDecoration.underline, |                 padding: const EdgeInsets.only( | ||||||
|                             color: ColorPalette.primary |                     left: 16, right: 24, bottom: 16, top: 16), | ||||||
|                         ), |                 decoration: BoxDecoration( | ||||||
|                       ) |                     border: Border( | ||||||
|  |                         left: BorderSide( | ||||||
|  |                             width: 8, | ||||||
|  |                             color: | ||||||
|  |                                 ColorPalette.investTypeColor[e.value.type]!))), | ||||||
|  |                 child: Row( | ||||||
|  |                   mainAxisAlignment: MainAxisAlignment.spaceBetween, | ||||||
|  |                   children: [ | ||||||
|  |                     Expanded( | ||||||
|  |                         flex: 5, | ||||||
|  |                         child: Text( | ||||||
|  |                           e.value.name ?? '', | ||||||
|  |                           style: const TextStyle( | ||||||
|  |                               color: ColorPalette.slate400, | ||||||
|  |                               fontWeight: FontWeight.w600, | ||||||
|  |                               fontSize: 16), | ||||||
|  |                         )), | ||||||
|  |                     Expanded( | ||||||
|  |                         flex: 7, | ||||||
|  |                         child: Text( | ||||||
|  |                           NumberFormatter.numberCurrency( | ||||||
|  |                               totalInvest * e.value.totalPercent!, | ||||||
|  |                               'Rp ', | ||||||
|  |                               'id_ID'), | ||||||
|  |                           textAlign: TextAlign.end, | ||||||
|  |                           style: const TextStyle( | ||||||
|  |                               fontWeight: FontWeight.w700, | ||||||
|  |                               fontSize: 18, | ||||||
|  |                               color: ColorPalette.slate800), | ||||||
|  |                         )) | ||||||
|  |                   ], | ||||||
|  |                 ), | ||||||
|  |               ); | ||||||
|  |             }).toList(), | ||||||
|  |             const SizedBox(height: 16), | ||||||
|  |             const Padding( | ||||||
|  |               padding: EdgeInsets.symmetric(horizontal: 24), | ||||||
|  |               child: Row( | ||||||
|  |                 mainAxisAlignment: MainAxisAlignment.spaceBetween, | ||||||
|  |                 children: [ | ||||||
|  |                   Text( | ||||||
|  |                     'Purchase Commission', | ||||||
|  |                     style: TextStyle( | ||||||
|  |                         color: ColorPalette.slate400, | ||||||
|  |                         fontWeight: FontWeight.w600, | ||||||
|  |                         fontSize: 16), | ||||||
|  |                   ), | ||||||
|  |                   Text( | ||||||
|  |                     'Free', | ||||||
|  |                     style: TextStyle( | ||||||
|  |                         color: ColorPalette.primary, | ||||||
|  |                         fontSize: 18, | ||||||
|  |                         fontWeight: FontWeight.w700), | ||||||
|                   ) |                   ) | ||||||
|                 ], |                 ], | ||||||
|               ) |               ), | ||||||
|           ) |             ), | ||||||
|         ], |             const SizedBox( | ||||||
|  |               height: 16, | ||||||
|  |             ), | ||||||
|  |             Container( | ||||||
|  |               color: ColorPalette.slate200.withOpacity(0.5), | ||||||
|  |               padding: const EdgeInsets.symmetric(horizontal: 24, vertical: 16), | ||||||
|  |               child: Row( | ||||||
|  |                 mainAxisAlignment: MainAxisAlignment.spaceBetween, | ||||||
|  |                 children: [ | ||||||
|  |                   const Text( | ||||||
|  |                     'Total', | ||||||
|  |                     style: TextStyle( | ||||||
|  |                         color: ColorPalette.slate400, | ||||||
|  |                         fontWeight: FontWeight.w600, | ||||||
|  |                         fontSize: 16), | ||||||
|  |                   ), | ||||||
|  |                   Text( | ||||||
|  |                     NumberFormatter.numberCurrency( | ||||||
|  |                         totalInvest, 'Rp ', 'id_ID'), | ||||||
|  |                     textAlign: TextAlign.end, | ||||||
|  |                     style: const TextStyle( | ||||||
|  |                         fontWeight: FontWeight.w700, | ||||||
|  |                         fontSize: 18, | ||||||
|  |                         color: ColorPalette.slate800), | ||||||
|  |                   ) | ||||||
|  |                 ], | ||||||
|  |               ), | ||||||
|  |             ), | ||||||
|  |             RadioAgreement( | ||||||
|  |               isAgree: isAgree, | ||||||
|  |               desc: 'I agree to buy the mutual fund on this page and have read and agreed to all the contents of the Prospectus and summary information and understand the risks of my investment decision.', | ||||||
|  |               onTap: () { | ||||||
|  |                 onTapAgree(); | ||||||
|  |               }, | ||||||
|  |             ), | ||||||
|  |             Container( | ||||||
|  |               padding: const EdgeInsets.symmetric(horizontal: 24, vertical: 16), | ||||||
|  |               child: Row( | ||||||
|  |                 mainAxisAlignment: MainAxisAlignment.spaceBetween, | ||||||
|  |                 children: [ | ||||||
|  |                   const Text( | ||||||
|  |                     'Total Payment', | ||||||
|  |                     style: TextStyle( | ||||||
|  |                         color: ColorPalette.slate400, | ||||||
|  |                         fontWeight: FontWeight.w600, | ||||||
|  |                         fontSize: 16), | ||||||
|  |                   ), | ||||||
|  |                   Text( | ||||||
|  |                     NumberFormatter.numberCurrency( | ||||||
|  |                         totalInvest, 'Rp ', 'id_ID'), | ||||||
|  |                     textAlign: TextAlign.end, | ||||||
|  |                     style: const TextStyle( | ||||||
|  |                         fontWeight: FontWeight.w700, | ||||||
|  |                         fontSize: 18, | ||||||
|  |                         color: ColorPalette.slate800), | ||||||
|  |                   ) | ||||||
|  |                 ], | ||||||
|  |               ), | ||||||
|  |             ), | ||||||
|  |             ButtonView( | ||||||
|  |               disabled: !isAgree, | ||||||
|  |               name: 'Subscribe Now', | ||||||
|  |               onPressed: () { | ||||||
|  |                 routePush(context, | ||||||
|  |                     page: PaymentMethodView( | ||||||
|  |                       totalInvest: totalInvest, | ||||||
|  |                     )); | ||||||
|  |               }, | ||||||
|  |               disabledBgColor: ColorPalette.slate200.withOpacity(0.5), | ||||||
|  |               textColor: isAgree ? Colors.white : ColorPalette.slate400, | ||||||
|  |               textWeight: FontWeight.w700, | ||||||
|  |               textSize: 20, | ||||||
|  |               backgroundColor: ColorPalette.primary, | ||||||
|  |             ) | ||||||
|  |           ], | ||||||
|  |         ), | ||||||
|       ), |       ), | ||||||
|     ); |     ); | ||||||
|   } |   } | ||||||
| } |  | ||||||
|  |   // Widget buttonAgreement() { | ||||||
|  |   //   return Padding( | ||||||
|  |   //     padding: const EdgeInsets.symmetric(horizontal: 24, vertical: 16), | ||||||
|  |   //     child: Row( | ||||||
|  |   //       crossAxisAlignment: CrossAxisAlignment.start, | ||||||
|  |   //       children: [ | ||||||
|  |   //         GestureDetector( | ||||||
|  |   //           onTap: () { | ||||||
|  |   //           }, | ||||||
|  |   //           child: AnimatedContainer( | ||||||
|  |   //             margin: const EdgeInsets.only(top: 4), | ||||||
|  |   //             duration: const Duration(milliseconds: 200), | ||||||
|  |   //             height: 16, | ||||||
|  |   //             width: 16, | ||||||
|  |   //             padding: const EdgeInsets.all(1), | ||||||
|  |   //             alignment: Alignment.center, | ||||||
|  |   //             decoration: BoxDecoration( | ||||||
|  |   //                 shape: BoxShape.circle, | ||||||
|  |   //                 border: Border.all( | ||||||
|  |   //                     color: isAgree | ||||||
|  |   //                         ? ColorPalette.primary | ||||||
|  |   //                         : ColorPalette.slate200)), | ||||||
|  |   //             child: AnimatedContainer( | ||||||
|  |   //               duration: const Duration(milliseconds: 200), | ||||||
|  |   //               child: Container( | ||||||
|  |   //                 decoration: BoxDecoration( | ||||||
|  |   //                     color: | ||||||
|  |   //                         isAgree ? ColorPalette.primary : ColorPalette.white, | ||||||
|  |   //                     shape: BoxShape.circle), | ||||||
|  |   //               ), | ||||||
|  |   //             ), | ||||||
|  |   //           ), | ||||||
|  |   //         ), | ||||||
|  |   //         const SizedBox( | ||||||
|  |   //           width: 12, | ||||||
|  |   //         ), | ||||||
|  |   //         Expanded( | ||||||
|  |   //             child: Column( | ||||||
|  |   //           crossAxisAlignment: CrossAxisAlignment.start, | ||||||
|  |   //           children: [ | ||||||
|  |   //             const Text( | ||||||
|  |   //               'I agree to buy the mutual fund on this page and have read and agreed to all the contents of the Prospectus and summary information and understand the risks of my investment decision.', | ||||||
|  |   //               style: TextStyle( | ||||||
|  |   //                   fontSize: 16, | ||||||
|  |   //                   fontWeight: FontWeight.w600, | ||||||
|  |   //                   color: ColorPalette.slate400), | ||||||
|  |   //             ), | ||||||
|  |   //             GestureDetector( | ||||||
|  |   //                 onTap: () {}, | ||||||
|  |   //                 child: const Text( | ||||||
|  |   //                   'Read More', | ||||||
|  |   //                   style: TextStyle( | ||||||
|  |   //                       fontSize: 16, | ||||||
|  |   //                       fontWeight: FontWeight.w600, | ||||||
|  |   //                       decoration: TextDecoration.underline, | ||||||
|  |   //                       color: ColorPalette.primary), | ||||||
|  |   //                 )) | ||||||
|  |   //           ], | ||||||
|  |   //         )) | ||||||
|  |   //       ], | ||||||
|  |   //     ), | ||||||
|  |   //   ); | ||||||
|  |   // } | ||||||
|  | } | ||||||
|   | |||||||
| @@ -2,6 +2,7 @@ import 'dart:io'; | |||||||
|  |  | ||||||
| import 'package:cims_apps/application/assets/path_assets.dart'; | 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/button/button_view.dart'; | ||||||
|  | import 'package:cims_apps/application/component/custom_app_bar/custom_app_bar.dart'; | ||||||
| import 'package:cims_apps/application/component/image/image_view.dart'; | import 'package:cims_apps/application/component/image/image_view.dart'; | ||||||
| import 'package:cims_apps/application/component/take_picture_screen/take_picture_screen.dart'; | import 'package:cims_apps/application/component/take_picture_screen/take_picture_screen.dart'; | ||||||
| import 'package:cims_apps/application/theme/color_palette.dart'; | import 'package:cims_apps/application/theme/color_palette.dart'; | ||||||
| @@ -12,6 +13,7 @@ import 'package:cims_apps/features/auth/registration/viewmodel/submission_data_v | |||||||
| import 'package:flutter/material.dart'; | import 'package:flutter/material.dart'; | ||||||
| import 'package:provider/provider.dart'; | import 'package:provider/provider.dart'; | ||||||
| import 'package:shared_preferences/shared_preferences.dart'; | import 'package:shared_preferences/shared_preferences.dart'; | ||||||
|  | import 'dart:math' as math; | ||||||
|  |  | ||||||
| class DisplayPictureScreen extends StatefulWidget { | class DisplayPictureScreen extends StatefulWidget { | ||||||
|   final String imagePath, content; |   final String imagePath, content; | ||||||
| @@ -93,10 +95,8 @@ class _DisplayPictureScreenState extends State<DisplayPictureScreen> { | |||||||
|           return Consumer<SubmissionDataViewModel>( |           return Consumer<SubmissionDataViewModel>( | ||||||
|               builder: (context, provider, child) { |               builder: (context, provider, child) { | ||||||
|             return Scaffold( |             return Scaffold( | ||||||
|               appBar: AppBar( |               appBar: CustomAppBar( | ||||||
|                 title: const Text('Preview'), |                   height: SizeConfig.height * .08, title: 'Preview'), | ||||||
|                 automaticallyImplyLeading: false, |  | ||||||
|               ), |  | ||||||
|               body: Container( |               body: Container( | ||||||
|                   padding: const EdgeInsets.symmetric(horizontal: 24.0), |                   padding: const EdgeInsets.symmetric(horizontal: 24.0), | ||||||
|                   child: Column( |                   child: Column( | ||||||
| @@ -106,7 +106,14 @@ class _DisplayPictureScreenState extends State<DisplayPictureScreen> { | |||||||
|                       SizedBox( |                       SizedBox( | ||||||
|                           width: SizeConfig.width, |                           width: SizeConfig.width, | ||||||
|                           height: SizeConfig.height * .4, |                           height: SizeConfig.height * .4, | ||||||
|                           child: Image.file(File(widget.imagePath))), |                           child: Transform( | ||||||
|  |                               alignment: Alignment.center, | ||||||
|  |                               transform: widget.content == 'selfie' | ||||||
|  |                                   ? Matrix4.rotationY(math.pi) | ||||||
|  |                                   : Matrix4.rotationY(0), | ||||||
|  |                               child: Image.file( | ||||||
|  |                                 File(widget.imagePath), | ||||||
|  |                               ))), | ||||||
|                       const Padding( |                       const Padding( | ||||||
|                         padding: EdgeInsets.symmetric(vertical: 16.0), |                         padding: EdgeInsets.symmetric(vertical: 16.0), | ||||||
|                         child: Text( |                         child: Text( | ||||||
|   | |||||||
| @@ -1,5 +1,6 @@ | |||||||
| import 'package:camera/camera.dart'; | import 'package:camera/camera.dart'; | ||||||
| import 'package:cims_apps/application/assets/path_assets.dart'; | import 'package:cims_apps/application/assets/path_assets.dart'; | ||||||
|  | import 'package:cims_apps/application/component/custom_app_bar/custom_app_bar.dart'; | ||||||
| import 'package:cims_apps/application/component/image/image_view.dart'; | import 'package:cims_apps/application/component/image/image_view.dart'; | ||||||
| import 'package:cims_apps/application/component/take_picture_screen/display_picture_screen.dart'; | import 'package:cims_apps/application/component/take_picture_screen/display_picture_screen.dart'; | ||||||
| import 'package:cims_apps/core/route/route.dart'; | import 'package:cims_apps/core/route/route.dart'; | ||||||
| @@ -27,7 +28,6 @@ class TakePictureScreenState extends State<TakePictureScreen> { | |||||||
|   late String _takeContent; |   late String _takeContent; | ||||||
|  |  | ||||||
|   Future<void> changeFlash() async { |   Future<void> changeFlash() async { | ||||||
|     await _controller.setFlashMode(FlashMode.auto); |  | ||||||
|     setState(() { |     setState(() { | ||||||
|       isFlash = !isFlash; |       isFlash = !isFlash; | ||||||
|     }); |     }); | ||||||
| @@ -44,6 +44,7 @@ class TakePictureScreenState extends State<TakePictureScreen> { | |||||||
|     // Next, initialize the controller. This returns a Future. |     // Next, initialize the controller. This returns a Future. | ||||||
|     _initializeControllerFuture = _controller.initialize(); |     _initializeControllerFuture = _controller.initialize(); | ||||||
|     _takeContent = widget.takeContent; |     _takeContent = widget.takeContent; | ||||||
|  |     _controller.setFlashMode(isFlash ? FlashMode.torch : FlashMode.off); | ||||||
|   } |   } | ||||||
|  |  | ||||||
|   @override |   @override | ||||||
| @@ -57,9 +58,10 @@ class TakePictureScreenState extends State<TakePictureScreen> { | |||||||
|   Widget build(BuildContext context) { |   Widget build(BuildContext context) { | ||||||
|     // Fill this out in the next steps. |     // Fill this out in the next steps. | ||||||
|     return Scaffold( |     return Scaffold( | ||||||
|       appBar: AppBar( |       appBar: CustomAppBar( | ||||||
|         title: const Text('Registration'), |         title: 'Registration', | ||||||
|         actions: [ |         height: SizeConfig.height * .08, | ||||||
|  |         trailing: [ | ||||||
|           IconButton( |           IconButton( | ||||||
|               onPressed: () { |               onPressed: () { | ||||||
|                 changeFlash(); |                 changeFlash(); | ||||||
|   | |||||||
| @@ -141,7 +141,7 @@ class TextFormView extends StatelessWidget { | |||||||
|             style: TextStyle( |             style: TextStyle( | ||||||
|               fontWeight: FontWeight.w500, |               fontWeight: FontWeight.w500, | ||||||
|               fontSize: 14, |               fontSize: 14, | ||||||
|               color: fontColorDisabled ?? ColorPalette.slate500, |               color: fontColorDisabled ?? ColorPalette.slate800, | ||||||
|             ), |             ), | ||||||
|             readOnly: readOnly, |             readOnly: readOnly, | ||||||
|             validator: validator, |             validator: validator, | ||||||
| @@ -163,7 +163,7 @@ class TextFormView extends StatelessWidget { | |||||||
|                 hintStyle: hintTextStyle ?? |                 hintStyle: hintTextStyle ?? | ||||||
|                     const TextStyle( |                     const TextStyle( | ||||||
|                       fontSize: 14, |                       fontSize: 14, | ||||||
|                       color: ColorPalette.greyFont, |                       color: ColorPalette.slate400, | ||||||
|                       fontWeight: FontWeight.normal, |                       fontWeight: FontWeight.normal, | ||||||
|                     ), |                     ), | ||||||
|                 isDense: true, |                 isDense: true, | ||||||
| @@ -190,6 +190,18 @@ class TextFormView extends StatelessWidget { | |||||||
|                     color: focusedBorderColor ?? ColorPalette.greyBorder, |                     color: focusedBorderColor ?? ColorPalette.greyBorder, | ||||||
|                   ), |                   ), | ||||||
|                 ), |                 ), | ||||||
|  |                 errorBorder: OutlineInputBorder( | ||||||
|  |                   borderRadius: _borderRadius, | ||||||
|  |                   borderSide: BorderSide( | ||||||
|  |                       color: ColorPalette.red600 | ||||||
|  |                   ) | ||||||
|  |                 ), | ||||||
|  |                 focusedErrorBorder: OutlineInputBorder( | ||||||
|  |                   borderRadius: _borderRadius, | ||||||
|  |                   borderSide: BorderSide( | ||||||
|  |                     color: ColorPalette.red600 | ||||||
|  |                   ) | ||||||
|  |                 ), | ||||||
|                 border: OutlineInputBorder(borderRadius: _borderRadius), |                 border: OutlineInputBorder(borderRadius: _borderRadius), | ||||||
|                 suffixIcon: suffixIcon, |                 suffixIcon: suffixIcon, | ||||||
|                 prefixIcon: prefixIcon, |                 prefixIcon: prefixIcon, | ||||||
|   | |||||||
| @@ -5,17 +5,20 @@ class TextTitle extends StatelessWidget { | |||||||
|   final String title; |   final String title; | ||||||
|   final Color? color; |   final Color? color; | ||||||
|   final double? fontSize; |   final double? fontSize; | ||||||
|  |   final TextAlign? textAlign; | ||||||
|   const TextTitle({ |   const TextTitle({ | ||||||
|     Key? key, |     Key? key, | ||||||
|     required this.title, |     required this.title, | ||||||
|     this.color, |     this.color, | ||||||
|     this.fontSize, |     this.fontSize, | ||||||
|  |     this.textAlign, | ||||||
|   }) : super(key: key); |   }) : super(key: key); | ||||||
|  |  | ||||||
|   @override |   @override | ||||||
|   Widget build(BuildContext context) { |   Widget build(BuildContext context) { | ||||||
|     return Text( |     return Text( | ||||||
|       title, |       title, | ||||||
|  |       textAlign: textAlign, | ||||||
|       style: TextStyle( |       style: TextStyle( | ||||||
|         fontSize: fontSize ?? 20, |         fontSize: fontSize ?? 20, | ||||||
|         fontWeight: FontWeight.w700, |         fontWeight: FontWeight.w700, | ||||||
|   | |||||||
| @@ -75,6 +75,7 @@ class ColorPalette { | |||||||
|   static const Color backgroundBlueLight = Color(0xFFEBF3FD); |   static const Color backgroundBlueLight = Color(0xFFEBF3FD); | ||||||
|   static const Color blue50 = Color(0xFFEFF6FF); |   static const Color blue50 = Color(0xFFEFF6FF); | ||||||
|   static const Color blue200 = Color(0xFFBFDBFE); |   static const Color blue200 = Color(0xFFBFDBFE); | ||||||
|  |   static const Color blue600 = Color(0xFF2563EB); | ||||||
|   static const Color blue900 = Color(0xFF1E3A8A); |   static const Color blue900 = Color(0xFF1E3A8A); | ||||||
|   static const Color slate50 = Color(0xFFF8FAFC); |   static const Color slate50 = Color(0xFFF8FAFC); | ||||||
|   static const Color slate200 = Color(0xFFE2E8F0); |   static const Color slate200 = Color(0xFFE2E8F0); | ||||||
| @@ -90,8 +91,11 @@ class ColorPalette { | |||||||
|   static const Color cyan100 = Color(0xFFCFFAFE); |   static const Color cyan100 = Color(0xFFCFFAFE); | ||||||
|   static const Color cyan500 = Color(0xFF06B6D4); |   static const Color cyan500 = Color(0xFF06B6D4); | ||||||
|   static const Color green100 = Color(0xFFDCFCE7); |   static const Color green100 = Color(0xFFDCFCE7); | ||||||
|  |   static const Color green300 = Color(0xFF86EFAC); | ||||||
|   static const Color green400 = Color(0xFF4ADE80); |   static const Color green400 = Color(0xFF4ADE80); | ||||||
|   static const Color green500 = Color(0xFF16A34A); |   static const Color green500 = Color(0xFF16A34A); | ||||||
|  |   static const Color red600 = Color(0xFFDC2626); | ||||||
|  |   static const Color red50 = Color(0xFFFEF2F2); | ||||||
|  |  | ||||||
|   static const Map<String, Color> investTypeColor = { |   static const Map<String, Color> investTypeColor = { | ||||||
|     'Money Market': purple500, |     'Money Market': purple500, | ||||||
| @@ -106,4 +110,16 @@ class ColorPalette { | |||||||
|     'Sharia': green100, |     'Sharia': green100, | ||||||
|     'Bonds': cyan100 |     'Bonds': cyan100 | ||||||
|   }; |   }; | ||||||
|  |  | ||||||
|  |   static const Map<String, Color> riskColor = { | ||||||
|  |     'Moderate': orange500, | ||||||
|  |     'Conservative': green500, | ||||||
|  |     'Aggressive': cyan500 | ||||||
|  |   }; | ||||||
|  |  | ||||||
|  |   static const Map<String, Color> textRiskColor = { | ||||||
|  |     'Moderate': orange500, | ||||||
|  |     'Conservative': green300, | ||||||
|  |     'Aggressive': cyan500 | ||||||
|  |   }; | ||||||
| } | } | ||||||
|   | |||||||
| @@ -1,3 +1,5 @@ | |||||||
|  | import 'package:intl/intl.dart'; | ||||||
|  |  | ||||||
| class StringUtils { | class StringUtils { | ||||||
|   static bool emailValidation(String email) { |   static bool emailValidation(String email) { | ||||||
|     return RegExp( |     return RegExp( | ||||||
| @@ -13,4 +15,12 @@ class StringUtils { | |||||||
|     return RegExp(r'^(?=.*[a-z])(?=.*[A-Z])(?=.*[0-9])(?=.*?[\W_])(?=.{8,})') |     return RegExp(r'^(?=.*[a-z])(?=.*[A-Z])(?=.*[0-9])(?=.*?[\W_])(?=.{8,})') | ||||||
|         .hasMatch(password); |         .hasMatch(password); | ||||||
|   } |   } | ||||||
|  |  | ||||||
|  |   static String formatTime(DateTime? dateTime) { | ||||||
|  |     if (dateTime != null) { | ||||||
|  |       DateFormat formatter = DateFormat('HH:mm:ss'); | ||||||
|  |       return formatter.format(dateTime); | ||||||
|  |     } | ||||||
|  |     return '--:--:--'; | ||||||
|  |   } | ||||||
| } | } | ||||||
|   | |||||||
| @@ -1,19 +1,12 @@ | |||||||
| import 'package:cims_apps/application/assets/path_assets.dart'; |  | ||||||
| import 'package:cims_apps/application/component/button/back_button_view.dart'; | import 'package:cims_apps/application/component/button/back_button_view.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_form/text_form_view.dart'; |  | ||||||
| import 'package:cims_apps/application/component/text_title/text_title.dart'; |  | ||||||
| import 'package:cims_apps/application/theme/color_palette.dart'; | import 'package:cims_apps/application/theme/color_palette.dart'; | ||||||
| import 'package:cims_apps/core/route/route.dart'; | import 'package:cims_apps/core/route/route.dart'; | ||||||
| import 'package:cims_apps/core/utils/size_config.dart'; | import 'package:cims_apps/core/utils/size_config.dart'; | ||||||
| import 'package:cims_apps/features/auth/login/view/password_view.dart'; | import 'package:cims_apps/features/auth/login/view/password_view.dart'; | ||||||
| import 'package:cims_apps/features/auth/login/view/phone_number_view.dart'; | import 'package:cims_apps/features/auth/login/view/phone_number_view.dart'; | ||||||
| import 'package:cims_apps/features/auth/login/view_model/login_view_model.dart'; | import 'package:cims_apps/features/auth/login/view_model/login_view_model.dart'; | ||||||
| import 'package:cims_apps/features/auth/registration/view/submission_data/risk_profile/risk_profile_view.dart'; |  | ||||||
| import 'package:cims_apps/features/bottom_navigation_view.dart'; | import 'package:cims_apps/features/bottom_navigation_view.dart'; | ||||||
| import 'package:flutter/material.dart'; | import 'package:flutter/material.dart'; | ||||||
| import 'package:flutter/services.dart'; |  | ||||||
| import 'package:provider/provider.dart'; | import 'package:provider/provider.dart'; | ||||||
|  |  | ||||||
| class LoginView extends StatefulWidget { | class LoginView extends StatefulWidget { | ||||||
| @@ -90,7 +83,11 @@ class _LoginViewState extends State<LoginView> { | |||||||
|       currentPage++; |       currentPage++; | ||||||
|       pageController.jumpToPage(1); |       pageController.jumpToPage(1); | ||||||
|     } else { |     } else { | ||||||
|       routePush(context, page: BottomNavigationView()); |       routePush( | ||||||
|  |         context, | ||||||
|  |         page: const BottomNavigationView(), | ||||||
|  |         routeType: RouteType.pushReplace, | ||||||
|  |       ); | ||||||
|     } |     } | ||||||
|   } |   } | ||||||
| } | } | ||||||
|   | |||||||
| @@ -10,70 +10,83 @@ import 'package:provider/provider.dart'; | |||||||
| class PasswordView extends StatelessWidget { | class PasswordView extends StatelessWidget { | ||||||
|   final void Function() nextStep; |   final void Function() nextStep; | ||||||
|   final TextEditingController controller; |   final TextEditingController controller; | ||||||
|   const PasswordView({super.key, required this.nextStep, required this.controller}); |   const PasswordView( | ||||||
|  |       {super.key, required this.nextStep, required this.controller}); | ||||||
|  |  | ||||||
|   @override |   @override | ||||||
|   Widget build(BuildContext context) { |   Widget build(BuildContext context) { | ||||||
|     return Consumer<LoginViewModel>( |     return Consumer<LoginViewModel>(builder: (context, provider, child) { | ||||||
|       builder: (context, provider, child) { |       return Container( | ||||||
|         return Container( |         width: SizeConfig.width, | ||||||
|           width: SizeConfig.width, |         height: SizeConfig.height, | ||||||
|           height: SizeConfig.height, |         padding: const EdgeInsets.all(24), | ||||||
|           padding: const EdgeInsets.all(24), |         child: Form( | ||||||
|           child: Column( |           key: provider.formKey, | ||||||
|             crossAxisAlignment: CrossAxisAlignment.start, |           child: SingleChildScrollView( | ||||||
|             children: [ |             child: Column( | ||||||
|               const TextTitle(title: 'Enter your password', fontSize: 24), |               crossAxisAlignment: CrossAxisAlignment.start, | ||||||
|               SizedBox( |               children: [ | ||||||
|                 height: 24, |                 const TextTitle(title: 'Enter your password', fontSize: 24), | ||||||
|               ), |                 SizedBox( | ||||||
|               TextFormView( |                   height: 24, | ||||||
|                 name: 'Password', |                 ), | ||||||
|                 ctrl: controller, |                 TextFormView( | ||||||
|                 obscureText: !provider.showPassword, |                   name: 'Password', | ||||||
|                 contentPadding: EdgeInsets.all(12), |                   ctrl: controller, | ||||||
|                 suffixIcon: GestureDetector( |                   obscureText: !provider.showPassword, | ||||||
|                   onTap: () { |                   contentPadding: EdgeInsets.all(12), | ||||||
|                     provider.changeShowPassword(); |                   validator: (value) { | ||||||
|  |                     if (value!.isEmpty) { | ||||||
|  |                       return 'Password must filled'; | ||||||
|  |                     } else if (value.length < 8) { | ||||||
|  |                       return 'Minimum password 8 Character'; | ||||||
|  |                     } else { | ||||||
|  |                       return null; | ||||||
|  |                     } | ||||||
|                   }, |                   }, | ||||||
|                   child: Icon( |                   suffixIcon: GestureDetector( | ||||||
|                     provider.showPassword |                     onTap: () { | ||||||
|                         ? Icons.visibility_outlined |                       provider.changeShowPassword(); | ||||||
|                         : Icons.visibility_off_outlined, |                     }, | ||||||
|                     color: ColorPalette.greyDarker, |                     child: Icon( | ||||||
|  |                       provider.showPassword | ||||||
|  |                           ? Icons.visibility_outlined | ||||||
|  |                           : Icons.visibility_off_outlined, | ||||||
|  |                       color: ColorPalette.greyDarker, | ||||||
|  |                     ), | ||||||
|                   ), |                   ), | ||||||
|                 ), |                 ), | ||||||
|               ), |                 TextButton( | ||||||
|               TextButton( |                     style: TextButton.styleFrom(padding: EdgeInsets.all(0)), | ||||||
|                 style: TextButton.styleFrom( |                     onPressed: () {}, | ||||||
|                   padding: EdgeInsets.all(0) |                     child: Text( | ||||||
|  |                       'Forget the password?', | ||||||
|  |                       style: TextStyle( | ||||||
|  |                         color: ColorPalette.primary, | ||||||
|  |                       ), | ||||||
|  |                     )), | ||||||
|  |                 SizedBox( | ||||||
|  |                   height: 16, | ||||||
|                 ), |                 ), | ||||||
|                 onPressed: () { |                 ButtonView( | ||||||
|  |                   name: 'Confirm', | ||||||
|                 }, |                   heightWrapContent: true, | ||||||
|                 child: Text( |                   width: SizeConfig.width, | ||||||
|                   'Forget the password?', |                   textSize: 18, | ||||||
|                   style: TextStyle( |                   marginVertical: 0, | ||||||
|                     color: ColorPalette.primary, |                   contentPadding: | ||||||
|                   ), |                       EdgeInsets.symmetric(horizontal: 16, vertical: 12), | ||||||
|  |                   onPressed: () { | ||||||
|  |                     if (provider.formKey.currentState!.validate()) { | ||||||
|  |                       nextStep(); | ||||||
|  |                     } | ||||||
|  |                   }, | ||||||
|                 ) |                 ) | ||||||
|               ), |               ], | ||||||
|               SizedBox( |             ), | ||||||
|                 height: 16, |  | ||||||
|               ), |  | ||||||
|               ButtonView( |  | ||||||
|                 name: 'Confirm', |  | ||||||
|                 heightWrapContent: true, |  | ||||||
|                 width: SizeConfig.width, |  | ||||||
|                 textSize: 18, |  | ||||||
|                 marginVertical: 0, |  | ||||||
|                 contentPadding: EdgeInsets.symmetric(horizontal: 16, vertical: 12), |  | ||||||
|                 onPressed: nextStep, |  | ||||||
|               ) |  | ||||||
|             ], |  | ||||||
|           ), |           ), | ||||||
|         ); |         ), | ||||||
|       } |       ); | ||||||
|     ); |     }); | ||||||
|   } |   } | ||||||
| } | } | ||||||
|   | |||||||
| @@ -1,118 +1,135 @@ | |||||||
| import 'package:cims_apps/application/assets/path_assets.dart'; | 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/button/button_view.dart'; | ||||||
| import 'package:cims_apps/application/component/image/image_view.dart'; | import 'package:cims_apps/application/component/image/image_view.dart'; | ||||||
| import 'package:cims_apps/application/component/numeric_pad/numeric_pad.dart'; |  | ||||||
| import 'package:cims_apps/application/component/text_form/text_form_view.dart'; | import 'package:cims_apps/application/component/text_form/text_form_view.dart'; | ||||||
| import 'package:cims_apps/application/component/text_title/text_title.dart'; | import 'package:cims_apps/application/component/text_title/text_title.dart'; | ||||||
| import 'package:cims_apps/application/theme/color_palette.dart'; | import 'package:cims_apps/application/theme/color_palette.dart'; | ||||||
| import 'package:cims_apps/core/route/route.dart'; | import 'package:cims_apps/core/route/route.dart'; | ||||||
| import 'package:cims_apps/core/utils/size_config.dart'; | import 'package:cims_apps/core/utils/size_config.dart'; | ||||||
|  | import 'package:cims_apps/features/auth/login/view_model/login_view_model.dart'; | ||||||
| import 'package:cims_apps/features/auth/registration/view/registration_view.dart'; | import 'package:cims_apps/features/auth/registration/view/registration_view.dart'; | ||||||
| import 'package:flutter/material.dart'; | import 'package:flutter/material.dart'; | ||||||
| import 'package:flutter/services.dart'; | import 'package:flutter/services.dart'; | ||||||
|  | import 'package:provider/provider.dart'; | ||||||
|  |  | ||||||
| class PhoneNumberView extends StatelessWidget { | class PhoneNumberView extends StatelessWidget { | ||||||
|   final void Function() nextStep; |   final void Function() nextStep; | ||||||
|   final TextEditingController controller; |   final TextEditingController controller; | ||||||
|   const PhoneNumberView({super.key, required this.nextStep, required this.controller}); |   const PhoneNumberView( | ||||||
|  |       {super.key, required this.nextStep, required this.controller}); | ||||||
|  |  | ||||||
|   @override |   @override | ||||||
|   Widget build(BuildContext context) { |   Widget build(BuildContext context) { | ||||||
|     return Container( |     return ChangeNotifierProvider( | ||||||
|       width: SizeConfig.width, |         create: (context) => LoginViewModel(), | ||||||
|       height: SizeConfig.height, |         builder: (context, child) { | ||||||
|       padding: const EdgeInsets.all(24), |           return Container( | ||||||
|       child: Column( |  | ||||||
|         crossAxisAlignment: CrossAxisAlignment.start, |  | ||||||
|         children: [ |  | ||||||
|           const TextTitle(title: 'Enter your phone number', fontSize: 24), |  | ||||||
|           SizedBox( |  | ||||||
|             height: 24, |  | ||||||
|           ), |  | ||||||
|           TextFormView( |  | ||||||
|             name: 'Phone Number', |  | ||||||
|             keyboardType: TextInputType.number, |  | ||||||
|             ctrl: controller, |  | ||||||
|             inputFormatters: [ |  | ||||||
|               FilteringTextInputFormatter.deny(RegExp(r'^0')) |  | ||||||
|             ], |  | ||||||
|             contentPadding: EdgeInsets.all(1), |  | ||||||
|             prefixIcon: Container( |  | ||||||
|                 width: SizeConfig.width * .23, |  | ||||||
|                 padding: |  | ||||||
|                 const EdgeInsets.symmetric(horizontal: 16.0), |  | ||||||
|                 margin: const EdgeInsets.only(right: 16), |  | ||||||
|                 decoration: const BoxDecoration( |  | ||||||
|                     color: ColorPalette.grey, |  | ||||||
|                     borderRadius: BorderRadius.only( |  | ||||||
|                       topLeft: Radius.circular(8), |  | ||||||
|                       bottomLeft: Radius.circular(8), |  | ||||||
|                     )), |  | ||||||
|                 child: const Row( |  | ||||||
|                   mainAxisAlignment: MainAxisAlignment.spaceBetween, |  | ||||||
|                   children: [ |  | ||||||
|                     ImageView( |  | ||||||
|                       image: PathAssets.iconFlag, |  | ||||||
|                       fit: BoxFit.contain, |  | ||||||
|                       width: 24, |  | ||||||
|                       height: 24, |  | ||||||
|                     ), |  | ||||||
|                     Text( |  | ||||||
|                       '+62', |  | ||||||
|                       style: TextStyle( |  | ||||||
|                         fontWeight: FontWeight.w600, |  | ||||||
|                         color: ColorPalette.slate800, |  | ||||||
|                       ), |  | ||||||
|                     ) |  | ||||||
|                   ], |  | ||||||
|                 )), |  | ||||||
|             validator: (value) { |  | ||||||
|               if (value!.isEmpty) { |  | ||||||
|                 return 'Phone number must be filled'; |  | ||||||
|               } else { |  | ||||||
|                 return null; |  | ||||||
|               } |  | ||||||
|             }, |  | ||||||
|           ), |  | ||||||
|           SizedBox( |  | ||||||
|             height: 32, |  | ||||||
|           ), |  | ||||||
|           ButtonView( |  | ||||||
|             name: 'Next', |  | ||||||
|             heightWrapContent: true, |  | ||||||
|             width: SizeConfig.width, |             width: SizeConfig.width, | ||||||
|             marginVertical: 0, |             height: SizeConfig.height, | ||||||
|             contentPadding: EdgeInsets.symmetric(horizontal: 16, vertical: 12), |             padding: const EdgeInsets.all(24), | ||||||
|             onPressed: nextStep, |             child: | ||||||
|           ), |                 Consumer<LoginViewModel>(builder: (context, provider, child) { | ||||||
|           Row( |               return Form( | ||||||
|             mainAxisAlignment: MainAxisAlignment.center, |                 key: provider.formKey, | ||||||
|             children: [ |                 child: SingleChildScrollView( | ||||||
|               Text( |                   child: Column( | ||||||
|                 "Don't have an account yet?", |                     crossAxisAlignment: CrossAxisAlignment.start, | ||||||
|                 style: TextStyle( |                     children: [ | ||||||
|                   color: ColorPalette.slate500, |                       const TextTitle( | ||||||
|                 ), |                           title: 'Enter your phone number', fontSize: 24), | ||||||
|               ), |                       SizedBox( | ||||||
|               TextButton( |                         height: 24, | ||||||
|                   onPressed: () { |                       ), | ||||||
|                     routePush(context, page: RegistrationView()); |                       TextFormView( | ||||||
|                   }, |                         name: 'Phone Number', | ||||||
|                   style: TextButton.styleFrom( |                         keyboardType: TextInputType.number, | ||||||
|                     padding: EdgeInsets.all(0) |                         ctrl: controller, | ||||||
|  |                         inputFormatters: [ | ||||||
|  |                           FilteringTextInputFormatter.deny(RegExp(r'^0')) | ||||||
|  |                         ], | ||||||
|  |                         contentPadding: EdgeInsets.all(1), | ||||||
|  |                         prefixIcon: Container( | ||||||
|  |                             width: SizeConfig.width * .23, | ||||||
|  |                             padding: | ||||||
|  |                                 const EdgeInsets.symmetric(horizontal: 16.0), | ||||||
|  |                             margin: const EdgeInsets.only(right: 16, left: 1, top: 1, bottom: 1), | ||||||
|  |                             decoration: const BoxDecoration( | ||||||
|  |                                 color: ColorPalette.grey, | ||||||
|  |                                 borderRadius: BorderRadius.only( | ||||||
|  |                                   topLeft: Radius.circular(8), | ||||||
|  |                                   bottomLeft: Radius.circular(8), | ||||||
|  |                                 )), | ||||||
|  |                             child: const Row( | ||||||
|  |                               mainAxisAlignment: MainAxisAlignment.spaceBetween, | ||||||
|  |                               children: [ | ||||||
|  |                                 ImageView( | ||||||
|  |                                   image: PathAssets.iconFlag, | ||||||
|  |                                   fit: BoxFit.contain, | ||||||
|  |                                   width: 24, | ||||||
|  |                                   height: 24, | ||||||
|  |                                 ), | ||||||
|  |                                 Text( | ||||||
|  |                                   '+62', | ||||||
|  |                                   style: TextStyle( | ||||||
|  |                                     fontWeight: FontWeight.w600, | ||||||
|  |                                     color: ColorPalette.slate800, | ||||||
|  |                                   ), | ||||||
|  |                                 ) | ||||||
|  |                               ], | ||||||
|  |                             )), | ||||||
|  |                         validator: (value) { | ||||||
|  |                           if (value!.isEmpty) { | ||||||
|  |                             return 'Phone number must be filled'; | ||||||
|  |                           } else { | ||||||
|  |                             return null; | ||||||
|  |                           } | ||||||
|  |                         }, | ||||||
|  |                       ), | ||||||
|  |                       SizedBox( | ||||||
|  |                         height: 32, | ||||||
|  |                       ), | ||||||
|  |                       ButtonView( | ||||||
|  |                         name: 'Next', | ||||||
|  |                         heightWrapContent: true, | ||||||
|  |                         width: SizeConfig.width, | ||||||
|  |                         marginVertical: 0, | ||||||
|  |                         contentPadding: const EdgeInsets.symmetric( | ||||||
|  |                             horizontal: 16, vertical: 12), | ||||||
|  |                         onPressed: () { | ||||||
|  |                           if (provider.formKey.currentState!.validate()) { | ||||||
|  |                             nextStep(); | ||||||
|  |                           } | ||||||
|  |                         }, | ||||||
|  |                       ), | ||||||
|  |                       Row( | ||||||
|  |                         mainAxisAlignment: MainAxisAlignment.center, | ||||||
|  |                         children: [ | ||||||
|  |                           Text( | ||||||
|  |                             "Don't have an account yet?", | ||||||
|  |                             style: TextStyle( | ||||||
|  |                               color: ColorPalette.slate500, | ||||||
|  |                             ), | ||||||
|  |                           ), | ||||||
|  |                           TextButton( | ||||||
|  |                               onPressed: () { | ||||||
|  |                                 routePush(context, page: RegistrationView()); | ||||||
|  |                               }, | ||||||
|  |                               style: TextButton.styleFrom( | ||||||
|  |                                   padding: EdgeInsets.all(0)), | ||||||
|  |                               child: Text( | ||||||
|  |                                 'Sign Up', | ||||||
|  |                                 style: TextStyle( | ||||||
|  |                                     fontWeight: FontWeight.w600, | ||||||
|  |                                     color: ColorPalette.primary), | ||||||
|  |                               )) | ||||||
|  |                         ], | ||||||
|  |                       ), | ||||||
|  |                     ], | ||||||
|                   ), |                   ), | ||||||
|                   child: Text( |                 ), | ||||||
|                     'Sign Up', |               ); | ||||||
|                     style: TextStyle( |             }), | ||||||
|                         fontWeight: FontWeight.w600, |           ); | ||||||
|                         color: ColorPalette.primary |         }); | ||||||
|                     ), |  | ||||||
|                   ) |  | ||||||
|               ) |  | ||||||
|             ], |  | ||||||
|           ), |  | ||||||
|         ], |  | ||||||
|       ), |  | ||||||
|     ); |  | ||||||
|   } |   } | ||||||
| } | } | ||||||
|   | |||||||
| @@ -1,10 +1,11 @@ | |||||||
| import 'package:flutter/foundation.dart'; | import 'package:flutter/material.dart'; | ||||||
|  |  | ||||||
| class LoginViewModel extends ChangeNotifier { | class LoginViewModel extends ChangeNotifier { | ||||||
|   bool showPassword = false; |   bool showPassword = false; | ||||||
|  |   var formKey = GlobalKey<FormState>(); | ||||||
|  |  | ||||||
|   void changeShowPassword() { |   void changeShowPassword() { | ||||||
|     showPassword = !showPassword; |     showPassword = !showPassword; | ||||||
|     notifyListeners(); |     notifyListeners(); | ||||||
|   } |   } | ||||||
| } | } | ||||||
|   | |||||||
| @@ -6,7 +6,7 @@ import 'package:cims_apps/application/theme/color_palette.dart'; | |||||||
| import 'package:cims_apps/core/route/route.dart'; | import 'package:cims_apps/core/route/route.dart'; | ||||||
| import 'package:cims_apps/core/utils/size_config.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/view/submission_data/submission_parent.dart'; | ||||||
| import 'package:cims_apps/features/dashboard/dashboard_public/view/dashboard_public_view.dart'; | import 'package:cims_apps/features/bottom_navigation_view.dart'; | ||||||
| import 'package:flutter/material.dart'; | import 'package:flutter/material.dart'; | ||||||
|  |  | ||||||
| class InitialRegistrationStep extends StatelessWidget { | class InitialRegistrationStep extends StatelessWidget { | ||||||
| @@ -203,7 +203,7 @@ class InitialRegistrationStep extends StatelessWidget { | |||||||
|                   isOutlined: true, |                   isOutlined: true, | ||||||
|                   onPressed: () { |                   onPressed: () { | ||||||
|                     routePush(context, |                     routePush(context, | ||||||
|                         page: const DashboardPublicView(), |                         page: const BottomNavigationView(), | ||||||
|                         routeType: RouteType.pushReplace); |                         routeType: RouteType.pushReplace); | ||||||
|                   }, |                   }, | ||||||
|                 ), |                 ), | ||||||
|   | |||||||
| @@ -45,7 +45,7 @@ class RegistrationPasswordView extends StatelessWidget { | |||||||
|                         validator: (value) { |                         validator: (value) { | ||||||
|                           if (value!.isEmpty) { |                           if (value!.isEmpty) { | ||||||
|                             return 'Password must filled'; |                             return 'Password must filled'; | ||||||
|                           } else if (value.length <= 8) { |                           } else if (value.length < 8) { | ||||||
|                             return 'Minimum password 8 Character'; |                             return 'Minimum password 8 Character'; | ||||||
|                           } else { |                           } else { | ||||||
|                             return null; |                             return null; | ||||||
|   | |||||||
| @@ -31,10 +31,11 @@ class RegistrationView extends StatelessWidget { | |||||||
|           ), |           ), | ||||||
|         ), |         ), | ||||||
|         builder: (BuildContext context) { |         builder: (BuildContext context) { | ||||||
|  |           var flutterView = View.of(context); | ||||||
|           return Padding( |           return Padding( | ||||||
|             padding: EdgeInsets.only( |             padding: EdgeInsets.only( | ||||||
|               top: MediaQueryData.fromView( |               top: MediaQueryData.fromView( | ||||||
|                 WidgetsBinding.instance.window, |                 flutterView, | ||||||
|               ).padding.top, |               ).padding.top, | ||||||
|             ), |             ), | ||||||
|             child: const OtpView( |             child: const OtpView( | ||||||
|   | |||||||
| @@ -6,107 +6,120 @@ import 'package:cims_apps/application/theme/color_palette.dart'; | |||||||
| import 'package:cims_apps/core/route/route.dart'; | import 'package:cims_apps/core/route/route.dart'; | ||||||
| import 'package:cims_apps/core/utils/size_config.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/view/submission_data/submission_parent.dart'; | ||||||
|  | import 'package:cims_apps/features/auth/registration/viewmodel/submission_data_viewmodel.dart'; | ||||||
| import 'package:flutter/material.dart'; | import 'package:flutter/material.dart'; | ||||||
|  | import 'package:provider/provider.dart'; | ||||||
|  |  | ||||||
|  | class ModelDataBank { | ||||||
|  |   final String? title, subtitle; | ||||||
|  |   ModelDataBank(this.title, this.subtitle); | ||||||
|  | } | ||||||
|  |  | ||||||
| class ConfirmBankAccount extends StatelessWidget { | class ConfirmBankAccount extends StatelessWidget { | ||||||
|   const ConfirmBankAccount({Key? key}) : super(key: key); |   const ConfirmBankAccount({Key? key}) : super(key: key); | ||||||
|  |  | ||||||
|   @override |   @override | ||||||
|   Widget build(BuildContext context) { |   Widget build(BuildContext context) { | ||||||
|     List listData = [ |     final listDataBank = | ||||||
|       {'title': 'Bank Name', 'subtitle': 'Bank Mandiri'}, |         ModalRoute.of(context)!.settings.arguments as List<ModelDataBank>; | ||||||
|       {'title': 'Account Number', 'subtitle': '123002212084'}, |  | ||||||
|       {'title': 'Account Owner Name', 'subtitle': 'Muhamad Rosyidin'}, |     return ChangeNotifierProvider( | ||||||
|       {'title': 'Name on ID card', 'subtitle': 'Muhamad Rosyidin'}, |         create: (context) => SubmissionDataViewModel(), | ||||||
|     ]; |         builder: (context, child) { | ||||||
|     return Scaffold( |           return Scaffold( | ||||||
|       appBar: AppBar( |             appBar: AppBar( | ||||||
|         toolbarHeight: 70, |               toolbarHeight: 70, | ||||||
|         backgroundColor: Colors.white, |               backgroundColor: Colors.white, | ||||||
|         surfaceTintColor: Colors.white, |               surfaceTintColor: Colors.white, | ||||||
|         automaticallyImplyLeading: false, |               automaticallyImplyLeading: false, | ||||||
|         title: Row( |               title: Row( | ||||||
|           mainAxisAlignment: MainAxisAlignment.spaceBetween, |                 mainAxisAlignment: MainAxisAlignment.spaceBetween, | ||||||
|           children: [ |                 children: [ | ||||||
|             const BackButtonView(), |                   const BackButtonView(), | ||||||
|             const Text('Registration'), |                   const Text('Registration'), | ||||||
|             SizedBox( |                   SizedBox( | ||||||
|               width: SizeConfig.width * 0.1, |                     width: SizeConfig.width * 0.1, | ||||||
|             ) |                   ) | ||||||
|           ], |                 ], | ||||||
|         ), |               ), | ||||||
|         shape: const RoundedRectangleBorder( |               shape: const RoundedRectangleBorder( | ||||||
|             side: BorderSide(color: ColorPalette.slate200)), |                   side: BorderSide(color: ColorPalette.slate200)), | ||||||
|       ), |             ), | ||||||
|       body: SingleChildScrollView( |             body: SingleChildScrollView( | ||||||
|         padding: const EdgeInsets.all(16.0), |               padding: const EdgeInsets.all(16.0), | ||||||
|         child: SizedBox( |               child: SizedBox( | ||||||
|           height: SizeConfig.height * .85, |                 height: SizeConfig.height * .85, | ||||||
|           child: Column( |                 child: Consumer<SubmissionDataViewModel>( | ||||||
|             mainAxisAlignment: MainAxisAlignment.spaceBetween, |                     builder: (context, provider, child) { | ||||||
|             crossAxisAlignment: CrossAxisAlignment.start, |                   return Column( | ||||||
|             children: [ |                     mainAxisAlignment: MainAxisAlignment.spaceBetween, | ||||||
|               const TextCaption(title: 'Bank account confirmation'), |                     crossAxisAlignment: CrossAxisAlignment.start, | ||||||
|               SizedBox( |                     children: [ | ||||||
|                 height: SizeConfig.height * .6, |                       const TextCaption(title: 'Bank account confirmation'), | ||||||
|                 child: Column( |                       SizedBox( | ||||||
|                   mainAxisAlignment: MainAxisAlignment.start, |                         height: SizeConfig.height * .6, | ||||||
|                   crossAxisAlignment: CrossAxisAlignment.start, |  | ||||||
|                   children: [ |  | ||||||
|                     ...listData.map((e) { |  | ||||||
|                       return Padding( |  | ||||||
|                         padding: const EdgeInsets.only(bottom: 16.0), |  | ||||||
|                         child: Column( |                         child: Column( | ||||||
|                           mainAxisAlignment: MainAxisAlignment.start, |                           mainAxisAlignment: MainAxisAlignment.start, | ||||||
|                           crossAxisAlignment: CrossAxisAlignment.start, |                           crossAxisAlignment: CrossAxisAlignment.start, | ||||||
|                           children: [ |                           children: [ | ||||||
|                             Text( |                             ...listDataBank.map((e) { | ||||||
|                               e['title'], |                               return Padding( | ||||||
|                               style: const TextStyle( |                                 padding: const EdgeInsets.only(bottom: 16.0), | ||||||
|                                   color: ColorPalette.slate400, fontSize: 16), |                                 child: Column( | ||||||
|                             ), |                                   mainAxisAlignment: MainAxisAlignment.start, | ||||||
|                             Text( |                                   crossAxisAlignment: CrossAxisAlignment.start, | ||||||
|                               e['subtitle'], |                                   children: [ | ||||||
|                               style: const TextStyle( |                                     Text( | ||||||
|                                   fontSize: 16, |                                       e.title!, | ||||||
|                                   color: ColorPalette.slate800, |                                       style: const TextStyle( | ||||||
|                                   fontWeight: FontWeight.w600), |                                           color: ColorPalette.slate400, | ||||||
|  |                                           fontSize: 16), | ||||||
|  |                                     ), | ||||||
|  |                                     Text( | ||||||
|  |                                       e.subtitle!, | ||||||
|  |                                       style: const TextStyle( | ||||||
|  |                                           fontSize: 16, | ||||||
|  |                                           color: ColorPalette.slate800, | ||||||
|  |                                           fontWeight: FontWeight.w600), | ||||||
|  |                                     ), | ||||||
|  |                                   ], | ||||||
|  |                                 ), | ||||||
|  |                               ); | ||||||
|  |                             }).toList(), | ||||||
|  |                             const ListTileView( | ||||||
|  |                               title: | ||||||
|  |                                   'Make sure your data is correct as it will affect the disbursement process', | ||||||
|                             ), |                             ), | ||||||
|                           ], |                           ], | ||||||
|                         ), |                         ), | ||||||
|                       ); |                       ), | ||||||
|                     }).toList(), |                       Row( | ||||||
|                     const ListTileView( |                         mainAxisAlignment: MainAxisAlignment.spaceBetween, | ||||||
|                       title: |                         children: [ | ||||||
|                           'Make sure your data is correct as it will affect the disbursement process', |                           ButtonView( | ||||||
|                     ), |                             name: 'Recheck', | ||||||
|                   ], |                             isOutlined: true, | ||||||
|                 ), |                             width: SizeConfig.width * .42, | ||||||
|  |                             onPressed: () { | ||||||
|  |                               Navigator.pop(context); | ||||||
|  |                             }, | ||||||
|  |                           ), | ||||||
|  |                           ButtonView( | ||||||
|  |                             name: 'Confirm', | ||||||
|  |                             width: SizeConfig.width * .42, | ||||||
|  |                             onPressed: () { | ||||||
|  |                               routePush(context, | ||||||
|  |                                   page: const SubmissionParent()); | ||||||
|  |                             }, | ||||||
|  |                           ), | ||||||
|  |                         ], | ||||||
|  |                       ) | ||||||
|  |                     ], | ||||||
|  |                   ); | ||||||
|  |                 }), | ||||||
|               ), |               ), | ||||||
|               Row( |             ), | ||||||
|                 mainAxisAlignment: MainAxisAlignment.spaceBetween, |           ); | ||||||
|                 children: [ |         }); | ||||||
|                   ButtonView( |  | ||||||
|                     name: 'Recheck', |  | ||||||
|                     isOutlined: true, |  | ||||||
|                     width: SizeConfig.width * .42, |  | ||||||
|                     onPressed: () { |  | ||||||
|                       Navigator.pop(context); |  | ||||||
|                     }, |  | ||||||
|                   ), |  | ||||||
|                   ButtonView( |  | ||||||
|                     name: 'Confirm', |  | ||||||
|                     width: SizeConfig.width * .42, |  | ||||||
|                     onPressed: () { |  | ||||||
|                       routePush(context, page: const SubmissionParent()); |  | ||||||
|                     }, |  | ||||||
|                   ), |  | ||||||
|                 ], |  | ||||||
|               ) |  | ||||||
|             ], |  | ||||||
|           ), |  | ||||||
|         ), |  | ||||||
|       ), |  | ||||||
|     ); |  | ||||||
|   } |   } | ||||||
| } | } | ||||||
|   | |||||||
| @@ -0,0 +1,108 @@ | |||||||
|  | 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/custom_app_bar/custom_app_bar.dart'; | ||||||
|  | import 'package:cims_apps/application/component/image/image_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:cims_apps/features/auth/registration/viewmodel/submission_data_viewmodel.dart'; | ||||||
|  | import 'package:flutter/material.dart'; | ||||||
|  | import 'package:provider/provider.dart'; | ||||||
|  |  | ||||||
|  | class ListBankView extends StatelessWidget { | ||||||
|  |   final ValueChanged<String> onSelect; | ||||||
|  |   const ListBankView({Key? key, required this.onSelect}) : super(key: key); | ||||||
|  |  | ||||||
|  |   @override | ||||||
|  |   Widget build(BuildContext context) { | ||||||
|  |     var textTheme = Theme.of(context).textTheme; | ||||||
|  |  | ||||||
|  |     return ChangeNotifierProvider( | ||||||
|  |         create: (context) => SubmissionDataViewModel(), | ||||||
|  |         builder: (context, child) { | ||||||
|  |           return Scaffold( | ||||||
|  |             appBar: CustomAppBar( | ||||||
|  |                 height: SizeConfig.height * .1, title: 'Select Bank'), | ||||||
|  |             body: Container( | ||||||
|  |               padding: const EdgeInsets.symmetric(horizontal: 16.0), | ||||||
|  |               child: Consumer<SubmissionDataViewModel>( | ||||||
|  |                   builder: (context, provider, child) { | ||||||
|  |                 return Column( | ||||||
|  |                   children: [ | ||||||
|  |                     Row( | ||||||
|  |                       mainAxisAlignment: MainAxisAlignment.spaceBetween, | ||||||
|  |                       children: [ | ||||||
|  |                         ImageView( | ||||||
|  |                           image: PathAssets.imgGuideBank, | ||||||
|  |                           width: SizeConfig.width * .35, | ||||||
|  |                         ), | ||||||
|  |                         Expanded( | ||||||
|  |                           child: Text( | ||||||
|  |                             'Make sure the bank you choose is a bank account in your own name ', | ||||||
|  |                             style: textTheme.bodyLarge, | ||||||
|  |                           ), | ||||||
|  |                         ) | ||||||
|  |                       ], | ||||||
|  |                     ), | ||||||
|  |                     TextFormView( | ||||||
|  |                       name: '', | ||||||
|  |                       hintText: 'Search bank', | ||||||
|  |                       ctrl: provider.ctrlBankNameSearch, | ||||||
|  |                       contentPadding: const EdgeInsets.symmetric(vertical: 0), | ||||||
|  |                       prefixIcon: const Icon( | ||||||
|  |                         Icons.search, | ||||||
|  |                         color: ColorPalette.slate500, | ||||||
|  |                       ), | ||||||
|  |                     ), | ||||||
|  |                     Expanded( | ||||||
|  |                       child: SingleChildScrollView( | ||||||
|  |                         child: Column( | ||||||
|  |                           children: provider.listBank.asMap().entries.map((e) { | ||||||
|  |                             bool selectedBank = | ||||||
|  |                                 e.key.toString() == provider.idx; | ||||||
|  |                             return Card( | ||||||
|  |                               elevation: 0, | ||||||
|  |                               color: selectedBank | ||||||
|  |                                   ? ColorPalette.blue50 | ||||||
|  |                                   : Colors.white, | ||||||
|  |                               shape: const RoundedRectangleBorder( | ||||||
|  |                                 borderRadius: | ||||||
|  |                                     BorderRadius.all(Radius.circular(12)), | ||||||
|  |                               ), | ||||||
|  |                               child: ListTile( | ||||||
|  |                                 title: Text( | ||||||
|  |                                   e.value.text, | ||||||
|  |                                   style: TextStyle( | ||||||
|  |                                     fontSize: 16, | ||||||
|  |                                     fontWeight: FontWeight.w600, | ||||||
|  |                                     color: selectedBank | ||||||
|  |                                         ? ColorPalette.primary | ||||||
|  |                                         : ColorPalette.slate500, | ||||||
|  |                                   ), | ||||||
|  |                                 ), | ||||||
|  |                                 onTap: () { | ||||||
|  |                                   provider.changeBank(e.key.toString()); | ||||||
|  |                                   provider.selectBank(e.value.text); | ||||||
|  |                                 }, | ||||||
|  |                               ), | ||||||
|  |                             ); | ||||||
|  |                           }).toList(), | ||||||
|  |                         ), | ||||||
|  |                       ), | ||||||
|  |                     ), | ||||||
|  |                     ButtonView( | ||||||
|  |                       name: 'Select', | ||||||
|  |                       marginVertical: 8.0, | ||||||
|  |                       onPressed: () { | ||||||
|  |                         onSelect(provider.valueBank); | ||||||
|  |                         Navigator.pop(context); | ||||||
|  |                       }, | ||||||
|  |                     ), | ||||||
|  |                   ], | ||||||
|  |                 ); | ||||||
|  |               }), | ||||||
|  |             ), | ||||||
|  |           ); | ||||||
|  |         }); | ||||||
|  |   } | ||||||
|  | } | ||||||
| @@ -1,13 +1,13 @@ | |||||||
| import 'package:cims_apps/application/assets/path_assets.dart'; | 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/button/button_view.dart'; | ||||||
| import 'package:cims_apps/application/component/image/image_view.dart'; | import 'package:cims_apps/application/component/image/image_view.dart'; | ||||||
| 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/component/text_caption/text_caption.dart'; | ||||||
| import 'package:cims_apps/application/component/text_form/text_form_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/application/theme/color_palette.dart'; | ||||||
| import 'package:cims_apps/core/route/route.dart'; | import 'package:cims_apps/core/route/route.dart'; | ||||||
| import 'package:cims_apps/core/utils/size_config.dart'; | import 'package:cims_apps/core/utils/size_config.dart'; | ||||||
| import 'package:cims_apps/features/auth/registration/view/submission_data/data_bank/guide_screen.dart'; | import 'package:cims_apps/features/auth/registration/view/submission_data/data_bank/guide_screen.dart'; | ||||||
|  | import 'package:cims_apps/features/auth/registration/view/submission_data/data_bank/list_bank_view.dart'; | ||||||
| import 'package:cims_apps/features/auth/registration/viewmodel/submission_data_viewmodel.dart'; | import 'package:cims_apps/features/auth/registration/viewmodel/submission_data_viewmodel.dart'; | ||||||
| import 'package:flutter/material.dart'; | import 'package:flutter/material.dart'; | ||||||
| import 'package:provider/provider.dart'; | import 'package:provider/provider.dart'; | ||||||
| @@ -19,6 +19,40 @@ class SubmitBankAccount extends StatelessWidget { | |||||||
|  |  | ||||||
|   @override |   @override | ||||||
|   Widget build(BuildContext context) { |   Widget build(BuildContext context) { | ||||||
|  |     showSearchBank(TextEditingController valueCtrl) { | ||||||
|  |       showModalBottomSheet( | ||||||
|  |         context: context, | ||||||
|  |         isScrollControlled: true, | ||||||
|  |         enableDrag: false, | ||||||
|  |         shape: const RoundedRectangleBorder( | ||||||
|  |           borderRadius: BorderRadius.vertical( | ||||||
|  |             top: Radius.zero, | ||||||
|  |           ), | ||||||
|  |         ), | ||||||
|  |         builder: (BuildContext context) { | ||||||
|  |           return StatefulBuilder( | ||||||
|  |             builder: (context, setState) { | ||||||
|  |               var flutterView = View.of(context); | ||||||
|  |               return Padding( | ||||||
|  |                 padding: EdgeInsets.only( | ||||||
|  |                   top: MediaQueryData.fromView( | ||||||
|  |                     flutterView, | ||||||
|  |                   ).padding.top, | ||||||
|  |                 ), | ||||||
|  |                 child: ListBankView( | ||||||
|  |                   onSelect: (value) { | ||||||
|  |                     setState(() { | ||||||
|  |                       valueCtrl.text = value; | ||||||
|  |                     }); | ||||||
|  |                   }, | ||||||
|  |                 ), | ||||||
|  |               ); | ||||||
|  |             }, | ||||||
|  |           ); | ||||||
|  |         }, | ||||||
|  |       ); | ||||||
|  |     } | ||||||
|  |  | ||||||
|     return MultiProvider( |     return MultiProvider( | ||||||
|         providers: [ |         providers: [ | ||||||
|           ChangeNotifierProvider( |           ChangeNotifierProvider( | ||||||
| @@ -29,52 +63,99 @@ class SubmitBankAccount extends StatelessWidget { | |||||||
|           return SizedBox( |           return SizedBox( | ||||||
|             child: Consumer<SubmissionDataViewModel>( |             child: Consumer<SubmissionDataViewModel>( | ||||||
|                 builder: (context, provider, child) { |                 builder: (context, provider, child) { | ||||||
|               return Column( |               return SizedBox( | ||||||
|                 crossAxisAlignment: CrossAxisAlignment.start, |                 height: SizeConfig.height * .8, | ||||||
|                 children: [ |                 child: Form( | ||||||
|                   const TextCaption(title: 'Input your bank account data'), |                   key: provider.formKeySubmitDataBank, | ||||||
|                   SelectFormView( |                   child: Column( | ||||||
|                     name: 'Bank Name', |                     crossAxisAlignment: CrossAxisAlignment.start, | ||||||
|                     hintText: 'Select Bank', |                     mainAxisAlignment: MainAxisAlignment.spaceBetween, | ||||||
|                     listItem: provider.listBank, |                     children: [ | ||||||
|                     ctrl: provider.ctrlBankName, |                       const TextCaption(title: 'Input your bank account data'), | ||||||
|                     onSelect: (value) {}, |                       TextFormView( | ||||||
|                   ), |                         name: 'Bank Name', | ||||||
|                   TextFormView( |                         hintText: 'Select bank', | ||||||
|                     name: 'Account Number', |                         readOnly: true, | ||||||
|                     hintText: 'Input Account Number', |                         ctrl: provider.ctrlBankName, | ||||||
|                     trailingTitleWidget: SizedBox( |  | ||||||
|                       width: 24, |  | ||||||
|                       child: GestureDetector( |  | ||||||
|                         onTap: () { |                         onTap: () { | ||||||
|                           routePush(context, page: const GuideScreen()); |                           showSearchBank(provider.ctrlBankName); | ||||||
|  |                         }, | ||||||
|  |                         suffixIcon: const Icon( | ||||||
|  |                           Icons.keyboard_arrow_down_outlined, | ||||||
|  |                         ), | ||||||
|  |                         validator: (value) { | ||||||
|  |                           if (value!.isEmpty) { | ||||||
|  |                             return 'Field must be filled'; | ||||||
|  |                           } | ||||||
|  |                           return null; | ||||||
|                         }, |                         }, | ||||||
|                         child: const ImageView(image: PathAssets.iconQuestion), |  | ||||||
|                       ), |                       ), | ||||||
|                     ), |                       TextFormView( | ||||||
|  |                         name: 'Account Number', | ||||||
|  |                         hintText: 'Input Account Number', | ||||||
|  |                         ctrl: provider.ctrlNoAccountBank, | ||||||
|  |                         keyboardType: TextInputType.number, | ||||||
|  |                         validator: (value) { | ||||||
|  |                           if (value!.isEmpty) { | ||||||
|  |                             return 'Field must be filled'; | ||||||
|  |                           } | ||||||
|  |                           return null; | ||||||
|  |                         }, | ||||||
|  |                         trailingTitleWidget: SizedBox( | ||||||
|  |                           width: 24, | ||||||
|  |                           child: GestureDetector( | ||||||
|  |                             onTap: () { | ||||||
|  |                               routePush(context, page: const GuideScreen()); | ||||||
|  |                             }, | ||||||
|  |                             child: | ||||||
|  |                                 const ImageView(image: PathAssets.iconQuestion), | ||||||
|  |                           ), | ||||||
|  |                         ), | ||||||
|  |                       ), | ||||||
|  |                       TextFormView( | ||||||
|  |                         name: 'Account Owner Name', | ||||||
|  |                         hintText: 'Input Account Name', | ||||||
|  |                         ctrl: provider.ctrlNameAccountBank, | ||||||
|  |                         validator: (value) { | ||||||
|  |                           if (value!.isEmpty) { | ||||||
|  |                             return 'Field must be filled'; | ||||||
|  |                           } | ||||||
|  |                           return null; | ||||||
|  |                         }, | ||||||
|  |                       ), | ||||||
|  |                       const Text( | ||||||
|  |                         "Make sure the account you use is in your name, not someone else's", | ||||||
|  |                         style: TextStyle( | ||||||
|  |                           color: ColorPalette.slate400, | ||||||
|  |                         ), | ||||||
|  |                       ), | ||||||
|  |                       SizedBox(height: SizeConfig.height * .08), | ||||||
|  |                       ButtonView( | ||||||
|  |                         name: 'Next', | ||||||
|  |                         onPressed: () { | ||||||
|  |                           if (provider.formKeySubmitDataBank.currentState! | ||||||
|  |                               .validate()) { | ||||||
|  |                             provider | ||||||
|  |                                 .submitDataBank( | ||||||
|  |                               bankName: provider.ctrlBankName.text, | ||||||
|  |                               accountNumber: provider.ctrlNoAccountBank.text, | ||||||
|  |                               accountName: provider.ctrlNameAccountBank.text, | ||||||
|  |                             ) | ||||||
|  |                                 .then((values) { | ||||||
|  |                               provider.next(context).then((value) { | ||||||
|  |                                 if (value) { | ||||||
|  |                                   routePush(context, | ||||||
|  |                                       page: const ConfirmBankAccount(), | ||||||
|  |                                       arguments: values); | ||||||
|  |                                 } | ||||||
|  |                               }); | ||||||
|  |                             }); | ||||||
|  |                           } | ||||||
|  |                         }, | ||||||
|  |                       ) | ||||||
|  |                     ], | ||||||
|                   ), |                   ), | ||||||
|                   TextFormView( |                 ), | ||||||
|                     name: 'Account Owner Name', |  | ||||||
|                     hintText: 'Input Account Name', |  | ||||||
|                   ), |  | ||||||
|                   const Text( |  | ||||||
|                     "Make sure the account you use is in your name, not someone else's", |  | ||||||
|                     style: TextStyle( |  | ||||||
|                       color: ColorPalette.slate400, |  | ||||||
|                     ), |  | ||||||
|                   ), |  | ||||||
|                   SizedBox(height: SizeConfig.height * .08), |  | ||||||
|                   ButtonView( |  | ||||||
|                     name: 'Next', |  | ||||||
|                     onPressed: () { |  | ||||||
|                       provider.next(context).then((value) { |  | ||||||
|                         if (value) { |  | ||||||
|                           routePush(context, page: const ConfirmBankAccount()); |  | ||||||
|                         } |  | ||||||
|                       }); |  | ||||||
|                     }, |  | ||||||
|                   ) |  | ||||||
|                 ], |  | ||||||
|               ); |               ); | ||||||
|             }), |             }), | ||||||
|           ); |           ); | ||||||
|   | |||||||
| @@ -56,17 +56,24 @@ class _QuestionViewState extends State<QuestionView> { | |||||||
|           bottomNavigationBar: SizedBox( |           bottomNavigationBar: SizedBox( | ||||||
|             height: 84, |             height: 84, | ||||||
|             child: ButtonView( |             child: ButtonView( | ||||||
|  |               disabled: provider.listScore[currentPage] == 0, | ||||||
|               name: 'Next', |               name: 'Next', | ||||||
|               marginVertical: 16, |               marginVertical: 16, | ||||||
|  |               disabledBgColor: ColorPalette.slate200, | ||||||
|  |               textColor: provider.listScore[currentPage] == 0 ? ColorPalette.slate500 : Colors.white, | ||||||
|  |               backgroundColor: ColorPalette.primary, | ||||||
|               onPressed: () { |               onPressed: () { | ||||||
|                 if (currentPage > 3) { |                 if (currentPage > 3) { | ||||||
|                   int totalScore = provider.listScore |                   int totalScore = provider.listScore | ||||||
|                       .reduce((value, element) => value + element); |                       .reduce((value, element) => value + element); | ||||||
|                   provider.setTypeResult(totalScore); |                   provider.setTypeResult(totalScore); | ||||||
|                   routePush(context, |                   routePush(context, | ||||||
|                       page: ResultsView( |                     page: ResultsView( | ||||||
|                           totalScore: totalScore.toString(), |                         totalScore: totalScore, | ||||||
|                           typeResult: provider.typeResult)); |                         typeResult: provider.typeResult | ||||||
|  |                     ), | ||||||
|  |                     routeType: RouteType.pushReplace | ||||||
|  |                   ); | ||||||
|                 } else { |                 } else { | ||||||
|                   setState(() { |                   setState(() { | ||||||
|                     currentPage += 1; |                     currentPage += 1; | ||||||
|   | |||||||
| @@ -1,14 +1,17 @@ | |||||||
| import 'package:cims_apps/application/component/button/back_button_view.dart'; | import 'package:cims_apps/application/component/button/back_button_view.dart'; | ||||||
| import 'package:cims_apps/application/component/button/button_view.dart'; | import 'package:cims_apps/application/component/button/button_view.dart'; | ||||||
|  | import 'package:cims_apps/application/component/risk_profile.dart'; | ||||||
| import 'package:cims_apps/application/theme/color_palette.dart'; | import 'package:cims_apps/application/theme/color_palette.dart'; | ||||||
| import 'package:cims_apps/core/route/route.dart'; | import 'package:cims_apps/core/route/route.dart'; | ||||||
| import 'package:cims_apps/core/utils/size_config.dart'; | import 'package:cims_apps/core/utils/size_config.dart'; | ||||||
|  | import 'package:cims_apps/features/auth/registration/view/submission_data/risk_profile/question_view.dart'; | ||||||
|  | import 'package:cims_apps/features/auth/registration/view/submission_data/risk_profile/risk_profile_view.dart'; | ||||||
| import 'package:cims_apps/features/auth/registration/view/submission_data/risk_profile/risk_profile_view_model/risk_profile_view_model.dart'; | import 'package:cims_apps/features/auth/registration/view/submission_data/risk_profile/risk_profile_view_model/risk_profile_view_model.dart'; | ||||||
| import 'package:cims_apps/features/auth/registration/view/submission_data/terms_and_condition/terms_and_condition_view.dart'; | import 'package:cims_apps/features/auth/registration/view/submission_data/terms_and_condition/terms_and_condition_view.dart'; | ||||||
| import 'package:flutter/material.dart'; | import 'package:flutter/material.dart'; | ||||||
|  |  | ||||||
| class ResultsView extends StatelessWidget { | class ResultsView extends StatelessWidget { | ||||||
|   final String totalScore; |   final int totalScore; | ||||||
|   final RiskProfileResult typeResult; |   final RiskProfileResult typeResult; | ||||||
|   const ResultsView( |   const ResultsView( | ||||||
|       {super.key, required this.typeResult, required this.totalScore}); |       {super.key, required this.typeResult, required this.totalScore}); | ||||||
| @@ -37,115 +40,15 @@ class ResultsView extends StatelessWidget { | |||||||
|         child: Column( |         child: Column( | ||||||
|           crossAxisAlignment: CrossAxisAlignment.start, |           crossAxisAlignment: CrossAxisAlignment.start, | ||||||
|           children: [ |           children: [ | ||||||
|             ClipRRect( |             RiskProfile(totalScore: totalScore, rowSuitableProduct: false), | ||||||
|               borderRadius: BorderRadius.circular(8), |  | ||||||
|               child: Container( |  | ||||||
|                 decoration: BoxDecoration( |  | ||||||
|                     color: typeResult.color, |  | ||||||
|                     image: DecorationImage( |  | ||||||
|                         image: AssetImage(typeResult.img), |  | ||||||
|                         alignment: Alignment.centerRight)), |  | ||||||
|                 child: Row( |  | ||||||
|                   mainAxisAlignment: MainAxisAlignment.spaceBetween, |  | ||||||
|                   children: [ |  | ||||||
|                     Container( |  | ||||||
|                       padding: const EdgeInsets.all(24), |  | ||||||
|                       child: Column( |  | ||||||
|                         crossAxisAlignment: CrossAxisAlignment.start, |  | ||||||
|                         children: [ |  | ||||||
|                           Text( |  | ||||||
|                             typeResult.type, |  | ||||||
|                             style: const TextStyle( |  | ||||||
|                                 fontWeight: FontWeight.bold, |  | ||||||
|                                 fontSize: 24, |  | ||||||
|                                 color: ColorPalette.white), |  | ||||||
|                           ), |  | ||||||
|                           const SizedBox( |  | ||||||
|                             height: 16, |  | ||||||
|                           ), |  | ||||||
|                           const Text( |  | ||||||
|                             'Total Score :', |  | ||||||
|                             style: TextStyle( |  | ||||||
|                                 fontWeight: FontWeight.bold, |  | ||||||
|                                 fontSize: 16, |  | ||||||
|                                 color: ColorPalette.white), |  | ||||||
|                           ), |  | ||||||
|                           Text( |  | ||||||
|                             totalScore, |  | ||||||
|                             style: const TextStyle( |  | ||||||
|                                 fontWeight: FontWeight.bold, |  | ||||||
|                                 fontSize: 28, |  | ||||||
|                                 color: ColorPalette.white), |  | ||||||
|                           ) |  | ||||||
|                         ], |  | ||||||
|                       ), |  | ||||||
|                     ), |  | ||||||
|                   ], |  | ||||||
|                 ), |  | ||||||
|               ), |  | ||||||
|             ), |  | ||||||
|             const SizedBox( |  | ||||||
|               height: 24, |  | ||||||
|             ), |  | ||||||
|             Text(typeResult.desc, |  | ||||||
|                 style: const TextStyle( |  | ||||||
|                     color: ColorPalette.slate500, fontSize: 16)), |  | ||||||
|             const SizedBox( |  | ||||||
|               height: 24, |  | ||||||
|             ), |  | ||||||
|             const Text( |  | ||||||
|               'Suitable Product', |  | ||||||
|               style: TextStyle( |  | ||||||
|                   color: ColorPalette.slate800, |  | ||||||
|                   fontWeight: FontWeight.bold, |  | ||||||
|                   fontSize: 16), |  | ||||||
|             ), |  | ||||||
|             const SizedBox( |  | ||||||
|               height: 16, |  | ||||||
|             ), |  | ||||||
|             Wrap( |  | ||||||
|               runSpacing: 16, |  | ||||||
|               children: typeResult.suitableProduct.map((e) { |  | ||||||
|                 return Container( |  | ||||||
|                   padding: const EdgeInsets.all(16), |  | ||||||
|                   decoration: BoxDecoration( |  | ||||||
|                     borderRadius: BorderRadius.circular(6), |  | ||||||
|                     border: Border.all(color: ColorPalette.slate200), |  | ||||||
|                   ), |  | ||||||
|                   child: Row( |  | ||||||
|                     children: [ |  | ||||||
|                       Container( |  | ||||||
|                           padding: const EdgeInsets.all(8), |  | ||||||
|                           alignment: Alignment.center, |  | ||||||
|                           decoration: BoxDecoration( |  | ||||||
|                               shape: BoxShape.circle, |  | ||||||
|                               color: typeResult.color.withOpacity(0.1)), |  | ||||||
|                           child: Image.asset(e['icon'], |  | ||||||
|                               width: SizeConfig.width * 0.07, |  | ||||||
|                               color: typeResult.color)), |  | ||||||
|                       const SizedBox( |  | ||||||
|                         width: 12, |  | ||||||
|                       ), |  | ||||||
|                       Expanded( |  | ||||||
|                         child: Text( |  | ||||||
|                           e['desc'], |  | ||||||
|                           style: const TextStyle( |  | ||||||
|                               fontSize: 16, |  | ||||||
|                               fontWeight: FontWeight.bold, |  | ||||||
|                               color: ColorPalette.slate800), |  | ||||||
|                         ), |  | ||||||
|                       ) |  | ||||||
|                     ], |  | ||||||
|                   ), |  | ||||||
|                 ); |  | ||||||
|               }).toList(), |  | ||||||
|             ), |  | ||||||
|             const SizedBox( |             const SizedBox( | ||||||
|               height: 32, |               height: 32, | ||||||
|             ), |             ), | ||||||
|             ButtonView( |             ButtonView( | ||||||
|               name: 'Re-test', |               name: 'Re-test', | ||||||
|               onPressed: () {}, |               onPressed: () { | ||||||
|  |                 routePush(context, page: QuestionView(), routeType: RouteType.pushReplace); | ||||||
|  |               }, | ||||||
|               marginVertical: 0, |               marginVertical: 0, | ||||||
|               backgroundColor: ColorPalette.white, |               backgroundColor: ColorPalette.white, | ||||||
|               textColor: ColorPalette.primary, |               textColor: ColorPalette.primary, | ||||||
|   | |||||||
| @@ -14,12 +14,12 @@ class RiskProfileView extends StatelessWidget { | |||||||
|   Widget build(BuildContext context) { |   Widget build(BuildContext context) { | ||||||
|     return Container( |     return Container( | ||||||
|       width: SizeConfig.width, |       width: SizeConfig.width, | ||||||
|       height: SizeConfig.height, |       height: SizeConfig.height * .8, | ||||||
|       padding: EdgeInsets.all(24), |       padding: const EdgeInsets.all(24), | ||||||
|       child: Column( |       child: Column( | ||||||
|         mainAxisAlignment: MainAxisAlignment.spaceBetween, |         mainAxisAlignment: MainAxisAlignment.spaceBetween, | ||||||
|         children: [ |         children: [ | ||||||
|           Column( |           const Column( | ||||||
|             children: [ |             children: [ | ||||||
|               ImageView(image: PathAssets.imgDataReport), |               ImageView(image: PathAssets.imgDataReport), | ||||||
|               SizedBox( |               SizedBox( | ||||||
| @@ -48,7 +48,7 @@ class RiskProfileView extends StatelessWidget { | |||||||
|           ), |           ), | ||||||
|           Column( |           Column( | ||||||
|             children: [ |             children: [ | ||||||
|               Row( |               const Row( | ||||||
|                 mainAxisAlignment: MainAxisAlignment.center, |                 mainAxisAlignment: MainAxisAlignment.center, | ||||||
|                 children: [ |                 children: [ | ||||||
|                   ImageView( |                   ImageView( | ||||||
| @@ -68,7 +68,7 @@ class RiskProfileView extends StatelessWidget { | |||||||
|                   ) |                   ) | ||||||
|                 ], |                 ], | ||||||
|               ), |               ), | ||||||
|               SizedBox( |               const SizedBox( | ||||||
|                 height: 24, |                 height: 24, | ||||||
|               ), |               ), | ||||||
|               ButtonView( |               ButtonView( | ||||||
|   | |||||||
| @@ -1,3 +1,4 @@ | |||||||
|  | import 'package:cims_apps/application/component/button/back_button_view.dart'; | ||||||
| import 'package:cims_apps/application/component/custom_app_bar/custom_app_bar.dart'; | import 'package:cims_apps/application/component/custom_app_bar/custom_app_bar.dart'; | ||||||
| import 'package:cims_apps/application/theme/color_palette.dart'; | import 'package:cims_apps/application/theme/color_palette.dart'; | ||||||
| import 'package:cims_apps/core/route/route.dart'; | import 'package:cims_apps/core/route/route.dart'; | ||||||
| @@ -24,13 +25,13 @@ class SubmissionParent extends StatefulWidget { | |||||||
| } | } | ||||||
|  |  | ||||||
| class _SubmissionParentState extends State<SubmissionParent> { | class _SubmissionParentState extends State<SubmissionParent> { | ||||||
|   Widget _stepItem({bool isCurrentStep = false, bool isDone = false}) { |   Widget _stepItem({bool isCurrentStep = false}) { | ||||||
|     return Container( |     return Container( | ||||||
|       margin: const EdgeInsets.only(right: 0.0, left: 4.0), |       margin: const EdgeInsets.only(right: 0.0, left: 4.0), | ||||||
|       height: 6, |       height: 6, | ||||||
|       width: SizeConfig.width * .08, |       width: SizeConfig.width * .08, | ||||||
|       decoration: BoxDecoration( |       decoration: BoxDecoration( | ||||||
|         color: isCurrentStep || isDone |         color: isCurrentStep | ||||||
|             ? ColorPalette.primary |             ? ColorPalette.primary | ||||||
|             : ColorPalette.greyBorderNeutrals, |             : ColorPalette.greyBorderNeutrals, | ||||||
|         borderRadius: BorderRadius.circular(50), |         borderRadius: BorderRadius.circular(50), | ||||||
| @@ -66,52 +67,55 @@ class _SubmissionParentState extends State<SubmissionParent> { | |||||||
|     return ChangeNotifierProvider( |     return ChangeNotifierProvider( | ||||||
|         create: (context) => SubmissionDataViewModel(), |         create: (context) => SubmissionDataViewModel(), | ||||||
|         builder: (context, child) { |         builder: (context, child) { | ||||||
|           return WillPopScope( |           return PopScope( | ||||||
|             onWillPop: () async { |             canPop: false, | ||||||
|  |             onPopInvoked: (didPop) async { | ||||||
|  |               if (didPop) { | ||||||
|  |                 return; | ||||||
|  |               } | ||||||
|               await routePush(context, |               await routePush(context, | ||||||
|                   page: const BottomNavigationView(), |                   page: const BottomNavigationView(), | ||||||
|                   routeType: RouteType.pushReplace); |                   routeType: RouteType.pushReplace); | ||||||
|               return false; |  | ||||||
|             }, |             }, | ||||||
|             child: Consumer<SubmissionDataViewModel>( |             child: Consumer<SubmissionDataViewModel>( | ||||||
|                 builder: (context, provider, child) { |                 builder: (context, provider, child) { | ||||||
|               return Scaffold( |               return Scaffold( | ||||||
|                 appBar: CustomAppBar( |                 appBar: CustomAppBar( | ||||||
|                     height: SizeConfig.height * .1, title: 'Registration'), |                   height: SizeConfig.height * .1, | ||||||
|                 body: Stack( |                   title: 'Registration', | ||||||
|  |                   leading: BackButtonView( | ||||||
|  |                     onPress: () { | ||||||
|  |                       routePush( | ||||||
|  |                         context, | ||||||
|  |                         page: const BottomNavigationView(), | ||||||
|  |                         routeType: RouteType.pushReplace, | ||||||
|  |                       ); | ||||||
|  |                     }, | ||||||
|  |                   ), | ||||||
|  |                 ), | ||||||
|  |                 body: Column( | ||||||
|  |                   crossAxisAlignment: CrossAxisAlignment.start, | ||||||
|  |                   mainAxisAlignment: MainAxisAlignment.spaceBetween, | ||||||
|                   children: [ |                   children: [ | ||||||
|                     Column( |                     Padding( | ||||||
|                       crossAxisAlignment: CrossAxisAlignment.start, |                       padding: const EdgeInsets.symmetric( | ||||||
|                       mainAxisAlignment: MainAxisAlignment.spaceBetween, |                           horizontal: 16.0, vertical: 16.0), | ||||||
|                       children: [ |                       child: Row( | ||||||
|                         Padding( |                         mainAxisAlignment: MainAxisAlignment.spaceBetween, | ||||||
|                           padding: const EdgeInsets.symmetric( |                         children: List.generate(provider.stepAmount, (index) { | ||||||
|                               horizontal: 16.0, vertical: 16.0), |                           return _stepItem( | ||||||
|                           child: Row( |                             isCurrentStep: | ||||||
|                             mainAxisAlignment: MainAxisAlignment.spaceBetween, |                                 provider.getCurrentStep == index + 1 || | ||||||
|                             children: |                                     provider.getCurrentStep - 1 > index, | ||||||
|                                 List.generate(provider.stepAmount, (index) { |                           ); | ||||||
|                               // print('indd $index'); |                         }), | ||||||
|                               // print( |                       ), | ||||||
|                               //     'getCurrentStep ${provider.getCurrentStep}'); |                     ), | ||||||
|                               return _stepItem( |                     Expanded( | ||||||
|                                 isCurrentStep: provider.getCurrentStep == |                       child: SingleChildScrollView( | ||||||
|                                         index + 1 || |                         padding: const EdgeInsets.symmetric(horizontal: 16.0), | ||||||
|                                     provider.getCurrentStep - 1 == index + 1, |                         child: _content(provider.getCurrentStep), | ||||||
|                                 // isDone: |                       ), | ||||||
|                                 //     index + 1 != provider.getCurrentStep + 1, |  | ||||||
|                               ); |  | ||||||
|                             }), |  | ||||||
|                           ), |  | ||||||
|                         ), |  | ||||||
|                         Expanded( |  | ||||||
|                           child: Container( |  | ||||||
|                             padding: |  | ||||||
|                                 const EdgeInsets.symmetric(horizontal: 16.0), |  | ||||||
|                             child: _content(provider.getCurrentStep), |  | ||||||
|                           ), |  | ||||||
|                         ), |  | ||||||
|                       ], |  | ||||||
|                     ), |                     ), | ||||||
|                   ], |                   ], | ||||||
|                 ), |                 ), | ||||||
|   | |||||||
| @@ -2,6 +2,7 @@ import 'dart:io'; | |||||||
|  |  | ||||||
| import 'package:cims_apps/application/assets/path_assets.dart'; | 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/button/button_view.dart'; | ||||||
|  | import 'package:cims_apps/application/component/date_picker/date_picker_view.dart'; | ||||||
| import 'package:cims_apps/application/component/image/image_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_caption/text_caption.dart'; | ||||||
| import 'package:cims_apps/application/component/text_form/text_form_view.dart'; | import 'package:cims_apps/application/component/text_form/text_form_view.dart'; | ||||||
| @@ -12,6 +13,7 @@ import 'package:cims_apps/features/auth/registration/view/submission_data/submis | |||||||
| import 'package:cims_apps/features/auth/registration/viewmodel/submission_data_viewmodel.dart'; | import 'package:cims_apps/features/auth/registration/viewmodel/submission_data_viewmodel.dart'; | ||||||
| import 'package:flutter/material.dart'; | import 'package:flutter/material.dart'; | ||||||
| import 'package:provider/provider.dart'; | import 'package:provider/provider.dart'; | ||||||
|  | import 'dart:math' as math; | ||||||
|  |  | ||||||
| class SubmitDataIdCard extends StatelessWidget { | class SubmitDataIdCard extends StatelessWidget { | ||||||
|   const SubmitDataIdCard({Key? key}) : super(key: key); |   const SubmitDataIdCard({Key? key}) : super(key: key); | ||||||
| @@ -29,7 +31,7 @@ class SubmitDataIdCard extends StatelessWidget { | |||||||
|                     color: Colors.white, |                     color: Colors.white, | ||||||
|                     borderRadius: |                     borderRadius: | ||||||
|                         BorderRadius.vertical(top: Radius.circular(18))), |                         BorderRadius.vertical(top: Radius.circular(18))), | ||||||
|                 height: SizeConfig.height * .32, |                 height: SizeConfig.height * .35, | ||||||
|                 padding: const EdgeInsets.all(16.0), |                 padding: const EdgeInsets.all(16.0), | ||||||
|                 child: Column( |                 child: Column( | ||||||
|                   mainAxisAlignment: MainAxisAlignment.spaceBetween, |                   mainAxisAlignment: MainAxisAlignment.spaceBetween, | ||||||
| @@ -107,14 +109,21 @@ class SubmitDataIdCard extends StatelessWidget { | |||||||
|                   SizedBox( |                   SizedBox( | ||||||
|                     height: SizeConfig.height * .18, |                     height: SizeConfig.height * .18, | ||||||
|                     width: SizeConfig.width * .45, |                     width: SizeConfig.width * .45, | ||||||
|                     child: ClipRRect( |                     child: Transform( | ||||||
|                       borderRadius: BorderRadius.circular(8), |                       alignment: Alignment.center, | ||||||
|                       child: Image.file( |                       transform: e.key == 'selfie' | ||||||
|                         File(e.image), |                           ? Matrix4.rotationY(math.pi) | ||||||
|                         fit: BoxFit.fill, |                           : Matrix4.rotationY(0), | ||||||
|                         errorBuilder: (context, error, stackTrace) { |                       child: ClipRRect( | ||||||
|                           return const Icon(Icons.image_not_supported_outlined); |                         borderRadius: BorderRadius.circular(8), | ||||||
|                         }, |                         child: Image.file( | ||||||
|  |                           File(e.image), | ||||||
|  |                           fit: BoxFit.fill, | ||||||
|  |                           errorBuilder: (context, error, stackTrace) { | ||||||
|  |                             return const Icon( | ||||||
|  |                                 Icons.image_not_supported_outlined); | ||||||
|  |                           }, | ||||||
|  |                         ), | ||||||
|                       ), |                       ), | ||||||
|                     ), |                     ), | ||||||
|                   ), |                   ), | ||||||
| @@ -167,77 +176,107 @@ class SubmitDataIdCard extends StatelessWidget { | |||||||
|           return SingleChildScrollView( |           return SingleChildScrollView( | ||||||
|             child: Consumer<SubmissionDataViewModel>( |             child: Consumer<SubmissionDataViewModel>( | ||||||
|                 builder: (context, provider, child) { |                 builder: (context, provider, child) { | ||||||
|               return Column( |               return Form( | ||||||
|                 crossAxisAlignment: CrossAxisAlignment.start, |                 key: provider.formKeySubmitIdCard, | ||||||
|                 children: [ |                 child: Column( | ||||||
|                   const TextCaption( |                   crossAxisAlignment: CrossAxisAlignment.start, | ||||||
|                       title: 'Check your ID card data for accuracy'), |                   children: [ | ||||||
|                   TextFormView(name: 'NIK'), |                     const TextCaption( | ||||||
|                   TextFormView(name: 'Full Name'), |                         title: 'Check your ID card data for accuracy'), | ||||||
|                   TextFormView( |                     TextFormView( | ||||||
|                     name: 'Birth Date', |                       name: 'NIK', | ||||||
|                     suffixIcon: const Icon( |                       keyboardType: TextInputType.number, | ||||||
|                       Icons.calendar_today_rounded, |                       validator: (value) { | ||||||
|                       color: ColorPalette.slate400, |                         if (value!.isEmpty) { | ||||||
|  |                           return 'Field must be filled'; | ||||||
|  |                         } | ||||||
|  |                         return null; | ||||||
|  |                       }, | ||||||
|                     ), |                     ), | ||||||
|                   ), |                     TextFormView( | ||||||
|                   photoDocument(provider), |                       name: 'Full Name', | ||||||
|                   Container( |                       validator: (value) { | ||||||
|                     width: SizeConfig.width, |                         if (value!.isEmpty) { | ||||||
|                     padding: const EdgeInsets.symmetric(horizontal: 16.0), |                           return 'Field must be filled'; | ||||||
|                     margin: const EdgeInsets.symmetric(vertical: 16.0), |                         } | ||||||
|                     decoration: BoxDecoration( |                         return null; | ||||||
|                       color: ColorPalette.blue50, |                       }, | ||||||
|                       borderRadius: BorderRadius.circular(10), |                     ), | ||||||
|                       border: Border.all( |                     DatePickerView( | ||||||
|                         color: ColorPalette.greyLights, |                       name: 'Birth Date', | ||||||
|                         width: 1, |                       ctrl: provider.ctrlBirthDate, | ||||||
|  |                       maxDate: DateTime.now(), | ||||||
|  |                       isMultipleSelection: false, | ||||||
|  |                       enabled: true, | ||||||
|  |                       validatorDate: (value) { | ||||||
|  |                         if (value!.isEmpty) { | ||||||
|  |                           return 'Field must be filled'; | ||||||
|  |                         } | ||||||
|  |                         return null; | ||||||
|  |                       }, | ||||||
|  |                     ), | ||||||
|  |                     photoDocument(provider), | ||||||
|  |                     Container( | ||||||
|  |                       width: SizeConfig.width, | ||||||
|  |                       padding: const EdgeInsets.symmetric(horizontal: 16.0), | ||||||
|  |                       margin: const EdgeInsets.symmetric(vertical: 16.0), | ||||||
|  |                       decoration: BoxDecoration( | ||||||
|  |                         color: ColorPalette.blue50, | ||||||
|  |                         borderRadius: BorderRadius.circular(10), | ||||||
|  |                         border: Border.all( | ||||||
|  |                           color: ColorPalette.greyLights, | ||||||
|  |                           width: 1, | ||||||
|  |                         ), | ||||||
|                       ), |                       ), | ||||||
|                     ), |                       child: Row( | ||||||
|                     child: Row( |                         mainAxisAlignment: MainAxisAlignment.spaceBetween, | ||||||
|                       mainAxisAlignment: MainAxisAlignment.spaceBetween, |                         children: [ | ||||||
|                       children: [ |                           const ImageView( | ||||||
|                         const ImageView( |                             image: PathAssets.iconShield, | ||||||
|                           image: PathAssets.iconShield, |                             width: 20, | ||||||
|                           width: 20, |                             height: 22, | ||||||
|                           height: 22, |                           ), | ||||||
|                         ), |                           const SizedBox( | ||||||
|                         const SizedBox( |                             width: 8, | ||||||
|                           width: 8, |                           ), | ||||||
|                         ), |                           const Expanded( | ||||||
|                         const Expanded( |                             child: Text( | ||||||
|                           child: Text( |                               'Will my data be safe?', | ||||||
|                             'Will my data be safe?', |                               style: TextStyle( | ||||||
|                             style: TextStyle( |                                 fontWeight: FontWeight.w600, | ||||||
|                               fontWeight: FontWeight.w600, |                                 color: ColorPalette.primary, | ||||||
|                               color: ColorPalette.primary, |                               ), | ||||||
|                             ), |                             ), | ||||||
|                           ), |                           ), | ||||||
|                         ), |                           IconButton( | ||||||
|                         IconButton( |                             onPressed: () { | ||||||
|                           onPressed: () { |                               bottomSheet(); | ||||||
|                             bottomSheet(); |                             }, | ||||||
|                           }, |                             icon: const Icon( | ||||||
|                           icon: const Icon( |                               Icons.arrow_forward_ios, | ||||||
|                             Icons.arrow_forward_ios, |                               color: ColorPalette.primary, | ||||||
|                             color: ColorPalette.primary, |                               size: 20, | ||||||
|                             size: 20, |                             ), | ||||||
|                           ), |                           ) | ||||||
|                         ) |                         ], | ||||||
|                       ], |                       ), | ||||||
|                     ), |                     ), | ||||||
|                   ), |                     ButtonView( | ||||||
|                   ButtonView( |                       name: 'Next', | ||||||
|                     name: 'Next', |                       onPressed: () async { | ||||||
|                     onPressed: () async { |                         if (provider.formKeySubmitIdCard.currentState! | ||||||
|                       await provider.next(context).then((value) { |                             .validate()) { | ||||||
|                         if (value) { |                           await provider.next(context).then((value) { | ||||||
|                           routePush(context, page: const SubmissionParent()); |                             if (value) { | ||||||
|  |                               routePush(context, | ||||||
|  |                                   page: const SubmissionParent()); | ||||||
|  |                             } | ||||||
|  |                           }); | ||||||
|                         } |                         } | ||||||
|                       }); |                       }, | ||||||
|                     }, |                     ) | ||||||
|                   ) |                   ], | ||||||
|                 ], |                 ), | ||||||
|               ); |               ); | ||||||
|             }), |             }), | ||||||
|           ); |           ); | ||||||
|   | |||||||
| @@ -5,6 +5,7 @@ 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/component/text_form/text_form_view.dart'; | ||||||
| import 'package:cims_apps/core/route/route.dart'; | import 'package:cims_apps/core/route/route.dart'; | ||||||
| import 'package:cims_apps/core/utils/size_config.dart'; | import 'package:cims_apps/core/utils/size_config.dart'; | ||||||
|  | import 'package:cims_apps/core/utils/string_utils.dart'; | ||||||
| import 'package:cims_apps/features/auth/registration/view/submission_data/submission_parent.dart'; | import 'package:cims_apps/features/auth/registration/view/submission_data/submission_parent.dart'; | ||||||
| import 'package:cims_apps/features/auth/registration/viewmodel/submission_data_viewmodel.dart'; | import 'package:cims_apps/features/auth/registration/viewmodel/submission_data_viewmodel.dart'; | ||||||
| import 'package:flutter/gestures.dart'; | import 'package:flutter/gestures.dart'; | ||||||
| @@ -14,44 +15,70 @@ import 'package:provider/provider.dart'; | |||||||
| class SubmitEmail extends StatelessWidget { | class SubmitEmail extends StatelessWidget { | ||||||
|   const SubmitEmail({Key? key}) : super(key: key); |   const SubmitEmail({Key? key}) : super(key: key); | ||||||
|  |  | ||||||
|   Widget _emailVerify() { |   Widget _emailVerify(BuildContext context, SubmissionDataViewModel provider) { | ||||||
|     return Column( |     var textTheme = Theme.of(context).textTheme; | ||||||
|       children: [ |     return Padding( | ||||||
|         const ImageView(image: PathAssets.imgEmail), |       padding: const EdgeInsets.all(24.0), | ||||||
|         Align( |       child: Column( | ||||||
|           alignment: Alignment.center, |         crossAxisAlignment: CrossAxisAlignment.start, | ||||||
|           child: RichText( |         children: [ | ||||||
|             textAlign: TextAlign.center, |           const TextCaption(title: 'Check your e-mail'), | ||||||
|             text: TextSpan(children: [ |           const ImageView(image: PathAssets.imgEmail), | ||||||
|               const TextSpan( |           Align( | ||||||
|                 text: |             alignment: Alignment.center, | ||||||
|                     'We have sent a verification link to your e-mail. \nPlease check your email for ', |             child: RichText( | ||||||
|                 style: TextStyle( |               textAlign: TextAlign.center, | ||||||
|                   color: Colors.black, |               text: TextSpan(children: [ | ||||||
|                   decoration: TextDecoration.none, |                 TextSpan( | ||||||
|  |                   text: | ||||||
|  |                       'We have sent a verification link to your e-mail. \nPlease check your email for ', | ||||||
|  |                   style: textTheme.displayMedium, | ||||||
|                 ), |                 ), | ||||||
|               ), |                 TextSpan( | ||||||
|               TextSpan( |                   recognizer: TapGestureRecognizer() | ||||||
|                 recognizer: TapGestureRecognizer() |                     ..onTap = () async { | ||||||
|                   ..onTap = () { |                       await provider.next(context).then((value) { | ||||||
|                     print('object'); |                         if (value) { | ||||||
|                   }, |                           routePush(context, page: const SubmissionParent()); | ||||||
|                 text: 'verification', |                         } | ||||||
|                 style: const TextStyle( |                       }); | ||||||
|                   color: Colors.blue, |                     }, | ||||||
|  |                   text: 'verification', | ||||||
|  |                   style: const TextStyle( | ||||||
|  |                     color: Colors.blue, | ||||||
|  |                   ), | ||||||
|                 ), |                 ), | ||||||
|               ), |                 TextSpan( | ||||||
|               const TextSpan( |                   text: ' to \ncontinue registration.', | ||||||
|                 text: ' to \ncontinue registration.', |                   style: textTheme.displayMedium, | ||||||
|                 style: TextStyle( |  | ||||||
|                   color: Colors.black, |  | ||||||
|                   decoration: TextDecoration.none, |  | ||||||
|                 ), |                 ), | ||||||
|               ), |               ]), | ||||||
|             ]), |             ), | ||||||
|           ), |           ), | ||||||
|  |         ], | ||||||
|  |       ), | ||||||
|  |     ); | ||||||
|  |   } | ||||||
|  |  | ||||||
|  |   showEmailVerify(BuildContext context, SubmissionDataViewModel provider) { | ||||||
|  |     showModalBottomSheet( | ||||||
|  |       context: context, | ||||||
|  |       isScrollControlled: true, | ||||||
|  |       enableDrag: false, | ||||||
|  |       shape: const RoundedRectangleBorder( | ||||||
|  |         borderRadius: BorderRadius.vertical( | ||||||
|  |           top: Radius.zero, | ||||||
|         ), |         ), | ||||||
|       ], |       ), | ||||||
|  |       builder: (context) { | ||||||
|  |         var flutterView = View.of(context); | ||||||
|  |         return Padding( | ||||||
|  |           padding: EdgeInsets.only( | ||||||
|  |             top: MediaQueryData.fromView(flutterView).padding.top, | ||||||
|  |           ), | ||||||
|  |           child: _emailVerify(context, provider), | ||||||
|  |         ); | ||||||
|  |       }, | ||||||
|     ); |     ); | ||||||
|   } |   } | ||||||
|  |  | ||||||
| @@ -62,35 +89,41 @@ class SubmitEmail extends StatelessWidget { | |||||||
|         builder: (context, child) { |         builder: (context, child) { | ||||||
|           return Consumer<SubmissionDataViewModel>( |           return Consumer<SubmissionDataViewModel>( | ||||||
|               builder: (context, provider, child) { |               builder: (context, provider, child) { | ||||||
|             return SingleChildScrollView( |             return SizedBox( | ||||||
|               child: Column( |               height: SizeConfig.height * .78, | ||||||
|                 crossAxisAlignment: CrossAxisAlignment.start, |               child: Form( | ||||||
|                 // mainAxisAlignment: MainAxisAlignment.spaceBetween, |                 key: provider.formKeySubmitEmail, | ||||||
|                 children: [ |                 child: Column( | ||||||
|                   !provider.isEmailVerify |                   crossAxisAlignment: CrossAxisAlignment.start, | ||||||
|                       ? const TextCaption(title: 'Enter your e-mail') |                   mainAxisAlignment: MainAxisAlignment.spaceAround, | ||||||
|                       : const TextCaption(title: 'Check your e-mail '), |                   children: [ | ||||||
|                   !provider.isEmailVerify |                     const TextCaption(title: 'Enter your e-mail'), | ||||||
|                       ? TextFormView( |                     TextFormView( | ||||||
|                           name: 'E-mail Address', |                       name: 'E-mail Address', | ||||||
|                           hintText: 'Input e-mail address', |                       hintText: 'Input e-mail address', | ||||||
|                           // onTap: () { |                       keyboardType: TextInputType.emailAddress, | ||||||
|                           //   provider.submitEmail(); |                       validator: (value) { | ||||||
|                           // }, |                         if (value!.isEmpty) { | ||||||
|                         ) |                           return 'Filled cannot be empty'; | ||||||
|                       : _emailVerify(), |                         } else if (!StringUtils.emailValidation(value)) { | ||||||
|                   SizedBox(height: SizeConfig.height * .42), |                           return 'Format email wrong'; | ||||||
|                   ButtonView( |                         } else { | ||||||
|                     name: 'Next', |                           return null; | ||||||
|                     onPressed: () async { |  | ||||||
|                       await provider.next(context).then((value) { |  | ||||||
|                         if (value) { |  | ||||||
|                           routePush(context, page: const SubmissionParent()); |  | ||||||
|                         } |                         } | ||||||
|                       }); |                       }, | ||||||
|                     }, |                     ), | ||||||
|                   ) |                     SizedBox(height: SizeConfig.height * .43), | ||||||
|                 ], |                     ButtonView( | ||||||
|  |                       name: 'Next', | ||||||
|  |                       onPressed: () async { | ||||||
|  |                         if (provider.formKeySubmitEmail.currentState! | ||||||
|  |                             .validate()) { | ||||||
|  |                           showEmailVerify(context, provider); | ||||||
|  |                         } | ||||||
|  |                       }, | ||||||
|  |                     ) | ||||||
|  |                   ], | ||||||
|  |                 ), | ||||||
|               ), |               ), | ||||||
|             ); |             ); | ||||||
|           }); |           }); | ||||||
|   | |||||||
| @@ -2,6 +2,7 @@ import 'package:cims_apps/application/component/button/button_view.dart'; | |||||||
| import 'package:cims_apps/application/component/select_form/select_form_view.dart'; | 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/component/text_caption/text_caption.dart'; | ||||||
| import 'package:cims_apps/core/route/route.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/view/submission_data/submission_parent.dart'; | ||||||
| import 'package:cims_apps/features/auth/registration/viewmodel/submission_data_viewmodel.dart'; | import 'package:cims_apps/features/auth/registration/viewmodel/submission_data_viewmodel.dart'; | ||||||
| import 'package:flutter/material.dart'; | import 'package:flutter/material.dart'; | ||||||
| @@ -17,12 +18,13 @@ class SubmitPersonalData extends StatelessWidget { | |||||||
|         builder: (context, child) { |         builder: (context, child) { | ||||||
|           return Consumer<SubmissionDataViewModel>( |           return Consumer<SubmissionDataViewModel>( | ||||||
|               builder: (context, provider, child) { |               builder: (context, provider, child) { | ||||||
|             return SingleChildScrollView( |             return SizedBox( | ||||||
|  |               height: SizeConfig.height * .78, | ||||||
|               child: Form( |               child: Form( | ||||||
|                 key: provider.formKeyPersonalData, |                 key: provider.formKeyPersonalData, | ||||||
|                 child: Column( |                 child: Column( | ||||||
|                   crossAxisAlignment: CrossAxisAlignment.start, |                   crossAxisAlignment: CrossAxisAlignment.start, | ||||||
|                   mainAxisAlignment: MainAxisAlignment.spaceBetween, |                   mainAxisAlignment: MainAxisAlignment.spaceAround, | ||||||
|                   children: [ |                   children: [ | ||||||
|                     const TextCaption(title: 'Your personal details'), |                     const TextCaption(title: 'Your personal details'), | ||||||
|                     SelectFormView( |                     SelectFormView( | ||||||
| @@ -31,6 +33,12 @@ class SubmitPersonalData extends StatelessWidget { | |||||||
|                       ctrl: provider.ctrlOccupation, |                       ctrl: provider.ctrlOccupation, | ||||||
|                       listItem: provider.listOccupation, |                       listItem: provider.listOccupation, | ||||||
|                       onSelect: (value) {}, |                       onSelect: (value) {}, | ||||||
|  |                       validator: (value) { | ||||||
|  |                         if (value!.isEmpty) { | ||||||
|  |                           return 'Field must be filled'; | ||||||
|  |                         } | ||||||
|  |                         return null; | ||||||
|  |                       }, | ||||||
|                     ), |                     ), | ||||||
|                     SelectFormView( |                     SelectFormView( | ||||||
|                       name: 'Income Level (IDR)', |                       name: 'Income Level (IDR)', | ||||||
| @@ -38,6 +46,12 @@ class SubmitPersonalData extends StatelessWidget { | |||||||
|                       ctrl: provider.ctrlIncome, |                       ctrl: provider.ctrlIncome, | ||||||
|                       listItem: provider.listIncome, |                       listItem: provider.listIncome, | ||||||
|                       onSelect: (value) {}, |                       onSelect: (value) {}, | ||||||
|  |                       validator: (value) { | ||||||
|  |                         if (value!.isEmpty) { | ||||||
|  |                           return 'Field must be filled'; | ||||||
|  |                         } | ||||||
|  |                         return null; | ||||||
|  |                       }, | ||||||
|                     ), |                     ), | ||||||
|                     SelectFormView( |                     SelectFormView( | ||||||
|                       name: 'Marital Status', |                       name: 'Marital Status', | ||||||
| @@ -45,6 +59,12 @@ class SubmitPersonalData extends StatelessWidget { | |||||||
|                       ctrl: provider.ctrlMarital, |                       ctrl: provider.ctrlMarital, | ||||||
|                       listItem: provider.listMarital, |                       listItem: provider.listMarital, | ||||||
|                       onSelect: (value) {}, |                       onSelect: (value) {}, | ||||||
|  |                       validator: (value) { | ||||||
|  |                         if (value!.isEmpty) { | ||||||
|  |                           return 'Field must be filled'; | ||||||
|  |                         } | ||||||
|  |                         return null; | ||||||
|  |                       }, | ||||||
|                     ), |                     ), | ||||||
|                     SelectFormView( |                     SelectFormView( | ||||||
|                       name: 'Source of Fund', |                       name: 'Source of Fund', | ||||||
| @@ -52,20 +72,28 @@ class SubmitPersonalData extends StatelessWidget { | |||||||
|                       ctrl: provider.ctrlSourceFund, |                       ctrl: provider.ctrlSourceFund, | ||||||
|                       listItem: provider.listSourceFund, |                       listItem: provider.listSourceFund, | ||||||
|                       onSelect: (value) {}, |                       onSelect: (value) {}, | ||||||
|  |                       validator: (value) { | ||||||
|  |                         if (value!.isEmpty) { | ||||||
|  |                           return 'Field must be filled'; | ||||||
|  |                         } | ||||||
|  |                         return null; | ||||||
|  |                       }, | ||||||
|                     ), |                     ), | ||||||
|                     Align( |                     // SizedBox(height: SizeConfig.height * .18), | ||||||
|                       alignment: Alignment.bottomCenter, |                     ButtonView( | ||||||
|                       child: ButtonView( |                       marginVertical: 0, | ||||||
|                         name: 'Next', |                       name: 'Next', | ||||||
|                         onPressed: () async { |                       onPressed: () async { | ||||||
|  |                         if (provider.formKeyPersonalData.currentState! | ||||||
|  |                             .validate()) { | ||||||
|                           await provider.next(context).then((value) { |                           await provider.next(context).then((value) { | ||||||
|                             if (value) { |                             if (value) { | ||||||
|                               routePush(context, |                               routePush(context, | ||||||
|                                   page: const SubmissionParent()); |                                   page: const SubmissionParent()); | ||||||
|                             } |                             } | ||||||
|                           }); |                           }); | ||||||
|                         }, |                         } | ||||||
|                       ), |                       }, | ||||||
|                     ) |                     ) | ||||||
|                   ], |                   ], | ||||||
|                 ), |                 ), | ||||||
|   | |||||||
| @@ -24,26 +24,30 @@ class InitialSignature extends StatelessWidget { | |||||||
|         builder: (context, child) { |         builder: (context, child) { | ||||||
|           return Consumer<SubmissionDataViewModel>( |           return Consumer<SubmissionDataViewModel>( | ||||||
|               builder: (context, provider, child) { |               builder: (context, provider, child) { | ||||||
|             return Column( |             return SizedBox( | ||||||
|               crossAxisAlignment: CrossAxisAlignment.start, |               height: SizeConfig.height * .8, | ||||||
|               children: [ |               child: Column( | ||||||
|                 const TextCaption(title: 'Draw your digital sign'), |                 crossAxisAlignment: CrossAxisAlignment.start, | ||||||
|                 const ImageView(image: PathAssets.frameSignature), |                 mainAxisAlignment: MainAxisAlignment.spaceBetween, | ||||||
|                 const ListTileView( |                 children: [ | ||||||
|                     title: |                   const TextCaption(title: 'Draw your digital sign'), | ||||||
|                         'Make sure the sign you draw is match with your ID Card'), |                   const ImageView(image: PathAssets.frameSignature), | ||||||
|                 SizedBox(height: SizeConfig.height * .07), |                   const ListTileView( | ||||||
|                 ButtonView( |                       title: | ||||||
|                   name: 'Next', |                           'Make sure the sign you draw is match with your ID Card'), | ||||||
|                   onPressed: () { |                   SizedBox(height: SizeConfig.height * .1), | ||||||
|                     provider.next(context).then((value) { |                   ButtonView( | ||||||
|                       if (value) { |                     name: 'Next', | ||||||
|                         routePush(context, page: const SubmitSignature()); |                     onPressed: () { | ||||||
|                       } |                       provider.next(context).then((value) { | ||||||
|                     }); |                         if (value) { | ||||||
|                   }, |                           routePush(context, page: const SubmitSignature()); | ||||||
|                 ) |                         } | ||||||
|               ], |                       }); | ||||||
|  |                     }, | ||||||
|  |                   ) | ||||||
|  |                 ], | ||||||
|  |               ), | ||||||
|             ); |             ); | ||||||
|           }); |           }); | ||||||
|         }); |         }); | ||||||
|   | |||||||
| @@ -3,6 +3,7 @@ import 'package:cims_apps/application/component/button/button_view.dart'; | |||||||
| import 'package:cims_apps/application/component/set_pin_view/set_pin_view.dart'; | import 'package:cims_apps/application/component/set_pin_view/set_pin_view.dart'; | ||||||
| import 'package:cims_apps/application/theme/color_palette.dart'; | import 'package:cims_apps/application/theme/color_palette.dart'; | ||||||
| import 'package:cims_apps/core/route/route.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/viewmodel/submission_data_viewmodel.dart'; | import 'package:cims_apps/features/auth/registration/viewmodel/submission_data_viewmodel.dart'; | ||||||
| import 'package:flutter/material.dart'; | import 'package:flutter/material.dart'; | ||||||
| import 'package:provider/provider.dart'; | import 'package:provider/provider.dart'; | ||||||
| @@ -60,47 +61,48 @@ class TermsAndConditionView extends StatelessWidget { | |||||||
|                         ], |                         ], | ||||||
|                       ), |                       ), | ||||||
|                     ); |                     ); | ||||||
|                   }) |                   }), | ||||||
|  |                   Consumer<SubmissionDataViewModel>( | ||||||
|  |                       builder: (context, provider, child) { | ||||||
|  |                     return Padding( | ||||||
|  |                       padding: const EdgeInsets.only(top: 24.0), | ||||||
|  |                       child: Row( | ||||||
|  |                         children: [ | ||||||
|  |                           Expanded( | ||||||
|  |                               child: ButtonView( | ||||||
|  |                             name: 'Decline', | ||||||
|  |                             onPressed: () { | ||||||
|  |                               Navigator.pop(context); | ||||||
|  |                             }, | ||||||
|  |                             height: SizeConfig.height * .06, | ||||||
|  |                             marginVertical: 0, | ||||||
|  |                             backgroundColor: ColorPalette.white, | ||||||
|  |                             textColor: ColorPalette.primary, | ||||||
|  |                             isOutlined: true, | ||||||
|  |                             borderColor: ColorPalette.primary, | ||||||
|  |                           )), | ||||||
|  |                           const SizedBox(width: 16), | ||||||
|  |                           Expanded( | ||||||
|  |                               child: ButtonView( | ||||||
|  |                                   name: 'Accept', | ||||||
|  |                                   onPressed: () { | ||||||
|  |                                     provider.nextSubmission(context); | ||||||
|  |                                     routePush(context, | ||||||
|  |                                         routeType: RouteType.pushReplace, | ||||||
|  |                                         page: SetPinView( | ||||||
|  |                                           currentPin: '', | ||||||
|  |                                           submitPin: (context, pin) {}, | ||||||
|  |                                         )); | ||||||
|  |                                   }, | ||||||
|  |                                   height: SizeConfig.height * .06, | ||||||
|  |                                   marginVertical: 0)) | ||||||
|  |                         ], | ||||||
|  |                       ), | ||||||
|  |                     ); | ||||||
|  |                   }), | ||||||
|                 ], |                 ], | ||||||
|               ), |               ), | ||||||
|             ), |             ), | ||||||
|             bottomNavigationBar: Consumer<SubmissionDataViewModel>( |  | ||||||
|                 builder: (context, provider, child) { |  | ||||||
|               return Container( |  | ||||||
|                 height: 84, |  | ||||||
|                 padding: const EdgeInsets.symmetric(horizontal: 24), |  | ||||||
|                 child: Row( |  | ||||||
|                   children: [ |  | ||||||
|                     Expanded( |  | ||||||
|                         child: ButtonView( |  | ||||||
|                       name: 'Decline', |  | ||||||
|                       onPressed: () { |  | ||||||
|                         Navigator.pop(context); |  | ||||||
|                       }, |  | ||||||
|                       marginVertical: 16, |  | ||||||
|                       backgroundColor: ColorPalette.white, |  | ||||||
|                       textColor: ColorPalette.primary, |  | ||||||
|                       isOutlined: true, |  | ||||||
|                       borderColor: ColorPalette.primary, |  | ||||||
|                     )), |  | ||||||
|                     const SizedBox(width: 16), |  | ||||||
|                     Expanded( |  | ||||||
|                         child: ButtonView( |  | ||||||
|                             name: 'Accept', |  | ||||||
|                             onPressed: () { |  | ||||||
|                               provider.nextSubmission(context); |  | ||||||
|                               routePush(context, |  | ||||||
|                                   routeType: RouteType.pushReplace, |  | ||||||
|                                   page: SetPinView( |  | ||||||
|                                     currentPin: '', |  | ||||||
|                                     submitPin: (context, pin) {}, |  | ||||||
|                                   )); |  | ||||||
|                             }, |  | ||||||
|                             marginVertical: 16)) |  | ||||||
|                   ], |  | ||||||
|                 ), |  | ||||||
|               ); |  | ||||||
|             }), |  | ||||||
|           ); |           ); | ||||||
|         }); |         }); | ||||||
|   } |   } | ||||||
|   | |||||||
| @@ -1,5 +1,6 @@ | |||||||
| import 'package:camera/camera.dart'; | import 'package:camera/camera.dart'; | ||||||
| import 'package:cims_apps/application/component/select_form/select_form_view.dart'; | import 'package:cims_apps/application/component/select_form/select_form_view.dart'; | ||||||
|  | import 'package:cims_apps/features/auth/registration/view/submission_data/data_bank/confirm_bank_account.dart'; | ||||||
| import 'package:flutter/material.dart'; | import 'package:flutter/material.dart'; | ||||||
| import 'package:shared_preferences/shared_preferences.dart'; | import 'package:shared_preferences/shared_preferences.dart'; | ||||||
|  |  | ||||||
| @@ -14,12 +15,21 @@ class SubmissionDataViewModel extends ChangeNotifier { | |||||||
|   bool _isEmailVerify = false; |   bool _isEmailVerify = false; | ||||||
|   bool get isEmailVerify => _isEmailVerify; |   bool get isEmailVerify => _isEmailVerify; | ||||||
|   var formKeyPersonalData = GlobalKey<FormState>(); |   var formKeyPersonalData = GlobalKey<FormState>(); | ||||||
|  |   var formKeySubmitEmail = GlobalKey<FormState>(); | ||||||
|  |   var formKeySubmitIdCard = GlobalKey<FormState>(); | ||||||
|  |   var formKeySubmitDataBank = GlobalKey<FormState>(); | ||||||
|   TextEditingController ctrlOccupation = TextEditingController(); |   TextEditingController ctrlOccupation = TextEditingController(); | ||||||
|   TextEditingController ctrlIncome = TextEditingController(); |   TextEditingController ctrlIncome = TextEditingController(); | ||||||
|   TextEditingController ctrlMarital = TextEditingController(); |   TextEditingController ctrlMarital = TextEditingController(); | ||||||
|   TextEditingController ctrlSourceFund = TextEditingController(); |   TextEditingController ctrlSourceFund = TextEditingController(); | ||||||
|   TextEditingController ctrlBankName = TextEditingController(); |   TextEditingController ctrlBankName = TextEditingController(); | ||||||
|  |   TextEditingController ctrlNameAccountBank = TextEditingController(); | ||||||
|  |   TextEditingController ctrlNoAccountBank = TextEditingController(); | ||||||
|  |   TextEditingController ctrlBankNameSearch = TextEditingController(); | ||||||
|  |   TextEditingController ctrlBirthDate = TextEditingController(); | ||||||
|   int step = 1; |   int step = 1; | ||||||
|  |   String? idx; | ||||||
|  |   String valueBank = ''; | ||||||
|  |  | ||||||
|   List<ItemSelectForm> listOccupation = [ |   List<ItemSelectForm> listOccupation = [ | ||||||
|     ItemSelectForm('key1', 'Student'), |     ItemSelectForm('key1', 'Student'), | ||||||
| @@ -43,16 +53,18 @@ class SubmissionDataViewModel extends ChangeNotifier { | |||||||
|   ]; |   ]; | ||||||
|  |  | ||||||
|   List<ItemSelectForm> listBank = [ |   List<ItemSelectForm> listBank = [ | ||||||
|     ItemSelectForm('key1', 'BCA'), |     ItemSelectForm('0', 'BCA'), | ||||||
|     ItemSelectForm('key2', 'BRI'), |     ItemSelectForm('1', 'BRI'), | ||||||
|     ItemSelectForm('key3', 'BNI'), |     ItemSelectForm('2', 'BNI'), | ||||||
|     ItemSelectForm('key4', 'BANK MANDIRI'), |     ItemSelectForm('3', 'BANK MANDIRI'), | ||||||
|     ItemSelectForm('key5', 'CIMB NIAGA'), |     ItemSelectForm('4', 'CIMB NIAGA'), | ||||||
|  |     ItemSelectForm('5', 'PERMATA'), | ||||||
|  |     ItemSelectForm('6', 'BANK JATENG'), | ||||||
|   ]; |   ]; | ||||||
|  |  | ||||||
|   List<ItemSelectForm> listImg = [ |   List<ItemSelectForm> listImg = [ | ||||||
|     ItemSelectForm('', 'ID Card', image: ''), |     ItemSelectForm('ktp', 'ID Card', image: ''), | ||||||
|     ItemSelectForm('', 'Selfie with ID Card', image: ''), |     ItemSelectForm('selfie', 'Selfie with ID Card', image: ''), | ||||||
|   ]; |   ]; | ||||||
|  |  | ||||||
|   Future<List<CameraDescription>> initCamera() async { |   Future<List<CameraDescription>> initCamera() async { | ||||||
| @@ -104,4 +116,31 @@ class SubmissionDataViewModel extends ChangeNotifier { | |||||||
|     } |     } | ||||||
|     notifyListeners(); |     notifyListeners(); | ||||||
|   } |   } | ||||||
|  |  | ||||||
|  |   changeBank(String key) { | ||||||
|  |     idx = key; | ||||||
|  |     notifyListeners(); | ||||||
|  |   } | ||||||
|  |  | ||||||
|  |   selectBank(String value) { | ||||||
|  |     valueBank = value; | ||||||
|  |     notifyListeners(); | ||||||
|  |   } | ||||||
|  |  | ||||||
|  |   List<ModelDataBank> listDataBank = []; | ||||||
|  |  | ||||||
|  |   Future<List<ModelDataBank>?> submitDataBank( | ||||||
|  |       {required String bankName, accountNumber, accountName}) async { | ||||||
|  |     List<ModelDataBank> listResponse = [ | ||||||
|  |       ModelDataBank('Bank Name', bankName), | ||||||
|  |       ModelDataBank('Account Number', accountNumber), | ||||||
|  |       ModelDataBank('Account Owner Name', accountName), | ||||||
|  |       ModelDataBank('Name on ID card', accountName), | ||||||
|  |     ]; | ||||||
|  |     if (listResponse.first.subtitle != null) { | ||||||
|  |       // listDataBank = listResponse; | ||||||
|  |       return listResponse; | ||||||
|  |     } | ||||||
|  |     return null; | ||||||
|  |   } | ||||||
| } | } | ||||||
|   | |||||||
| @@ -1,10 +1,18 @@ | |||||||
|  | import 'package:cims_apps/application/assets/path_assets.dart'; | ||||||
| import 'package:cims_apps/application/theme/color_palette.dart'; | import 'package:cims_apps/application/theme/color_palette.dart'; | ||||||
|  | import 'package:cims_apps/core/utils/size_config.dart'; | ||||||
| import 'package:cims_apps/features/dashboard/dashboard_account/view/homepage/homepage_view.dart'; | import 'package:cims_apps/features/dashboard/dashboard_account/view/homepage/homepage_view.dart'; | ||||||
| import 'package:cims_apps/features/dashboard/dashboard_account/view/plan/view/plan_view.dart'; | import 'package:cims_apps/features/dashboard/dashboard_account/view/plan/view/plan_view.dart'; | ||||||
| import 'package:cims_apps/features/dashboard/dashboard_account/view/plan/view_model/plan_view_model.dart'; |  | ||||||
| import 'package:cims_apps/features/dashboard/dashboard_account/view/portfolio/portfolio_view.dart'; | import 'package:cims_apps/features/dashboard/dashboard_account/view/portfolio/portfolio_view.dart'; | ||||||
|  | import 'package:cims_apps/features/dashboard/dashboard_account/view/profile/view/profile_view.dart'; | ||||||
|  | import 'package:cims_apps/features/transaction/view/transaction_view.dart'; | ||||||
| import 'package:flutter/material.dart'; | import 'package:flutter/material.dart'; | ||||||
| import 'package:provider/provider.dart'; |  | ||||||
|  | class BottomNavigationItem { | ||||||
|  |   String icon, label; | ||||||
|  |  | ||||||
|  |   BottomNavigationItem(this.icon, this.label); | ||||||
|  | } | ||||||
|  |  | ||||||
| class BottomNavigationView extends StatefulWidget { | class BottomNavigationView extends StatefulWidget { | ||||||
|   const BottomNavigationView({Key? key}) : super(key: key); |   const BottomNavigationView({Key? key}) : super(key: key); | ||||||
| @@ -18,41 +26,28 @@ class _BottomNavigationViewState extends State<BottomNavigationView> { | |||||||
|  |  | ||||||
|   @override |   @override | ||||||
|   Widget build(BuildContext context) { |   Widget build(BuildContext context) { | ||||||
|     ///TODO: masukan pagenya dilistWidget ini |     List<Widget> listWidget = const [ | ||||||
|     List<Widget> listWidget = [ |  | ||||||
|       HomeView(), |       HomeView(), | ||||||
|       PlanView(), |       PlanView(), | ||||||
|       Container(), |       TransactionView(), | ||||||
|       PortofolioView(), |       PortofolioView(), | ||||||
|       Container(), |       ProfileView(), | ||||||
|     ]; |     ]; | ||||||
|  |  | ||||||
|     List<BottomNavigationBarItem> listNavigation = const [ |     List<BottomNavigationItem> listNavigation = [ | ||||||
|       BottomNavigationBarItem( |       BottomNavigationItem(PathAssets.iconNavigationHome, 'Home'), | ||||||
|         icon: Icon(Icons.home_outlined), |       BottomNavigationItem(PathAssets.iconNavigationPlan, 'Plan'), | ||||||
|         label: 'Home', |       BottomNavigationItem(PathAssets.iconNavigationTransaction, 'Transaction'), | ||||||
|       ), |       BottomNavigationItem(PathAssets.iconNavigationPortfolio, 'Portfolio'), | ||||||
|       BottomNavigationBarItem( |       BottomNavigationItem(PathAssets.iconNavigationProfile, 'Profile') | ||||||
|         icon: Icon(Icons.file_open), |  | ||||||
|         label: 'Plan', |  | ||||||
|       ), |  | ||||||
|       BottomNavigationBarItem( |  | ||||||
|         icon: Icon(Icons.compare_arrows), |  | ||||||
|         label: 'Transaction', |  | ||||||
|       ), |  | ||||||
|       BottomNavigationBarItem( |  | ||||||
|         icon: Icon(Icons.pie_chart_rounded), |  | ||||||
|         label: 'Portfolio', |  | ||||||
|       ), |  | ||||||
|       BottomNavigationBarItem( |  | ||||||
|         icon: Icon(Icons.person), |  | ||||||
|         label: 'Profile', |  | ||||||
|       ), |  | ||||||
|     ]; |     ]; | ||||||
|  |  | ||||||
|     return Scaffold( |     return Scaffold( | ||||||
|       body: listWidget[_selectedIndex], |       body: listWidget[_selectedIndex], | ||||||
|       bottomNavigationBar: Padding( |       bottomNavigationBar: Container( | ||||||
|  |         decoration: const BoxDecoration( | ||||||
|  |           border: Border(top: BorderSide(color: ColorPalette.slate200)) | ||||||
|  |         ), | ||||||
|         padding: const EdgeInsets.symmetric(vertical: 12), |         padding: const EdgeInsets.symmetric(vertical: 12), | ||||||
|         child: BottomNavigationBar( |         child: BottomNavigationBar( | ||||||
|           elevation: 0, |           elevation: 0, | ||||||
| @@ -62,13 +57,25 @@ class _BottomNavigationViewState extends State<BottomNavigationView> { | |||||||
|             }); |             }); | ||||||
|           }, |           }, | ||||||
|           currentIndex: _selectedIndex, |           currentIndex: _selectedIndex, | ||||||
|           items: listNavigation, |           items: listNavigation.asMap().entries.map((e) { | ||||||
|  |             return BottomNavigationBarItem( | ||||||
|  |               icon: Padding( | ||||||
|  |                 padding: const EdgeInsets.only(bottom: 4), | ||||||
|  |                 child: Image.asset( | ||||||
|  |                   e.value.icon, | ||||||
|  |                   width: SizeConfig.width * 0.06, | ||||||
|  |                   color: e.key == _selectedIndex ? ColorPalette.primary : ColorPalette.slate800 | ||||||
|  |                 ), | ||||||
|  |               ), | ||||||
|  |               label: e.value.label | ||||||
|  |             ); | ||||||
|  |           }).toList(), | ||||||
|           type: BottomNavigationBarType.fixed, |           type: BottomNavigationBarType.fixed, | ||||||
|           showUnselectedLabels: true, |           showUnselectedLabels: true, | ||||||
|           selectedItemColor: ColorPalette.primary, |           selectedItemColor: ColorPalette.primary, | ||||||
|           unselectedItemColor: Colors.black, |           unselectedItemColor: Colors.black, | ||||||
|           selectedLabelStyle: const TextStyle(color: ColorPalette.primary), |           selectedLabelStyle: const TextStyle(color: ColorPalette.primary, fontSize: 12), | ||||||
|           unselectedLabelStyle: const TextStyle(color: Colors.black), |           unselectedLabelStyle: const TextStyle(color: Colors.black, fontSize: 12), | ||||||
|         ), |         ), | ||||||
|       ), |       ), | ||||||
|     ); |     ); | ||||||
|   | |||||||
| @@ -7,7 +7,6 @@ import 'package:cims_apps/application/theme/color_palette.dart'; | |||||||
| import 'package:cims_apps/core/route/route.dart'; | import 'package:cims_apps/core/route/route.dart'; | ||||||
| import 'package:cims_apps/core/utils/size_config.dart'; | import 'package:cims_apps/core/utils/size_config.dart'; | ||||||
| import 'package:cims_apps/features/auth/registration/view/initial_registration_step.dart'; | import 'package:cims_apps/features/auth/registration/view/initial_registration_step.dart'; | ||||||
| import 'package:cims_apps/features/auth/registration/view/registration_view.dart'; |  | ||||||
| import 'package:cims_apps/features/dashboard/dashboard_account/view/invest_type/invest_type_view.dart'; | import 'package:cims_apps/features/dashboard/dashboard_account/view/invest_type/invest_type_view.dart'; | ||||||
| import 'package:flutter/material.dart'; | import 'package:flutter/material.dart'; | ||||||
|  |  | ||||||
| @@ -50,94 +49,110 @@ class _HomeViewState extends State<HomeView> { | |||||||
|     InvestType('Sharia', PathAssets.iconPortofolioSharia) |     InvestType('Sharia', PathAssets.iconPortofolioSharia) | ||||||
|   ]; |   ]; | ||||||
|  |  | ||||||
|   StepVerification listStepVerification = StepVerification(0, [ |   StepVerification listStepVerification = | ||||||
|     'Registration', 'Verification', 'Complete' |       StepVerification(1, ['Registration', '', 'Verification', '', 'Complete']); | ||||||
|   ]); |  | ||||||
|  |  | ||||||
|   List<Article> listArticle = [ |   List<Article> listArticle = [ | ||||||
|     Article('Education', 'Menggali Potensi Pasar: Analisis Sebelum Memulai Investasi', PathAssets.imgArticles), |     Article( | ||||||
|     Article('News', 'Tren Investasi 2024: Peluang dan Risiko yang Perlu Diketahui', PathAssets.imgArticles), |         'Education', | ||||||
|     Article('Education', 'Investasi Berkelanjutan: Mengenal Portofolio Hijau untuk Masa Depan', PathAssets.imgArticles), |         'Menggali Potensi Pasar: Analisis Sebelum Memulai Investasi', | ||||||
|  |         PathAssets.imgArticles), | ||||||
|  |     Article( | ||||||
|  |         'News', | ||||||
|  |         'Tren Investasi 2024: Peluang dan Risiko yang Perlu Diketahui', | ||||||
|  |         PathAssets.imgArticles), | ||||||
|  |     Article( | ||||||
|  |         'Education', | ||||||
|  |         'Investasi Berkelanjutan: Mengenal Portofolio Hijau untuk Masa Depan', | ||||||
|  |         PathAssets.imgArticles), | ||||||
|   ]; |   ]; | ||||||
|  |  | ||||||
|   @override |   @override | ||||||
|   Widget build(BuildContext context) { |   Widget build(BuildContext context) { | ||||||
|  |  | ||||||
|     return Scaffold( |     return Scaffold( | ||||||
|       backgroundColor: const Color(0xffF8FAFC), |       backgroundColor: ColorPalette.slate50, | ||||||
|       body: SizedBox( |       body: CustomScrollView( | ||||||
|         width: SizeConfig.width, |         slivers: [ | ||||||
|         height: SizeConfig.height, |           SliverAppBar( | ||||||
|         child: Stack( |             onStretchTrigger: () async { | ||||||
|           children: [ |             }, | ||||||
|             const ImageView(image: PathAssets.imgDashboardAccount), |             expandedHeight: 325, | ||||||
|             Column( |             collapsedHeight: 325, | ||||||
|               children: [ |             leading: const SizedBox(), | ||||||
|                 const SizedBox( |             surfaceTintColor: ColorPalette.slate50, | ||||||
|                   height: 50, |             backgroundColor: ColorPalette.slate50, | ||||||
|                 ), |             flexibleSpace: FlexibleSpaceBar( | ||||||
|                 Padding( |               background: Stack( | ||||||
|                   padding: const EdgeInsets.only(left: 24, right: 16), |                 children: [ | ||||||
|                   child: Row( |                   const ImageView(image: PathAssets.imgDashboardAccount), | ||||||
|                     mainAxisAlignment: MainAxisAlignment.spaceBetween, |                   Column( | ||||||
|                     children: [ |                     children: [ | ||||||
|                       const Text( |                       const SizedBox( | ||||||
|                         'Home', |                         height: 50, | ||||||
|                         style: TextStyle( |                       ), | ||||||
|                             color: Colors.white, |                       Padding( | ||||||
|                             fontSize: 20, |                         padding: const EdgeInsets.only(left: 24, right: 16), | ||||||
|                             fontWeight: FontWeight.w700 |                         child: Row( | ||||||
|  |                           mainAxisAlignment: MainAxisAlignment.spaceBetween, | ||||||
|  |                           children: [ | ||||||
|  |                             const Text( | ||||||
|  |                               'Home', | ||||||
|  |                               style: TextStyle( | ||||||
|  |                                   color: Colors.white, | ||||||
|  |                                   fontSize: 20, | ||||||
|  |                                   fontWeight: FontWeight.w700), | ||||||
|  |                             ), | ||||||
|  |                             ElevatedButton( | ||||||
|  |                                 onPressed: () {}, | ||||||
|  |                                 style: ElevatedButton.styleFrom( | ||||||
|  |                                     padding: const EdgeInsets.all(0), | ||||||
|  |                                     backgroundColor: Colors.white, | ||||||
|  |                                     foregroundColor: const Color(0xff2563EB), | ||||||
|  |                                     elevation: 0, | ||||||
|  |                                     shape: const CircleBorder()), | ||||||
|  |                                 child: const Icon(Icons.notifications_outlined)) | ||||||
|  |                           ], | ||||||
|                         ), |                         ), | ||||||
|                       ), |                       ), | ||||||
|                       ElevatedButton( |                       const SizedBox( | ||||||
|                           onPressed: () { |                         height: 32, | ||||||
|  |                       ), | ||||||
|                           }, |                       Padding( | ||||||
|                           style: ElevatedButton.styleFrom( |                         padding: const EdgeInsets.symmetric(horizontal: 24), | ||||||
|                               padding: const EdgeInsets.all(0), |                         child: portofolioValue(), | ||||||
|                               backgroundColor: Colors.white, |                       ), | ||||||
|                               foregroundColor: const Color(0xff2563EB), |                       const SizedBox( | ||||||
|                               elevation: 0, |                         height: 24, | ||||||
|                               shape: const CircleBorder() |                       ), | ||||||
|                           ), |                       cardInvestType(), | ||||||
|                           child: const Icon(Icons.notifications_outlined) |                       const SizedBox( | ||||||
|                       ) |                         height: 24, | ||||||
|  |                       ), | ||||||
|                     ], |                     ], | ||||||
|                   ), |                   ) | ||||||
|                 ), |                 ], | ||||||
|                 const SizedBox( |               ), | ||||||
|                   height: 32, |             ), | ||||||
|                 ), |             floating: true, | ||||||
|                 Padding( |             snap: true, | ||||||
|                   padding: const EdgeInsets.symmetric(horizontal: 24), |           ), | ||||||
|                   child: portofolioValue(), |           SliverToBoxAdapter( | ||||||
|                 ), |             child:  Column( | ||||||
|  |               children: [ | ||||||
|  |                 cardVerification(), | ||||||
|                 const SizedBox( |                 const SizedBox( | ||||||
|                   height: 24, |                   height: 24, | ||||||
|                 ), |                 ), | ||||||
|                 cardInvestType(), |                 infoAndPromo(), | ||||||
|                 const SizedBox( |                 const SizedBox( | ||||||
|                   height: 32, |                   height: 24, | ||||||
|                 ), |  | ||||||
|                 Expanded( |  | ||||||
|                   child: ListView( |  | ||||||
|                     padding: const EdgeInsets.all(0), |  | ||||||
|                     children: [ |  | ||||||
|                       cardVerification(), |  | ||||||
|                       const SizedBox( |  | ||||||
|                         height: 24, |  | ||||||
|                       ), |  | ||||||
|                       infoAndPromo(), |  | ||||||
|                       const SizedBox( |  | ||||||
|                         height: 24, |  | ||||||
|                       ), |  | ||||||
|                       articles(), |  | ||||||
|                     ], |  | ||||||
|                   ), |  | ||||||
|                 ), |                 ), | ||||||
|  |                 articles(), | ||||||
|               ], |               ], | ||||||
|             ) |             ), | ||||||
|           ], |           ) | ||||||
|         ), |         ], | ||||||
|       ), |       ), | ||||||
|     ); |     ); | ||||||
|   } |   } | ||||||
| @@ -148,7 +163,8 @@ class _HomeViewState extends State<HomeView> { | |||||||
|       children: [ |       children: [ | ||||||
|         Row( |         Row( | ||||||
|           children: [ |           children: [ | ||||||
|             const Text('Portofolio Value', style: TextStyle(color: Colors.white)), |             const Text('Portofolio Value', | ||||||
|  |                 style: TextStyle(color: Colors.white)), | ||||||
|             const SizedBox( |             const SizedBox( | ||||||
|               width: 12, |               width: 12, | ||||||
|             ), |             ), | ||||||
| @@ -158,8 +174,11 @@ class _HomeViewState extends State<HomeView> { | |||||||
|                     seePortofolioValue = !seePortofolioValue; |                     seePortofolioValue = !seePortofolioValue; | ||||||
|                   }); |                   }); | ||||||
|                 }, |                 }, | ||||||
|                 child: const Icon(Icons.visibility_outlined, color: Color(0xff93C5FD)) |                 child: Icon( | ||||||
|             ) |                     seePortofolioValue | ||||||
|  |                         ? Icons.visibility_off_outlined | ||||||
|  |                         : Icons.visibility_outlined, | ||||||
|  |                     color: const Color(0xff93C5FD))) | ||||||
|           ], |           ], | ||||||
|         ), |         ), | ||||||
|         const SizedBox( |         const SizedBox( | ||||||
| @@ -170,24 +189,28 @@ class _HomeViewState extends State<HomeView> { | |||||||
|             AnimatedCrossFade( |             AnimatedCrossFade( | ||||||
|               duration: const Duration(milliseconds: 300), |               duration: const Duration(milliseconds: 300), | ||||||
|               alignment: Alignment.center, |               alignment: Alignment.center, | ||||||
|               crossFadeState: seePortofolioValue ? CrossFadeState.showSecond : CrossFadeState.showFirst, |               crossFadeState: seePortofolioValue | ||||||
|  |                   ? CrossFadeState.showSecond | ||||||
|  |                   : CrossFadeState.showFirst, | ||||||
|               firstChild: RichText( |               firstChild: RichText( | ||||||
|                   text: const TextSpan( |                   text: const TextSpan( | ||||||
|                       text: 'Rp ', |                       text: 'Rp ', | ||||||
|                       style: TextStyle(fontSize: 32, color: Color(0xff93C5FD), fontFamily: 'Manrope',), |                       style: TextStyle( | ||||||
|  |                         fontSize: 32, | ||||||
|  |                         color: Color(0xff93C5FD), | ||||||
|  |                         fontFamily: 'Manrope', | ||||||
|  |                       ), | ||||||
|                       children: [ |                       children: [ | ||||||
|                         TextSpan( |                     TextSpan( | ||||||
|                           text: '22.500.000', |                       text: '22.500.000', | ||||||
|                           style: TextStyle( |                       style: TextStyle( | ||||||
|                               fontSize: 32, |                         fontSize: 32, | ||||||
|                               fontWeight: FontWeight.bold, |                         fontWeight: FontWeight.bold, | ||||||
|                               color: Colors.white, |                         color: Colors.white, | ||||||
|                               fontFamily: 'Manrope', |                         fontFamily: 'Manrope', | ||||||
|                           ), |                       ), | ||||||
|                         ) |                     ) | ||||||
|                       ] |                   ])), | ||||||
|                   ) |  | ||||||
|               ), |  | ||||||
|               secondChild: Padding( |               secondChild: Padding( | ||||||
|                 padding: const EdgeInsets.symmetric(vertical: 16), |                 padding: const EdgeInsets.symmetric(vertical: 16), | ||||||
|                 child: Wrap( |                 child: Wrap( | ||||||
| @@ -197,7 +220,8 @@ class _HomeViewState extends State<HomeView> { | |||||||
|                       Container( |                       Container( | ||||||
|                         width: 12, |                         width: 12, | ||||||
|                         height: 12, |                         height: 12, | ||||||
|                         decoration: const BoxDecoration(color: Colors.white, shape: BoxShape.circle), |                         decoration: const BoxDecoration( | ||||||
|  |                             color: Colors.white, shape: BoxShape.circle), | ||||||
|                       ), |                       ), | ||||||
|                   ], |                   ], | ||||||
|                 ), |                 ), | ||||||
| @@ -219,14 +243,12 @@ class _HomeViewState extends State<HomeView> { | |||||||
|             BoxShadow( |             BoxShadow( | ||||||
|                 spreadRadius: 2, |                 spreadRadius: 2, | ||||||
|                 blurRadius: 4, |                 blurRadius: 4, | ||||||
|                 color: const Color(0xff1E293B).withOpacity(0.04) |                 color: const Color(0xff1E293B).withOpacity(0.04)) | ||||||
|             ) |           ]), | ||||||
|           ] |  | ||||||
|       ), |  | ||||||
|       child: Wrap( |       child: Wrap( | ||||||
|         spacing: 10, |         spacing: 10, | ||||||
|         children: listPortofolioType.asMap().entries.map((e) { |         children: listPortofolioType.asMap().entries.map((e) { | ||||||
|           return  GestureDetector( |           return GestureDetector( | ||||||
|             onTap: () { |             onTap: () { | ||||||
|               routePush(context, page: InvestTypeView(title: e.value.name)); |               routePush(context, page: InvestTypeView(title: e.value.name)); | ||||||
|             }, |             }, | ||||||
| @@ -235,7 +257,11 @@ class _HomeViewState extends State<HomeView> { | |||||||
|               width: SizeConfig.width * .18, |               width: SizeConfig.width * .18, | ||||||
|               child: Column( |               child: Column( | ||||||
|                 children: [ |                 children: [ | ||||||
|                   ImageView(image: e.value.iconImage, height: SizeConfig.width * .12, width: SizeConfig.width * .12,), |                   ImageView( | ||||||
|  |                     image: e.value.iconImage, | ||||||
|  |                     height: SizeConfig.width * .12, | ||||||
|  |                     width: SizeConfig.width * .12, | ||||||
|  |                   ), | ||||||
|                   const SizedBox( |                   const SizedBox( | ||||||
|                     height: 8, |                     height: 8, | ||||||
|                   ), |                   ), | ||||||
| @@ -244,9 +270,7 @@ class _HomeViewState extends State<HomeView> { | |||||||
|                     overflow: TextOverflow.ellipsis, |                     overflow: TextOverflow.ellipsis, | ||||||
|                     textAlign: TextAlign.center, |                     textAlign: TextAlign.center, | ||||||
|                     style: const TextStyle( |                     style: const TextStyle( | ||||||
|                       fontSize: 12, |                         fontSize: 12, fontWeight: FontWeight.w600), | ||||||
|                       fontWeight: FontWeight.w600 |  | ||||||
|                     ), |  | ||||||
|                   ) |                   ) | ||||||
|                 ], |                 ], | ||||||
|               ), |               ), | ||||||
| @@ -268,24 +292,27 @@ class _HomeViewState extends State<HomeView> { | |||||||
|       child: Column( |       child: Column( | ||||||
|         children: [ |         children: [ | ||||||
|           stepVerification(), |           stepVerification(), | ||||||
|           const SizedBox( |           if(listStepVerification.currentStep < 3) | ||||||
|             height: 24, |             const SizedBox( | ||||||
|           ), |               height: 24, | ||||||
|           if(listStepVerification.currentStep == 1)...[ |             ), | ||||||
|  |           if (listStepVerification.currentStep == 1) ...[ | ||||||
|             Row( |             Row( | ||||||
|               mainAxisAlignment: MainAxisAlignment.spaceBetween, |               mainAxisAlignment: MainAxisAlignment.spaceBetween, | ||||||
|               children: [ |               children: [ | ||||||
|                 const Row( |                 const Row( | ||||||
|                   children: [ |                   children: [ | ||||||
|                     Icon(Icons.verified, size: 18,), |                     Icon( | ||||||
|  |                       Icons.verified, | ||||||
|  |                       size: 18, | ||||||
|  |                       color: ColorPalette.slate300, | ||||||
|  |                     ), | ||||||
|                     SizedBox( |                     SizedBox( | ||||||
|                       width: 12, |                       width: 12, | ||||||
|                     ), |                     ), | ||||||
|                     Text( |                     Text( | ||||||
|                       'Verified by PT Gemilang', |                       'Verified by PT Gemilang', | ||||||
|                       style: TextStyle( |                       style: TextStyle(color: ColorPalette.slate500), | ||||||
|                           color: ColorPalette.slate500 |  | ||||||
|                       ), |  | ||||||
|                     ) |                     ) | ||||||
|                   ], |                   ], | ||||||
|                 ), |                 ), | ||||||
| @@ -294,9 +321,9 @@ class _HomeViewState extends State<HomeView> { | |||||||
|                   height: 16, |                   height: 16, | ||||||
|                   decoration: BoxDecoration( |                   decoration: BoxDecoration( | ||||||
|                       color: Colors.white, |                       color: Colors.white, | ||||||
|                       border: Border.all(color: const Color(0xffCBD5E1), width: 1.5), |                       border: Border.all( | ||||||
|                       shape: BoxShape.circle |                           color: const Color(0xffCBD5E1), width: 1.5), | ||||||
|                   ), |                       shape: BoxShape.circle), | ||||||
|                 ) |                 ) | ||||||
|               ], |               ], | ||||||
|             ), |             ), | ||||||
| @@ -309,15 +336,17 @@ class _HomeViewState extends State<HomeView> { | |||||||
|                 const Row( |                 const Row( | ||||||
|                   crossAxisAlignment: CrossAxisAlignment.end, |                   crossAxisAlignment: CrossAxisAlignment.end, | ||||||
|                   children: [ |                   children: [ | ||||||
|                     Icon(Icons.verified, size: 18,), |                     Icon( | ||||||
|  |                       Icons.verified, | ||||||
|  |                       size: 18, | ||||||
|  |                       color: ColorPalette.slate300, | ||||||
|  |                     ), | ||||||
|                     SizedBox( |                     SizedBox( | ||||||
|                       width: 12, |                       width: 12, | ||||||
|                     ), |                     ), | ||||||
|                     Text( |                     Text( | ||||||
|                       'Verified by KSEI', |                       'Verified by KSEI', | ||||||
|                       style: TextStyle( |                       style: TextStyle(color: ColorPalette.slate500), | ||||||
|                           color: ColorPalette.slate500 |  | ||||||
|                       ), |  | ||||||
|                     ) |                     ) | ||||||
|                   ], |                   ], | ||||||
|                 ), |                 ), | ||||||
| @@ -326,9 +355,9 @@ class _HomeViewState extends State<HomeView> { | |||||||
|                   height: 16, |                   height: 16, | ||||||
|                   decoration: BoxDecoration( |                   decoration: BoxDecoration( | ||||||
|                       color: Colors.white, |                       color: Colors.white, | ||||||
|                       border: Border.all(color: const Color(0xffCBD5E1), width: 1.5), |                       border: Border.all( | ||||||
|                       shape: BoxShape.circle |                           color: const Color(0xffCBD5E1), width: 1.5), | ||||||
|                   ), |                       shape: BoxShape.circle), | ||||||
|                 ) |                 ) | ||||||
|               ], |               ], | ||||||
|             ), |             ), | ||||||
| @@ -339,15 +368,12 @@ class _HomeViewState extends State<HomeView> { | |||||||
|               padding: const EdgeInsets.all(12), |               padding: const EdgeInsets.all(12), | ||||||
|               decoration: BoxDecoration( |               decoration: BoxDecoration( | ||||||
|                   color: ColorPalette.blue50, |                   color: ColorPalette.blue50, | ||||||
|                   borderRadius: BorderRadius.circular(12) |                   borderRadius: BorderRadius.circular(12)), | ||||||
|               ), |  | ||||||
|               child: const Column( |               child: const Column( | ||||||
|                 children: [ |                 children: [ | ||||||
|                   Text( |                   Text( | ||||||
|                     'Your registration is currently being verified by PT Gemilang', |                     'Your registration is currently being verified by PT Gemilang', | ||||||
|                     style: TextStyle( |                     style: TextStyle(color: ColorPalette.slate500), | ||||||
|                         color: ColorPalette.slate500 |  | ||||||
|                     ), |  | ||||||
|                   ), |                   ), | ||||||
|                   SizedBox( |                   SizedBox( | ||||||
|                     height: 16, |                     height: 16, | ||||||
| @@ -355,39 +381,34 @@ class _HomeViewState extends State<HomeView> { | |||||||
|                   Row( |                   Row( | ||||||
|                     mainAxisAlignment: MainAxisAlignment.spaceBetween, |                     mainAxisAlignment: MainAxisAlignment.spaceBetween, | ||||||
|                     children: [ |                     children: [ | ||||||
|                       Text('Estimated:', |                       Text( | ||||||
|                         style: TextStyle( |                         'Estimated:', | ||||||
|                             color: ColorPalette.slate500 |                         style: TextStyle(color: ColorPalette.slate500), | ||||||
|                         ), |  | ||||||
|                       ), |                       ), | ||||||
|                       Text( |                       Text( | ||||||
|                         'January 30 2024', |                         'January 30 2024', | ||||||
|                         style: TextStyle( |                         style: TextStyle( | ||||||
|                             fontWeight: FontWeight.w600, |                             fontWeight: FontWeight.w600, | ||||||
|                             color: Color(0xff1E293B) |                             color: Color(0xff1E293B)), | ||||||
|                         ), |  | ||||||
|                       ) |                       ) | ||||||
|                     ], |                     ], | ||||||
|                   ) |                   ) | ||||||
|                 ], |                 ], | ||||||
|               ), |               ), | ||||||
|             ) |             ) | ||||||
|           ]else if(listStepVerification.currentStep == 0)...[ |           ] else if (listStepVerification.currentStep == 0) ...[ | ||||||
|             Container( |             Container( | ||||||
|               padding: const EdgeInsets.all(12), |               padding: const EdgeInsets.all(12), | ||||||
|               decoration: BoxDecoration( |               decoration: BoxDecoration( | ||||||
|                   color: ColorPalette.blue50, |                   color: ColorPalette.blue50, | ||||||
|                   borderRadius: BorderRadius.circular(12) |                   borderRadius: BorderRadius.circular(12)), | ||||||
|               ), |  | ||||||
|               child: Column( |               child: Column( | ||||||
|                 children: [ |                 children: [ | ||||||
|                   Text( |                   const Text( | ||||||
|                     "Let's start registering your data to start mutual fund investment at PT Gemilang Indonesia", |                     "Let's start registering your data to start mutual fund investment at PT Gemilang Indonesia", | ||||||
|                     style: TextStyle( |                     style: TextStyle(color: ColorPalette.slate500), | ||||||
|                         color: ColorPalette.slate500 |  | ||||||
|                     ), |  | ||||||
|                   ), |                   ), | ||||||
|                   SizedBox( |                   const SizedBox( | ||||||
|                     height: 16, |                     height: 16, | ||||||
|                   ), |                   ), | ||||||
|                   ButtonView( |                   ButtonView( | ||||||
| @@ -395,9 +416,9 @@ class _HomeViewState extends State<HomeView> { | |||||||
|                     width: SizeConfig.width, |                     width: SizeConfig.width, | ||||||
|                     marginVertical: 0, |                     marginVertical: 0, | ||||||
|                     heightWrapContent: true, |                     heightWrapContent: true, | ||||||
|                     contentPadding: EdgeInsets.all(12), |                     contentPadding: const EdgeInsets.all(12), | ||||||
|                     onPressed: () { |                     onPressed: () { | ||||||
|                       routePush(context, page: InitialRegistrationStep()); |                       routePush(context, page: const InitialRegistrationStep()); | ||||||
|                     }, |                     }, | ||||||
|                   ) |                   ) | ||||||
|                 ], |                 ], | ||||||
| @@ -412,40 +433,61 @@ class _HomeViewState extends State<HomeView> { | |||||||
|   Widget stepVerification() { |   Widget stepVerification() { | ||||||
|     return Row( |     return Row( | ||||||
|       mainAxisAlignment: MainAxisAlignment.spaceBetween, |       mainAxisAlignment: MainAxisAlignment.spaceBetween, | ||||||
|       children: listStepVerification.nameStep.asMap().entries.map((e) { |       crossAxisAlignment: CrossAxisAlignment.start, | ||||||
|         return Row( |       children: List.generate( | ||||||
|           crossAxisAlignment: CrossAxisAlignment.start, |         listStepVerification.nameStep.length, | ||||||
|           children: [ |             (index) { | ||||||
|             if(e.key != 0) |           print(index % 2); | ||||||
|               SizedBox( |           if (index % 2 == 0) { | ||||||
|                 width: 30, |             final currentStep = index ~/ 2; | ||||||
|                 height: 30, |             return Column( | ||||||
|                 child: Divider(color: listStepVerification.currentStep >= e.key ? const Color(0xff2563EB) : const Color(0xffCBD5E1),), |  | ||||||
|               ), |  | ||||||
|             Column( |  | ||||||
|               children: [ |               children: [ | ||||||
|                 Container( |                 Container( | ||||||
|                   width: 30, |                   width: 30, | ||||||
|                   height: 30, |                   height: 30, | ||||||
|                   decoration: BoxDecoration( |                   decoration: BoxDecoration( | ||||||
|                       shape: BoxShape.circle, |                     shape: BoxShape.circle, | ||||||
|                       color: listStepVerification.currentStep <= e.key ? Colors.white : const Color(0xff2563EB), |                     color: listStepVerification.currentStep <= currentStep | ||||||
|                       border: Border.all( |                         ? Colors.white | ||||||
|                           color: listStepVerification.currentStep < e.key ? const Color(0xffCBD5E1) : const Color(0xff2563EB), |                         : const Color(0xff2563EB), | ||||||
|                           width: 2 |                     border: Border.all( | ||||||
|                       ) |                       color: listStepVerification.currentStep < currentStep | ||||||
|  |                           ? const Color(0xffCBD5E1) | ||||||
|  |                           : const Color(0xff2563EB), | ||||||
|  |                       width: 2, | ||||||
|  |                     ), | ||||||
|  |                   ), | ||||||
|  |                   child: listStepVerification.currentStep <= currentStep | ||||||
|  |                       ? const SizedBox() | ||||||
|  |                       : const Icon( | ||||||
|  |                     Icons.done_rounded, | ||||||
|  |                     color: Colors.white, | ||||||
|                   ), |                   ), | ||||||
|                   child: listStepVerification.currentStep <= e.key ? const SizedBox() : const Icon(Icons.done_rounded, color: Colors.white,), |  | ||||||
|                 ), |                 ), | ||||||
|                 const SizedBox( |                 const SizedBox(height: 8), | ||||||
|                   height: 8, |                 Text( | ||||||
|  |                   listStepVerification.nameStep[index], | ||||||
|  |                   style: TextStyle( | ||||||
|  |                     color: listStepVerification.currentStep == currentStep | ||||||
|  |                         ? const Color(0xff2563EB) | ||||||
|  |                         : Colors.black, | ||||||
|  |                   ), | ||||||
|                 ), |                 ), | ||||||
|                 Text(e.value, style: TextStyle(color: listStepVerification.currentStep == e.key ? const Color(0xff2563EB) : Colors.black),) |  | ||||||
|               ], |               ], | ||||||
|             ), |             ); | ||||||
|           ], |           } else { | ||||||
|         ); |             return SizedBox( | ||||||
|       }).toList(), |               width: 30, | ||||||
|  |               height: 30, | ||||||
|  |               child: Divider( | ||||||
|  |                 color: listStepVerification.currentStep > index ~/ 2 | ||||||
|  |                     ? const Color(0xff2563EB) | ||||||
|  |                     : const Color(0xffCBD5E1), | ||||||
|  |               ), | ||||||
|  |             ); | ||||||
|  |           } | ||||||
|  |         }, | ||||||
|  |       ), | ||||||
|     ); |     ); | ||||||
|   } |   } | ||||||
|  |  | ||||||
| @@ -455,15 +497,22 @@ class _HomeViewState extends State<HomeView> { | |||||||
|       child: Column( |       child: Column( | ||||||
|         crossAxisAlignment: CrossAxisAlignment.start, |         crossAxisAlignment: CrossAxisAlignment.start, | ||||||
|         children: [ |         children: [ | ||||||
|           const TextTitle(title: 'Info and Special Promo', color: ColorPalette.slate800,), |           const TextTitle( | ||||||
|  |             title: 'Info and Special Promo', | ||||||
|  |             color: ColorPalette.slate800, | ||||||
|  |           ), | ||||||
|           const SizedBox( |           const SizedBox( | ||||||
|             height: 16, |             height: 16, | ||||||
|           ), |           ), | ||||||
|           CarouselSlider( |           CarouselSlider( | ||||||
|             items: [1,2,3].map((e) { |             items: [1, 2, 3].map((e) { | ||||||
|               return Padding( |               return Padding( | ||||||
|                 padding: const EdgeInsets.symmetric(horizontal: 8), |                 padding: const EdgeInsets.symmetric(horizontal: 8), | ||||||
|                 child: ImageView(image: PathAssets.imgCarousel, height: 150, width: SizeConfig.width * .9,), |                 child: ImageView( | ||||||
|  |                   image: PathAssets.imgCarousel, | ||||||
|  |                   height: 150, | ||||||
|  |                   width: SizeConfig.width * .9, | ||||||
|  |                 ), | ||||||
|               ); |               ); | ||||||
|             }).toList(), |             }).toList(), | ||||||
|             options: CarouselOptions( |             options: CarouselOptions( | ||||||
| @@ -493,14 +542,13 @@ class _HomeViewState extends State<HomeView> { | |||||||
|               children: [ |               children: [ | ||||||
|                 const TextTitle(title: 'Article', color: ColorPalette.slate800), |                 const TextTitle(title: 'Article', color: ColorPalette.slate800), | ||||||
|                 GestureDetector( |                 GestureDetector( | ||||||
|                   onTap: () { |                   onTap: () {}, | ||||||
|  |                   child: const Text( | ||||||
|                   }, |                     'See More', | ||||||
|                   child: const Text('See More', |  | ||||||
|                     style: TextStyle( |                     style: TextStyle( | ||||||
|                       color: ColorPalette.primary, |                         color: ColorPalette.primary, | ||||||
|                       fontWeight: FontWeight.bold |                         fontWeight: FontWeight.bold), | ||||||
|                     ),), |                   ), | ||||||
|                 ) |                 ) | ||||||
|               ], |               ], | ||||||
|             ), |             ), | ||||||
| @@ -511,10 +559,12 @@ class _HomeViewState extends State<HomeView> { | |||||||
|           ...listArticle.asMap().entries.map((e) { |           ...listArticle.asMap().entries.map((e) { | ||||||
|             return Column( |             return Column( | ||||||
|               children: [ |               children: [ | ||||||
|                 if(e.key != 0)...[ |                 if (e.key != 0) ...[ | ||||||
|                   const Padding( |                   const Padding( | ||||||
|                     padding: EdgeInsets.symmetric(vertical: 12), |                     padding: EdgeInsets.symmetric(vertical: 12), | ||||||
|                     child: Divider(color: ColorPalette.slate200,), |                     child: Divider( | ||||||
|  |                       color: ColorPalette.slate200, | ||||||
|  |                     ), | ||||||
|                   ) |                   ) | ||||||
|                 ], |                 ], | ||||||
|                 cardArticle(e.value), |                 cardArticle(e.value), | ||||||
| @@ -531,39 +581,43 @@ class _HomeViewState extends State<HomeView> { | |||||||
|       padding: const EdgeInsets.symmetric(horizontal: 24), |       padding: const EdgeInsets.symmetric(horizontal: 24), | ||||||
|       child: Row( |       child: Row( | ||||||
|         children: [ |         children: [ | ||||||
|           ImageView(image: PathAssets.imgArticles, width: SizeConfig.width * .17, height: SizeConfig.height * .08, borderRadius: 8,), |           ImageView( | ||||||
|  |             image: PathAssets.imgArticles, | ||||||
|  |             width: SizeConfig.width * .17, | ||||||
|  |             height: SizeConfig.height * .08, | ||||||
|  |             borderRadius: 8, | ||||||
|  |           ), | ||||||
|           const SizedBox( |           const SizedBox( | ||||||
|             width: 16, |             width: 16, | ||||||
|           ), |           ), | ||||||
|           Expanded( |           Expanded( | ||||||
|             child: Column( |               child: Column( | ||||||
|               crossAxisAlignment: CrossAxisAlignment.start, |             crossAxisAlignment: CrossAxisAlignment.start, | ||||||
|               children: [ |             children: [ | ||||||
|                 Text(article.title, |               Text( | ||||||
|                   style: const TextStyle( |                 article.title, | ||||||
|                     fontWeight: FontWeight.bold, |                 style: const TextStyle( | ||||||
|                   ), |                   fontWeight: FontWeight.bold, | ||||||
|                 ), |                 ), | ||||||
|                 const SizedBox( |               ), | ||||||
|                   height: 8, |               const SizedBox( | ||||||
|                 ), |                 height: 8, | ||||||
|                 Container( |               ), | ||||||
|                   padding: const EdgeInsets.symmetric(vertical: 4, horizontal: 12), |               Container( | ||||||
|                   decoration: BoxDecoration( |                 padding: | ||||||
|  |                     const EdgeInsets.symmetric(vertical: 4, horizontal: 12), | ||||||
|  |                 decoration: BoxDecoration( | ||||||
|                     borderRadius: BorderRadius.circular(30), |                     borderRadius: BorderRadius.circular(30), | ||||||
|                     color: ColorPalette.green100 |                     color: ColorPalette.green100), | ||||||
|                   ), |                 child: Text( | ||||||
|                   child: Text( |                   article.type, | ||||||
|                     article.type, |                   style: const TextStyle( | ||||||
|                     style: TextStyle( |  | ||||||
|                       fontWeight: FontWeight.w600, |                       fontWeight: FontWeight.w600, | ||||||
|                       color: ColorPalette.green500 |                       color: ColorPalette.green500), | ||||||
|                     ), |  | ||||||
|                   ), |  | ||||||
|                 ), |                 ), | ||||||
|               ], |               ), | ||||||
|             ) |             ], | ||||||
|           ) |           )) | ||||||
|         ], |         ], | ||||||
|       ), |       ), | ||||||
|     ); |     ); | ||||||
|   | |||||||
| @@ -20,11 +20,25 @@ class InvestTypeView extends StatefulWidget { | |||||||
| } | } | ||||||
|  |  | ||||||
| class _InvestTypeViewState extends State<InvestTypeView> { | class _InvestTypeViewState extends State<InvestTypeView> { | ||||||
|    |  | ||||||
|   List<Product> listProduct = [ |   List<Product> listProduct = [ | ||||||
|     Product(name: 'Gemilang Dana Kas Maxima', type: '', yield: 8.17, priceUnit: 2600.79, funds: 6300000), |     Product( | ||||||
|     Product(name: 'Gemilang Dana Likuid', type: '', yield: 6.42, priceUnit: 1600.79, funds: 2340000), |         name: 'Gemilang Dana Kas Maxima', | ||||||
|     Product(name: 'Gemilang Income Fund', type: '', yield: 8.17, priceUnit: 2600.79, funds: 6300000) |         type: '', | ||||||
|  |         yield: 8.17, | ||||||
|  |         priceUnit: 2600.79, | ||||||
|  |         funds: 6300000), | ||||||
|  |     Product( | ||||||
|  |         name: 'Gemilang Dana Likuid', | ||||||
|  |         type: '', | ||||||
|  |         yield: 6.42, | ||||||
|  |         priceUnit: 1600.79, | ||||||
|  |         funds: 2340000), | ||||||
|  |     Product( | ||||||
|  |         name: 'Gemilang Income Fund', | ||||||
|  |         type: '', | ||||||
|  |         yield: 8.17, | ||||||
|  |         priceUnit: 2600.79, | ||||||
|  |         funds: 6300000) | ||||||
|   ]; |   ]; | ||||||
|  |  | ||||||
|   @override |   @override | ||||||
| @@ -36,76 +50,80 @@ class _InvestTypeViewState extends State<InvestTypeView> { | |||||||
|       return e; |       return e; | ||||||
|     }).toList(); |     }).toList(); | ||||||
|   } |   } | ||||||
|    |  | ||||||
|   @override |   @override | ||||||
|   Widget build(BuildContext context) { |   Widget build(BuildContext context) { | ||||||
|     return ChangeNotifierProvider<ProductViewModel>( |     return ChangeNotifierProvider<ProductViewModel>( | ||||||
|       create: (context) => ProductViewModel(), |       create: (context) => ProductViewModel(), | ||||||
|       child: Consumer<ProductViewModel>( |       child: Consumer<ProductViewModel>(builder: (context, provider, child) { | ||||||
|         builder: (context, provider, child) { |         return Scaffold( | ||||||
|           return Scaffold( |           body: SizedBox( | ||||||
|             body: SizedBox( |             width: SizeConfig.width, | ||||||
|               width: SizeConfig.width, |             height: SizeConfig.height, | ||||||
|               height: SizeConfig.height, |             child: Stack( | ||||||
|               child: Stack( |               children: [ | ||||||
|                 children: [ |                 const ImageView(image: PathAssets.imgDashboardAccount), | ||||||
|                   const ImageView(image: PathAssets.imgDashboardAccount), |                 Column( | ||||||
|                   Column( |                   children: [ | ||||||
|                     children: [ |                     SizedBox( | ||||||
|                       const SizedBox( |                       height: SizeConfig.height * .1, | ||||||
|                         height: 50, |                     ), | ||||||
|  |                     Padding( | ||||||
|  |                       padding: const EdgeInsets.symmetric(horizontal: 24), | ||||||
|  |                       child: Row( | ||||||
|  |                         mainAxisAlignment: MainAxisAlignment.spaceBetween, | ||||||
|  |                         children: [ | ||||||
|  |                           const BackButtonView(), | ||||||
|  |                           TextTitle(title: widget.title, color: Colors.white), | ||||||
|  |                           SizedBox( | ||||||
|  |                             width: SizeConfig.width * 0.1, | ||||||
|  |                           ) | ||||||
|  |                         ], | ||||||
|                       ), |                       ), | ||||||
|                       Padding( |                     ), | ||||||
|                         padding: const EdgeInsets.symmetric(horizontal: 24), |                     const SizedBox( | ||||||
|                         child: Row( |                       height: 24, | ||||||
|                           mainAxisAlignment: MainAxisAlignment.spaceBetween, |                     ), | ||||||
|                           children: [ |                     Expanded( | ||||||
|                             const BackButtonView(), |                       child: Container( | ||||||
|                             TextTitle(title: widget.title, color: Colors.white), |  | ||||||
|                             SizedBox( |  | ||||||
|                               width: SizeConfig.width * 0.1, |  | ||||||
|                             ) |  | ||||||
|                           ], |  | ||||||
|                         ), |  | ||||||
|                       ), |  | ||||||
|                       const SizedBox( |  | ||||||
|                         height: 24, |  | ||||||
|                       ), |  | ||||||
|                       Container( |  | ||||||
|                         padding: const EdgeInsets.all(24), |                         padding: const EdgeInsets.all(24), | ||||||
|                         decoration: BoxDecoration( |                         decoration: BoxDecoration( | ||||||
|                           borderRadius: BorderRadius.circular(16), |                             borderRadius: BorderRadius.circular(16), | ||||||
|                           color: Colors.white |                             color: Colors.white), | ||||||
|                         ), |                         child: SingleChildScrollView( | ||||||
|                         child: Column( |                           scrollDirection: Axis.vertical, | ||||||
|                           children: [ |                           child: Column( | ||||||
|                             filters(), |                             children: [ | ||||||
|                             ListView( |                               filters(), | ||||||
|                               shrinkWrap: true, |                               ListView( | ||||||
|                               children: listProduct.asMap().entries.map((e) { |                                 shrinkWrap: true, | ||||||
|                                 return GestureDetector( |                                 children: listProduct.asMap().entries.map((e) { | ||||||
|                                   onTap: () { |                                   return GestureDetector( | ||||||
|                                     provider.setSelectedProduct(e.value); |                                     onTap: () { | ||||||
|                                     routePush(context, page: ProductView(widget.title)); |                                       provider.setSelectedProduct(e.value); | ||||||
|                                   }, |                                       routePush(context, | ||||||
|                                   child: Padding( |                                           page: ProductView(selectedProduct: e.value)); | ||||||
|                                     padding: EdgeInsets.only(top: e.key != 0 ? 24 : 0), |                                     }, | ||||||
|                                     child: cardProduct(e.value), |                                     child: Padding( | ||||||
|                                   ), |                                       padding: EdgeInsets.only( | ||||||
|                                 ); |                                           top: e.key != 0 ? 24 : 0), | ||||||
|                               }).toList(), |                                       child: cardProduct(e.value), | ||||||
|                             ) |                                     ), | ||||||
|                           ], |                                   ); | ||||||
|  |                                 }).toList(), | ||||||
|  |                               ) | ||||||
|  |                             ], | ||||||
|  |                           ), | ||||||
|                         ), |                         ), | ||||||
|                       ), |                       ), | ||||||
|                     ], |                     ), | ||||||
|                   ) |                   ], | ||||||
|                 ], |                 ) | ||||||
|               ), |               ], | ||||||
|             ), |             ), | ||||||
|           ); |           ), | ||||||
|         } |         ); | ||||||
|       ), |       }), | ||||||
|     ); |     ); | ||||||
|   } |   } | ||||||
|  |  | ||||||
| @@ -115,9 +133,25 @@ class _InvestTypeViewState extends State<InvestTypeView> { | |||||||
|       child: Row( |       child: Row( | ||||||
|         mainAxisAlignment: MainAxisAlignment.spaceBetween, |         mainAxisAlignment: MainAxisAlignment.spaceBetween, | ||||||
|         children: [ |         children: [ | ||||||
|           segmentFilter(const Icon(Icons.filter_alt_outlined, color: ColorPalette.slate400,), 'Filter', () { }), |           segmentFilter( | ||||||
|           segmentFilter(const RotatedBox(quarterTurns: 1, child: Icon(Icons.compare_arrows, color: ColorPalette.slate400)), 'Sort', () { }), |               const Icon( | ||||||
|           segmentFilter(const Icon(Icons.dashboard_outlined, color: ColorPalette.slate400), 'Compare', () { }), |                 Icons.filter_alt_outlined, | ||||||
|  |                 color: ColorPalette.slate400, | ||||||
|  |               ), | ||||||
|  |               'Filter', | ||||||
|  |               () {}), | ||||||
|  |           segmentFilter( | ||||||
|  |               const RotatedBox( | ||||||
|  |                   quarterTurns: 1, | ||||||
|  |                   child: | ||||||
|  |                       Icon(Icons.compare_arrows, color: ColorPalette.slate400)), | ||||||
|  |               'Sort', | ||||||
|  |               () {}), | ||||||
|  |           segmentFilter( | ||||||
|  |               const Icon(Icons.dashboard_outlined, | ||||||
|  |                   color: ColorPalette.slate400), | ||||||
|  |               'Compare', | ||||||
|  |               () {}), | ||||||
|         ], |         ], | ||||||
|       ), |       ), | ||||||
|     ); |     ); | ||||||
| @@ -126,12 +160,11 @@ class _InvestTypeViewState extends State<InvestTypeView> { | |||||||
|   Widget segmentFilter(Widget leading, String text, void Function()? onTap) { |   Widget segmentFilter(Widget leading, String text, void Function()? onTap) { | ||||||
|     return GestureDetector( |     return GestureDetector( | ||||||
|       onTap: onTap, |       onTap: onTap, | ||||||
|       child:  Container( |       child: Container( | ||||||
|         padding: const EdgeInsets.symmetric(vertical: 8, horizontal: 16), |         padding: const EdgeInsets.symmetric(vertical: 8, horizontal: 16), | ||||||
|         decoration: BoxDecoration( |         decoration: BoxDecoration( | ||||||
|             border: Border.all(color: ColorPalette.slate200), |             border: Border.all(color: ColorPalette.slate200), | ||||||
|             borderRadius: BorderRadius.circular(56) |             borderRadius: BorderRadius.circular(56)), | ||||||
|         ), |  | ||||||
|         child: Row( |         child: Row( | ||||||
|           children: [ |           children: [ | ||||||
|             leading, |             leading, | ||||||
| @@ -142,9 +175,7 @@ class _InvestTypeViewState extends State<InvestTypeView> { | |||||||
|               text, |               text, | ||||||
|               overflow: TextOverflow.ellipsis, |               overflow: TextOverflow.ellipsis, | ||||||
|               style: const TextStyle( |               style: const TextStyle( | ||||||
|                 color: ColorPalette.slate500, |                   color: ColorPalette.slate500, fontWeight: FontWeight.w700), | ||||||
|                 fontWeight: FontWeight.w700 |  | ||||||
|               ), |  | ||||||
|             ) |             ) | ||||||
|           ], |           ], | ||||||
|         ), |         ), | ||||||
| @@ -163,7 +194,10 @@ class _InvestTypeViewState extends State<InvestTypeView> { | |||||||
|         children: [ |         children: [ | ||||||
|           Row( |           Row( | ||||||
|             children: [ |             children: [ | ||||||
|               ImageView(image: PathAssets.imgProduct, width: SizeConfig.width * .12,), |               ImageView( | ||||||
|  |                 image: PathAssets.imgProduct, | ||||||
|  |                 width: SizeConfig.width * .12, | ||||||
|  |               ), | ||||||
|               const SizedBox( |               const SizedBox( | ||||||
|                 width: 8, |                 width: 8, | ||||||
|               ), |               ), | ||||||
| @@ -171,9 +205,7 @@ class _InvestTypeViewState extends State<InvestTypeView> { | |||||||
|                 child: Text( |                 child: Text( | ||||||
|                   product.name ?? '', |                   product.name ?? '', | ||||||
|                   style: const TextStyle( |                   style: const TextStyle( | ||||||
|                     fontWeight: FontWeight.bold, |                       fontWeight: FontWeight.bold, fontSize: 18), | ||||||
|                     fontSize: 18 |  | ||||||
|                   ), |  | ||||||
|                 ), |                 ), | ||||||
|               ) |               ) | ||||||
|             ], |             ], | ||||||
| @@ -187,36 +219,53 @@ class _InvestTypeViewState extends State<InvestTypeView> { | |||||||
|             children: [ |             children: [ | ||||||
|               Column( |               Column( | ||||||
|                 children: [ |                 children: [ | ||||||
|                   const Text('Yield', style: TextStyle(color: ColorPalette.slate400, fontWeight: FontWeight.w600),), |                   const Text( | ||||||
|  |                     'Yield', | ||||||
|  |                     style: TextStyle( | ||||||
|  |                         color: ColorPalette.slate400, | ||||||
|  |                         fontWeight: FontWeight.w600), | ||||||
|  |                   ), | ||||||
|                   Row( |                   Row( | ||||||
|                     children: [ |                     children: [ | ||||||
|                       Text( |                       Text( | ||||||
|                         '${product.yield.toString()}%', |                         '${product.yield.toString()}%', | ||||||
|                         style: const TextStyle( |                         style: const TextStyle( | ||||||
|                           color: ColorPalette.green400, |                             color: ColorPalette.green400, | ||||||
|                           fontWeight: FontWeight.w600 |                             fontWeight: FontWeight.w600), | ||||||
|                         ), |  | ||||||
|                       ), |                       ), | ||||||
|                       const Text('/'), |                       const Text('/'), | ||||||
|                       const Text('3year', style: TextStyle(color: ColorPalette.slate400, fontWeight: FontWeight.w600),) |                       const Text( | ||||||
|  |                         '3year', | ||||||
|  |                         style: TextStyle( | ||||||
|  |                             color: ColorPalette.slate400, | ||||||
|  |                             fontWeight: FontWeight.w600), | ||||||
|  |                       ) | ||||||
|                     ], |                     ], | ||||||
|                   ) |                   ) | ||||||
|                 ], |                 ], | ||||||
|               ), |               ), | ||||||
|               Column( |               Column( | ||||||
|                 children: [ |                 children: [ | ||||||
|                   const Text('Price/unit', style: TextStyle(color: ColorPalette.slate400, fontWeight: FontWeight.w600),), |                   const Text( | ||||||
|  |                     'Price/unit', | ||||||
|  |                     style: TextStyle( | ||||||
|  |                         color: ColorPalette.slate400, | ||||||
|  |                         fontWeight: FontWeight.w600), | ||||||
|  |                   ), | ||||||
|                   Row( |                   Row( | ||||||
|                     children: [ |                     children: [ | ||||||
|                       const Icon(Icons.trending_up_outlined, size: 18, color: ColorPalette.green400,), |                       const Icon( | ||||||
|  |                         Icons.trending_up_outlined, | ||||||
|  |                         size: 18, | ||||||
|  |                         color: ColorPalette.green400, | ||||||
|  |                       ), | ||||||
|                       const SizedBox( |                       const SizedBox( | ||||||
|                         width: 2, |                         width: 2, | ||||||
|                       ), |                       ), | ||||||
|                       Text( |                       Text( | ||||||
|                         NumberFormatter.numberCurrency(product.priceUnit, 'Rp', 'id_ID'), |                         NumberFormatter.numberCurrency( | ||||||
|                         style: const TextStyle( |                             product.priceUnit, 'Rp', 'id_ID'), | ||||||
|                           fontWeight: FontWeight.w600 |                         style: const TextStyle(fontWeight: FontWeight.w600), | ||||||
|                         ), |  | ||||||
|                       ), |                       ), | ||||||
|                     ], |                     ], | ||||||
|                   ) |                   ) | ||||||
| @@ -224,14 +273,18 @@ class _InvestTypeViewState extends State<InvestTypeView> { | |||||||
|               ), |               ), | ||||||
|               Column( |               Column( | ||||||
|                 children: [ |                 children: [ | ||||||
|                   const Text('Managed funds', style: TextStyle(color: ColorPalette.slate400, fontWeight: FontWeight.w600),), |                   const Text( | ||||||
|  |                     'Managed funds', | ||||||
|  |                     style: TextStyle( | ||||||
|  |                         color: ColorPalette.slate400, | ||||||
|  |                         fontWeight: FontWeight.w600), | ||||||
|  |                   ), | ||||||
|                   Row( |                   Row( | ||||||
|                     children: [ |                     children: [ | ||||||
|                       Text( |                       Text( | ||||||
|                         NumberFormatter.compactCurrency(product.funds, 'Rp ', 'id_ID'), |                         NumberFormatter.compactCurrency( | ||||||
|                         style: const TextStyle( |                             product.funds, 'Rp ', 'id_ID'), | ||||||
|                             fontWeight: FontWeight.w600 |                         style: const TextStyle(fontWeight: FontWeight.w600), | ||||||
|                         ), |  | ||||||
|                       ), |                       ), | ||||||
|                     ], |                     ], | ||||||
|                   ) |                   ) | ||||||
| @@ -243,5 +296,4 @@ class _InvestTypeViewState extends State<InvestTypeView> { | |||||||
|       ), |       ), | ||||||
|     ); |     ); | ||||||
|   } |   } | ||||||
|  |  | ||||||
| } | } | ||||||
|   | |||||||
| @@ -1,12 +1,8 @@ | |||||||
| import 'package:cims_apps/application/component/button/button_view.dart'; |  | ||||||
| import 'package:cims_apps/application/component/custom_app_bar/custom_app_bar.dart'; | import 'package:cims_apps/application/component/custom_app_bar/custom_app_bar.dart'; | ||||||
| import 'package:cims_apps/application/component/subscribe/goal_investing_view.dart'; | import 'package:cims_apps/application/component/subscribe/goal_investing_view.dart'; | ||||||
| import 'package:cims_apps/application/component/subscribe/input_investment_view.dart'; | import 'package:cims_apps/application/component/subscribe/input_investment_view.dart'; | ||||||
| import 'package:cims_apps/application/component/numeric_pad/numeric_pad.dart'; |  | ||||||
| import 'package:cims_apps/application/component/risk_profile.dart'; | import 'package:cims_apps/application/component/risk_profile.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/application/theme/color_palette.dart'; | ||||||
| import 'package:cims_apps/core/utils/number_formatter.dart'; |  | ||||||
| import 'package:cims_apps/core/utils/size_config.dart'; | import 'package:cims_apps/core/utils/size_config.dart'; | ||||||
| import 'package:cims_apps/features/dashboard/dashboard_account/view/plan/view/step_invest_plan/options_starting_invest.dart'; | import 'package:cims_apps/features/dashboard/dashboard_account/view/plan/view/step_invest_plan/options_starting_invest.dart'; | ||||||
| import 'package:cims_apps/features/dashboard/dashboard_account/view/plan/view_model/plan_view_model.dart'; | import 'package:cims_apps/features/dashboard/dashboard_account/view/plan/view_model/plan_view_model.dart'; | ||||||
| @@ -40,42 +36,49 @@ class _PlanViewState extends State<PlanView> { | |||||||
|   @override |   @override | ||||||
|   Widget build(BuildContext context) { |   Widget build(BuildContext context) { | ||||||
|  |  | ||||||
|     return Scaffold( |     return ChangeNotifierProvider( | ||||||
|       appBar: CustomAppBar(height: 70, title: 'Investment Plan'), |       create: (context) => PlanViewModel(), | ||||||
|       body: SingleChildScrollView( |       child: Scaffold( | ||||||
|         padding: EdgeInsets.all(24), |         appBar: CustomAppBar( | ||||||
|         child: Column( |           height: SizeConfig.height * 0.08, | ||||||
|           crossAxisAlignment: CrossAxisAlignment.start, |           title: 'Investment Plan', | ||||||
|           children: [ |           leading: const SizedBox(), | ||||||
|             RiskProfile( |         ), | ||||||
|               totalScore: 26, |         body: SingleChildScrollView( | ||||||
|               rowSuitableProduct: true |           padding: const EdgeInsets.all(24), | ||||||
|             ), |           child: Column( | ||||||
|             SizedBox( |             crossAxisAlignment: CrossAxisAlignment.start, | ||||||
|               height: 32, |             children: [ | ||||||
|             ), |               const RiskProfile( | ||||||
|             Text('Your Goal in Investing', |                 totalScore: 26, | ||||||
|               style: TextStyle( |                 rowSuitableProduct: true | ||||||
|                 fontWeight: FontWeight.w700, |  | ||||||
|                 color: ColorPalette.slate800, |  | ||||||
|                 fontSize: 18 |  | ||||||
|               ), |               ), | ||||||
|             ), |               const SizedBox( | ||||||
|             SizedBox( |                 height: 32, | ||||||
|               height: 24, |               ), | ||||||
|             ), |               const Text('Your Goal in Investing', | ||||||
|             GoalInvestingView( |                 style: TextStyle( | ||||||
|               onListSelected: (p0) { |                   fontWeight: FontWeight.w700, | ||||||
|                 showModalBottomSheet( |                   color: ColorPalette.slate800, | ||||||
|                   context: context, |                   fontSize: 18 | ||||||
|                   isScrollControlled: true, |                 ), | ||||||
|                   builder: (context) { |               ), | ||||||
|                     return modalInvest(context, p0); |               const SizedBox( | ||||||
|                   }, |                 height: 24, | ||||||
|                 ); |               ), | ||||||
|               }, |               GoalInvestingView( | ||||||
|             ) |                 onListSelected: (p0) { | ||||||
|           ], |                   showModalBottomSheet( | ||||||
|  |                     context: context, | ||||||
|  |                     isScrollControlled: true, | ||||||
|  |                     builder: (context) { | ||||||
|  |                       return modalInvest(context, p0); | ||||||
|  |                     }, | ||||||
|  |                   ); | ||||||
|  |                 }, | ||||||
|  |               ) | ||||||
|  |             ], | ||||||
|  |           ), | ||||||
|         ), |         ), | ||||||
|       ), |       ), | ||||||
|     ); |     ); | ||||||
| @@ -95,7 +98,7 @@ class _PlanViewState extends State<PlanView> { | |||||||
|             child: Row( |             child: Row( | ||||||
|               mainAxisAlignment: MainAxisAlignment.spaceBetween, |               mainAxisAlignment: MainAxisAlignment.spaceBetween, | ||||||
|               children: [ |               children: [ | ||||||
|                 Text("It's time to invest", |                 const Text("It's time to invest", | ||||||
|                   style: TextStyle( |                   style: TextStyle( | ||||||
|                     fontSize: 16, |                     fontSize: 16, | ||||||
|                     fontWeight: FontWeight.w600 |                     fontWeight: FontWeight.w600 | ||||||
| @@ -105,17 +108,20 @@ class _PlanViewState extends State<PlanView> { | |||||||
|                   onTap: () { |                   onTap: () { | ||||||
|                     Navigator.pop(context); |                     Navigator.pop(context); | ||||||
|                   }, |                   }, | ||||||
|                   child: Icon(Icons.close_rounded) |                   child: const Icon(Icons.close_rounded) | ||||||
|                 ) |                 ) | ||||||
|               ], |               ], | ||||||
|             ), |             ), | ||||||
|           ), |           ), | ||||||
|           Divider(color: ColorPalette.slate200, height: 1), |           const Divider(color: ColorPalette.slate200, height: 1), | ||||||
|           InputInvestmentView( |           InputInvestmentView( | ||||||
|             selectedPlan: text, |             currentPlan: text, | ||||||
|  |             changePlan: () { | ||||||
|  |               Navigator.pop(context); | ||||||
|  |             }, | ||||||
|             nextMove: (value) { |             nextMove: (value) { | ||||||
|               Navigator.pop(context); |               Navigator.pop(context); | ||||||
|               int formatIntParse = int.parse(value.replaceAll('Rp ', '').replaceAll(',', '')); |               int formatIntParse = int.parse(value.replaceAll('Rp ', '').replaceAll('.', '')); | ||||||
|               showModalBottomSheet(context: context, builder: (context) => OptionsStartingInvest(totalInvest: formatIntParse)); |               showModalBottomSheet(context: context, builder: (context) => OptionsStartingInvest(totalInvest: formatIntParse)); | ||||||
|             }, |             }, | ||||||
|           ), |           ), | ||||||
|   | |||||||
| @@ -3,9 +3,14 @@ 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/image/image_view.dart'; | ||||||
| import 'package:cims_apps/application/component/subscribe/total_payment_view.dart'; | import 'package:cims_apps/application/component/subscribe/total_payment_view.dart'; | ||||||
| import 'package:cims_apps/application/theme/color_palette.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/core/utils/size_config.dart'; | ||||||
|  | import 'package:cims_apps/features/dashboard/dashboard_account/view/plan/view/step_invest_plan/options_starting_invest.dart'; | ||||||
|  | import 'package:cims_apps/features/dashboard/dashboard_account/view/plan/view_model/plan_view_model.dart'; | ||||||
|  | import 'package:cims_apps/features/dashboard/dashboard_account/view/product/view/product_view.dart'; | ||||||
| import 'package:cims_apps/features/dashboard/dashboard_account/view/product/view_model/product_view_model.dart'; | import 'package:cims_apps/features/dashboard/dashboard_account/view/product/view_model/product_view_model.dart'; | ||||||
| import 'package:flutter/material.dart'; | import 'package:flutter/material.dart'; | ||||||
|  | import 'package:provider/provider.dart'; | ||||||
|  |  | ||||||
| class ResultOptionsProduct extends StatelessWidget { | class ResultOptionsProduct extends StatelessWidget { | ||||||
|   final int totalInvest; |   final int totalInvest; | ||||||
| @@ -19,134 +24,169 @@ class ResultOptionsProduct extends StatelessWidget { | |||||||
|       Product(name: 'Gemilang Kas 2 Kelas A', type: 'Shares', totalPercent: 0.1) |       Product(name: 'Gemilang Kas 2 Kelas A', type: 'Shares', totalPercent: 0.1) | ||||||
|     ]; |     ]; | ||||||
|  |  | ||||||
|     return Container( |     return ChangeNotifierProvider( | ||||||
|       decoration: BoxDecoration( |       create: (context) => PlanViewModel(), | ||||||
|         color: Colors.white, |       child: Consumer<PlanViewModel>( | ||||||
|         borderRadius: BorderRadius.circular(16) |         builder: (context, provider, child) { | ||||||
|       ), |           return Container( | ||||||
|       padding: const EdgeInsets.all(24), |             decoration: BoxDecoration( | ||||||
|       child: Column( |               color: Colors.white, | ||||||
|         mainAxisSize: MainAxisSize.min, |               borderRadius: BorderRadius.circular(16) | ||||||
|         children: [ |             ), | ||||||
|           const Row( |             padding: const EdgeInsets.all(24), | ||||||
|             mainAxisAlignment: MainAxisAlignment.spaceBetween, |  | ||||||
|             children: [ |  | ||||||
|               Icon(Icons.arrow_back, color: ColorPalette.slate500), |  | ||||||
|               Text('Results from your risk profile', |  | ||||||
|                 style: TextStyle( |  | ||||||
|                   fontWeight: FontWeight.w600, |  | ||||||
|                   fontSize: 18, |  | ||||||
|                   color: ColorPalette.slate800 |  | ||||||
|                 ), |  | ||||||
|               ), |  | ||||||
|               Icon(Icons.close_rounded, color: ColorPalette.slate400) |  | ||||||
|             ], |  | ||||||
|           ), |  | ||||||
|           const SizedBox(height: 32), |  | ||||||
|           SingleChildScrollView( |  | ||||||
|             child: Column( |             child: Column( | ||||||
|               children: listProduct.asMap().entries.map((e) { |               mainAxisSize: MainAxisSize.min, | ||||||
|                 return Container( |               children: [ | ||||||
|                   margin: const EdgeInsets.only(bottom: 16), |                 Row( | ||||||
|                   padding: const EdgeInsets.all(16), |                   mainAxisAlignment: MainAxisAlignment.spaceBetween, | ||||||
|                   decoration: BoxDecoration( |                   children: [ | ||||||
|                       color: Colors.white, |                     GestureDetector( | ||||||
|                       border: Border.all(color: ColorPalette.slate200), |                         onTap: () { | ||||||
|                       borderRadius: BorderRadius.circular(12), |                           Navigator.pop(context); | ||||||
|                       boxShadow: const [ |                           showModalBottomSheet( | ||||||
|                         BoxShadow( |                             context: context, | ||||||
|                             color: Color(0XFF1E293B0A) |                             builder: (context) { | ||||||
|                         ) |                               return OptionsStartingInvest(totalInvest: totalInvest); | ||||||
|                       ] |                             }, | ||||||
|                   ), |                           ); | ||||||
|  |                         }, | ||||||
|  |                       child: Icon(Icons.arrow_back, color: ColorPalette.slate500) | ||||||
|  |                     ), | ||||||
|  |                     Text('Results from your risk profile', | ||||||
|  |                       style: TextStyle( | ||||||
|  |                         fontWeight: FontWeight.w600, | ||||||
|  |                         fontSize: 18, | ||||||
|  |                         color: ColorPalette.slate800 | ||||||
|  |                       ), | ||||||
|  |                     ), | ||||||
|  |                     GestureDetector( | ||||||
|  |                       onTap: () { | ||||||
|  |                         Navigator.pop(context); | ||||||
|  |  | ||||||
|  |                       }, | ||||||
|  |                       child: Icon(Icons.close_rounded, color: ColorPalette.slate400) | ||||||
|  |                     ) | ||||||
|  |                   ], | ||||||
|  |                 ), | ||||||
|  |                 const SizedBox(height: 32), | ||||||
|  |                 SingleChildScrollView( | ||||||
|                   child: Column( |                   child: Column( | ||||||
|                     children: [ |                     children: listProduct.asMap().entries.map((e) { | ||||||
|                       Row( |                       return Container( | ||||||
|                         children: [ |                         margin: const EdgeInsets.only(bottom: 16), | ||||||
|                           const ImageView(image: PathAssets.iconGoogle, width: 30,), |                         padding: const EdgeInsets.all(16), | ||||||
|                           const SizedBox( |                         decoration: BoxDecoration( | ||||||
|                             width: 12, |                             color: Colors.white, | ||||||
|                           ), |                             border: Border.all(color: ColorPalette.slate200), | ||||||
|                           Expanded( |                             borderRadius: BorderRadius.circular(12), | ||||||
|                             child: Column( |                             boxShadow: const [ | ||||||
|                               crossAxisAlignment: CrossAxisAlignment.start, |                               BoxShadow( | ||||||
|  |                                   color: Color(0XFF1E293B0A) | ||||||
|  |                               ) | ||||||
|  |                             ] | ||||||
|  |                         ), | ||||||
|  |                         child: Column( | ||||||
|  |                           children: [ | ||||||
|  |                             Row( | ||||||
|                               children: [ |                               children: [ | ||||||
|                                 Text(e.value.name ?? '', |                                 const ImageView(image: PathAssets.iconGoogle, width: 30,), | ||||||
|                                   style: const TextStyle( |                                 const SizedBox( | ||||||
|                                     fontWeight: FontWeight.w700, |                                   width: 12, | ||||||
|                                     color: ColorPalette.slate800, |                                 ), | ||||||
|  |                                 Expanded( | ||||||
|  |                                   child: Column( | ||||||
|  |                                     crossAxisAlignment: CrossAxisAlignment.start, | ||||||
|  |                                     children: [ | ||||||
|  |                                       Text(e.value.name ?? '', | ||||||
|  |                                         style: const TextStyle( | ||||||
|  |                                           fontWeight: FontWeight.w700, | ||||||
|  |                                           color: ColorPalette.slate800, | ||||||
|  |                                         ), | ||||||
|  |                                       ), | ||||||
|  |                                       const SizedBox(height: 4,), | ||||||
|  |                                       Container( | ||||||
|  |                                         padding: const EdgeInsets.symmetric(vertical: 6, horizontal: 12), | ||||||
|  |                                         decoration: BoxDecoration( | ||||||
|  |                                             border: Border.all(color: ColorPalette.investTypeColor[e.value.type]!), | ||||||
|  |                                             color: ColorPalette.investTypeBgColor[e.value.type], | ||||||
|  |                                             borderRadius: BorderRadius.circular(40) | ||||||
|  |                                         ), | ||||||
|  |                                         child: Text(e.value.type ?? '', | ||||||
|  |                                           style: TextStyle( | ||||||
|  |                                             color: ColorPalette.investTypeColor[e.value.type], | ||||||
|  |                                             fontWeight: FontWeight.w600, | ||||||
|  |                                             fontSize: 12 | ||||||
|  |                                           ), | ||||||
|  |                                         ), | ||||||
|  |                                       ) | ||||||
|  |                                     ], | ||||||
|                                   ), |                                   ), | ||||||
|                                 ), |                                 ), | ||||||
|                                 const SizedBox(height: 4,), |                                 Text('${(e.value.totalPercent! * 100).toInt()} %', | ||||||
|                                 Container( |                                   style: const TextStyle( | ||||||
|                                   padding: const EdgeInsets.symmetric(vertical: 6, horizontal: 12), |                                       fontWeight: FontWeight.w700, | ||||||
|                                   decoration: BoxDecoration( |                                       fontSize: 16, | ||||||
|                                       border: Border.all(color: ColorPalette.investTypeColor[e.value.type]!), |                                       color: ColorPalette.slate800 | ||||||
|                                       color: ColorPalette.investTypeBgColor[e.value.type], |  | ||||||
|                                       borderRadius: BorderRadius.circular(40) |  | ||||||
|                                   ), |  | ||||||
|                                   child: Text(e.value.type ?? '', |  | ||||||
|                                     style: TextStyle( |  | ||||||
|                                       color: ColorPalette.investTypeColor[e.value.type], |  | ||||||
|                                       fontWeight: FontWeight.w600, |  | ||||||
|                                       fontSize: 12 |  | ||||||
|                                     ), |  | ||||||
|                                   ), |                                   ), | ||||||
|                                 ) |                                 ) | ||||||
|                               ], |                               ], | ||||||
|                             ), |                             ), | ||||||
|                           ), |                             const Padding( | ||||||
|                           Text('${(e.value.totalPercent! * 100).toInt()} %', |                               padding: EdgeInsets.symmetric(vertical: 16), | ||||||
|                             style: const TextStyle( |                               child: Divider(height: 1, color: ColorPalette.slate200), | ||||||
|                                 fontWeight: FontWeight.w700, |  | ||||||
|                                 fontSize: 16, |  | ||||||
|                                 color: ColorPalette.slate800 |  | ||||||
|                             ), |                             ), | ||||||
|                           ) |                             GestureDetector( | ||||||
|                         ], |                               onTap: () { | ||||||
|                       ), |                                 routePush(context, page: ProductView(selectedProduct: e.value, seeMore: true)); | ||||||
|                       const Padding( |                               }, | ||||||
|                         padding: EdgeInsets.symmetric(vertical: 16), |                               child: const Text('See More', | ||||||
|                         child: Divider(height: 1, color: ColorPalette.slate200), |                                 style: TextStyle( | ||||||
|                       ), |                                   color: ColorPalette.slate500, | ||||||
|                       GestureDetector( |                                   fontWeight: FontWeight.w600, | ||||||
|                         onTap: () { |                                 ), | ||||||
|                         }, |                               ), | ||||||
|                         child: const Text('See More', |                             ) | ||||||
|                           style: TextStyle( |                           ], | ||||||
|                             color: ColorPalette.slate500, |  | ||||||
|                             fontWeight: FontWeight.w600, |  | ||||||
|                           ), |  | ||||||
|                         ), |                         ), | ||||||
|                       ) |                       ); | ||||||
|                     ], |                     }).toList(), | ||||||
|                   ), |                   ), | ||||||
|                 ); |                 ), | ||||||
|               }).toList(), |                 const SizedBox( | ||||||
|  |                   height: 16, | ||||||
|  |                 ), | ||||||
|  |                 ButtonView( | ||||||
|  |                   name: 'Next', | ||||||
|  |                   onPressed: () { | ||||||
|  |                     Navigator.pop(context); | ||||||
|  |                     showModalBottomSheet( | ||||||
|  |                       context: context, | ||||||
|  |                       isScrollControlled: true, | ||||||
|  |                       builder: (context) => | ||||||
|  |                         ChangeNotifierProvider( | ||||||
|  |                           create: (context) => PlanViewModel(), | ||||||
|  |                           child: Consumer<PlanViewModel>( | ||||||
|  |                             builder: (context, planProvider, _) { | ||||||
|  |                               return TotalPaymentView( | ||||||
|  |                                 listProduct: listProduct, | ||||||
|  |                                 totalInvest: totalInvest, | ||||||
|  |                                 isAgree: planProvider.isAgree, | ||||||
|  |                                 onTapAgree: planProvider.setAgree, | ||||||
|  |                               ); | ||||||
|  |                             } | ||||||
|  |                           ), | ||||||
|  |                         ) | ||||||
|  |                     ); | ||||||
|  |                   }, | ||||||
|  |                   width: SizeConfig.width, | ||||||
|  |                   heightWrapContent: true, | ||||||
|  |                   contentPadding: const EdgeInsets.symmetric(vertical: 16), | ||||||
|  |                   marginVertical: 0, | ||||||
|  |                 ) | ||||||
|  |               ], | ||||||
|             ), |             ), | ||||||
|           ), |           ); | ||||||
|           const SizedBox( |         } | ||||||
|             height: 16, |  | ||||||
|           ), |  | ||||||
|           ButtonView( |  | ||||||
|             name: 'Next', |  | ||||||
|             onPressed: () { |  | ||||||
|               showModalBottomSheet( |  | ||||||
|                   context: context, |  | ||||||
|                   isScrollControlled: true, |  | ||||||
|                   builder: (context) => |  | ||||||
|                     TotalPaymentView( |  | ||||||
|                       listProduct: listProduct, |  | ||||||
|                       totalInvest: totalInvest, |  | ||||||
|                     ) |  | ||||||
|               ); |  | ||||||
|             }, |  | ||||||
|             width: SizeConfig.width, |  | ||||||
|             heightWrapContent: true, |  | ||||||
|             contentPadding: const EdgeInsets.symmetric(vertical: 16), |  | ||||||
|             marginVertical: 0, |  | ||||||
|           ) |  | ||||||
|         ], |  | ||||||
|       ), |       ), | ||||||
|     ); |     ); | ||||||
|   } |   } | ||||||
|   | |||||||
| @@ -3,4 +3,10 @@ import 'package:flutter/material.dart'; | |||||||
|  |  | ||||||
| class PlanViewModel extends ChangeNotifier { | class PlanViewModel extends ChangeNotifier { | ||||||
|   List<Product> listProduct = []; |   List<Product> listProduct = []; | ||||||
|  |   bool isAgree = false; | ||||||
|  |  | ||||||
|  |   void setAgree() { | ||||||
|  |     isAgree = !isAgree; | ||||||
|  |     notifyListeners(); | ||||||
|  |   } | ||||||
| } | } | ||||||
| @@ -0,0 +1,265 @@ | |||||||
|  | import 'package:cims_apps/application/assets/path_assets.dart'; | ||||||
|  | import 'package:cims_apps/application/component/button/back_button_view.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_title/text_title.dart'; | ||||||
|  | import 'package:cims_apps/application/theme/color_palette.dart'; | ||||||
|  | import 'package:cims_apps/core/utils/number_formatter.dart'; | ||||||
|  | import 'package:cims_apps/core/utils/size_config.dart'; | ||||||
|  | import 'package:cims_apps/features/dashboard/dashboard_account/view/portfolio/redeem_product/view/redeem_product.dart'; | ||||||
|  | import 'package:cims_apps/features/dashboard/dashboard_account/view/portfolio/redeem_product/view_model/redeem_product_view_model.dart'; | ||||||
|  | import 'package:flutter/material.dart'; | ||||||
|  | import 'package:provider/provider.dart'; | ||||||
|  |  | ||||||
|  | class PortfolioDetailView extends StatelessWidget { | ||||||
|  |   const PortfolioDetailView({super.key}); | ||||||
|  |  | ||||||
|  |   @override | ||||||
|  |   Widget build(BuildContext context) { | ||||||
|  |     List<PortfolioProduct> listProduct = [ | ||||||
|  |       PortfolioProduct( | ||||||
|  |           name: 'Gemilang Dana Kas Maxima', | ||||||
|  |           type: 'Money Market', | ||||||
|  |           yield: 8.17, | ||||||
|  |           priceUnit: 2600.79, | ||||||
|  |           funds: 6300000, | ||||||
|  |           totalUnit: 14520 | ||||||
|  |       ), | ||||||
|  |       PortfolioProduct( | ||||||
|  |           name: 'Gemilang Dana Likuid', | ||||||
|  |           type: 'Sharia', | ||||||
|  |           yield: 6.42, | ||||||
|  |           priceUnit: 1600.79, | ||||||
|  |           funds: 2340000, | ||||||
|  |           totalUnit: 232, | ||||||
|  |       ), | ||||||
|  |       PortfolioProduct( | ||||||
|  |           name: 'Gemilang Income Fund', | ||||||
|  |           type: 'Bonds', | ||||||
|  |           yield: 8.17, | ||||||
|  |           priceUnit: 2600.79, | ||||||
|  |           funds: 6300000, | ||||||
|  |           totalUnit: 2450, | ||||||
|  |       ) | ||||||
|  |     ]; | ||||||
|  |  | ||||||
|  |  | ||||||
|  |     return ChangeNotifierProvider( | ||||||
|  |       create: (context) => RedeemProductViewModel(), | ||||||
|  |       child: Scaffold( | ||||||
|  |         backgroundColor: Colors.white, | ||||||
|  |         body: SizedBox( | ||||||
|  |           width: SizeConfig.width, | ||||||
|  |           height: SizeConfig.height, | ||||||
|  |           child: Stack( | ||||||
|  |             children: [ | ||||||
|  |               const ImageView(image: PathAssets.imgDashboardAccount), | ||||||
|  |               Column( | ||||||
|  |                 children: [ | ||||||
|  |                   const SizedBox( | ||||||
|  |                     height: 50, | ||||||
|  |                   ), | ||||||
|  |                   Padding( | ||||||
|  |                     padding: const EdgeInsets.symmetric(horizontal: 24), | ||||||
|  |                     child: Row( | ||||||
|  |                       mainAxisAlignment: MainAxisAlignment.spaceBetween, | ||||||
|  |                       children: [ | ||||||
|  |                         const BackButtonView(), | ||||||
|  |                         const TextTitle(title: 'Education', color: Colors.white), | ||||||
|  |                         SizedBox(width: SizeConfig.width * 0.1,) | ||||||
|  |                       ], | ||||||
|  |                     ), | ||||||
|  |                   ), | ||||||
|  |                   const SizedBox(height: 24,), | ||||||
|  |                   const Padding( | ||||||
|  |                     padding: EdgeInsets.symmetric(horizontal: 24), | ||||||
|  |                     child: Row( | ||||||
|  |                       mainAxisAlignment: MainAxisAlignment.spaceBetween, | ||||||
|  |                       children: [ | ||||||
|  |                         Column( | ||||||
|  |                           crossAxisAlignment: CrossAxisAlignment.start, | ||||||
|  |                           children: [ | ||||||
|  |                             Text('Portfolio Value', | ||||||
|  |                               style: TextStyle( | ||||||
|  |                                   color: ColorPalette.white, | ||||||
|  |                                   fontWeight: FontWeight.w400 | ||||||
|  |                               ), | ||||||
|  |                             ), | ||||||
|  |                             TextTitle(title: 'Rp 2.000.000', fontSize: 14, color: Colors.white) | ||||||
|  |                           ], | ||||||
|  |                         ), | ||||||
|  |                         Column( | ||||||
|  |                           crossAxisAlignment: CrossAxisAlignment.end, | ||||||
|  |                           children: [ | ||||||
|  |                             Text('Advantages', | ||||||
|  |                               style: TextStyle( | ||||||
|  |                                   color: ColorPalette.white, | ||||||
|  |                                   fontWeight: FontWeight.w400 | ||||||
|  |                               ), | ||||||
|  |                             ), | ||||||
|  |                             TextTitle(title: 'Rp 2.000.000', fontSize: 14, color: Colors.white) | ||||||
|  |                           ], | ||||||
|  |                         ) | ||||||
|  |                       ], | ||||||
|  |                     ), | ||||||
|  |                   ), | ||||||
|  |                   const SizedBox(height: 24,), | ||||||
|  |                   Expanded( | ||||||
|  |                     child: Container( | ||||||
|  |                       decoration: BoxDecoration( | ||||||
|  |                         borderRadius: BorderRadius.circular(12), | ||||||
|  |                         color: Colors.white, | ||||||
|  |                       ), | ||||||
|  |                       child: Consumer<RedeemProductViewModel>( | ||||||
|  |                         builder: (context, provider, child) { | ||||||
|  |                           return ListView( | ||||||
|  |                             padding: const EdgeInsets.all(24), | ||||||
|  |                             children: listProduct.asMap().entries.map((e) { | ||||||
|  |                               return cardPortfolio(context, e.value); | ||||||
|  |                             }).toList(), | ||||||
|  |                           ); | ||||||
|  |                         } | ||||||
|  |                       ), | ||||||
|  |                     ) | ||||||
|  |                   ) | ||||||
|  |                 ], | ||||||
|  |               ) | ||||||
|  |             ], | ||||||
|  |           ), | ||||||
|  |         ), | ||||||
|  |       ), | ||||||
|  |     ); | ||||||
|  |   } | ||||||
|  |  | ||||||
|  |   Widget cardPortfolio(context, PortfolioProduct product) { | ||||||
|  |     return Container( | ||||||
|  |       padding: const EdgeInsets.all(16), | ||||||
|  |       decoration: BoxDecoration( | ||||||
|  |         color: Colors.white, | ||||||
|  |         borderRadius: BorderRadius.circular(12), | ||||||
|  |         border: Border.all(color: ColorPalette.slate200), | ||||||
|  |         boxShadow: [ | ||||||
|  |           BoxShadow( | ||||||
|  |             color: const Color(0xff1E293B).withOpacity(0.04), | ||||||
|  |             blurRadius: 8, | ||||||
|  |             spreadRadius: 2 | ||||||
|  |           ) | ||||||
|  |         ] | ||||||
|  |       ), | ||||||
|  |       child: Column( | ||||||
|  |         crossAxisAlignment: CrossAxisAlignment.start, | ||||||
|  |         children: [ | ||||||
|  |           Row( | ||||||
|  |             crossAxisAlignment: CrossAxisAlignment.start, | ||||||
|  |             children: [ | ||||||
|  |               ImageView( | ||||||
|  |                 image: PathAssets.imgProduct, | ||||||
|  |                 width: SizeConfig.width * .13, | ||||||
|  |               ), | ||||||
|  |               const SizedBox(width: 8), | ||||||
|  |               Expanded( | ||||||
|  |                 child: Column( | ||||||
|  |                   crossAxisAlignment: CrossAxisAlignment.start, | ||||||
|  |                   children: [ | ||||||
|  |                     TextTitle(title: product.name ?? '', fontSize: 16,), | ||||||
|  |                     const SizedBox(height: 4), | ||||||
|  |                     Container( | ||||||
|  |                       padding: const EdgeInsets.all(6), | ||||||
|  |                       decoration: BoxDecoration( | ||||||
|  |                           borderRadius: BorderRadius.circular(40), | ||||||
|  |                           color: ColorPalette.investTypeBgColor[product.type!]?.withOpacity(0.5) ?? Colors.white, | ||||||
|  |                           border: Border.all(width: 2, color: ColorPalette.investTypeColor[product.type!]?.withOpacity(0.4) ?? Colors.white) | ||||||
|  |                       ), | ||||||
|  |                       child: Text( | ||||||
|  |                         product.type ?? '', | ||||||
|  |                         style: TextStyle( | ||||||
|  |                             color: ColorPalette.investTypeColor[product.type!], | ||||||
|  |                             fontWeight: FontWeight.w600 | ||||||
|  |                         ), | ||||||
|  |                       ), | ||||||
|  |                     ) | ||||||
|  |                   ], | ||||||
|  |                 ), | ||||||
|  |               ) | ||||||
|  |             ], | ||||||
|  |           ), | ||||||
|  |           const Padding( | ||||||
|  |             padding: EdgeInsets.symmetric(vertical: 16), | ||||||
|  |             child: Divider(height: 1, color: ColorPalette.slate200,), | ||||||
|  |           ), | ||||||
|  |           Wrap( | ||||||
|  |             runSpacing: 8, | ||||||
|  |             children: [ | ||||||
|  |               rowDescription('Present Value', 'Rp2.660.706', fontWeight: FontWeight.w700), | ||||||
|  |               rowDescription('Investment Capital', 'Rp2.660.706'), | ||||||
|  |               rowDescription('Advantages', 'Rp2.660.706'), | ||||||
|  |               rowDescription('Purchase Price', NumberFormatter.numberCurrency(product.priceUnit, 'Rp ', 'id_ID')), | ||||||
|  |               rowDescription('Number of Units', '${product.totalUnit ?? 0}'), | ||||||
|  |             ], | ||||||
|  |           ), | ||||||
|  |           const SizedBox(height: 16,), | ||||||
|  |           Row( | ||||||
|  |             children: [ | ||||||
|  |               Expanded( | ||||||
|  |                 child: ButtonView( | ||||||
|  |                   name: 'Redeem', | ||||||
|  |                   marginVertical: 0, | ||||||
|  |                   width: SizeConfig.width, | ||||||
|  |                   isOutlined: true, | ||||||
|  |                   heightWrapContent: true, | ||||||
|  |                   contentPadding: const EdgeInsets.all(12), | ||||||
|  |                   backgroundColor: Colors.white, | ||||||
|  |                   borderColor: ColorPalette.red600, | ||||||
|  |                   textColor: ColorPalette.red600, | ||||||
|  |                   onPressed: () { | ||||||
|  |                     Provider.of<RedeemProductViewModel>(context, listen: false).setProduct(product); | ||||||
|  |                     showModalBottomSheet( | ||||||
|  |                       context: context, | ||||||
|  |                       isScrollControlled: true, | ||||||
|  |                       builder: (context) { | ||||||
|  |                         return RedeemProduct(); | ||||||
|  |                       }, | ||||||
|  |                     ); | ||||||
|  |                   }, | ||||||
|  |                 ), | ||||||
|  |               ), | ||||||
|  |               const SizedBox(width: 16), | ||||||
|  |               Expanded( | ||||||
|  |                 child: ButtonView( | ||||||
|  |                   name: 'Buy', | ||||||
|  |                   marginVertical: 0, | ||||||
|  |                   width: SizeConfig.width, | ||||||
|  |                   heightWrapContent: true, | ||||||
|  |                   contentPadding: const EdgeInsets.all(12), | ||||||
|  |                   onPressed: () { | ||||||
|  |  | ||||||
|  |                   }, | ||||||
|  |                 ), | ||||||
|  |               ) | ||||||
|  |             ], | ||||||
|  |           ) | ||||||
|  |         ], | ||||||
|  |       ), | ||||||
|  |     ); | ||||||
|  |   } | ||||||
|  |  | ||||||
|  |   Widget rowDescription(String title, String value, {Color? color, FontWeight? fontWeight}) { | ||||||
|  |     return Row( | ||||||
|  |       mainAxisAlignment: MainAxisAlignment.spaceBetween, | ||||||
|  |       children: [ | ||||||
|  |         Text(title, | ||||||
|  |           style: const TextStyle( | ||||||
|  |             color: ColorPalette.slate400, | ||||||
|  |             fontWeight: FontWeight.w600 | ||||||
|  |           ), | ||||||
|  |         ), | ||||||
|  |         Text(value, | ||||||
|  |           style: TextStyle( | ||||||
|  |             color: color ?? ColorPalette.slate800, | ||||||
|  |             fontWeight: fontWeight ?? FontWeight.w600, | ||||||
|  |           ), | ||||||
|  |         ) | ||||||
|  |       ], | ||||||
|  |     ); | ||||||
|  |   } | ||||||
|  | } | ||||||
| @@ -1,9 +1,10 @@ | |||||||
| import 'dart:math'; |  | ||||||
|  |  | ||||||
| import 'package:cims_apps/application/assets/path_assets.dart'; | 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/image/image_view.dart'; | ||||||
|  | import 'package:cims_apps/application/component/text_title/text_title.dart'; | ||||||
| import 'package:cims_apps/application/theme/color_palette.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/core/utils/size_config.dart'; | ||||||
|  | import 'package:cims_apps/features/dashboard/dashboard_account/view/portfolio/portfolio_detail_view.dart'; | ||||||
| import 'package:fl_chart/fl_chart.dart'; | import 'package:fl_chart/fl_chart.dart'; | ||||||
| import 'package:flutter/material.dart'; | import 'package:flutter/material.dart'; | ||||||
|  |  | ||||||
| @@ -70,7 +71,7 @@ class _PortofolioViewState extends State<PortofolioView> { | |||||||
|                 ), |                 ), | ||||||
|                 const Center( |                 const Center( | ||||||
|                   child: Text( |                   child: Text( | ||||||
|                     'Portofolio', |                     'Portfolio', | ||||||
|                     style: TextStyle( |                     style: TextStyle( | ||||||
|                         fontSize: 20, |                         fontSize: 20, | ||||||
|                         fontWeight: FontWeight.w700, |                         fontWeight: FontWeight.w700, | ||||||
| @@ -125,20 +126,22 @@ class _PortofolioViewState extends State<PortofolioView> { | |||||||
|                           ), |                           ), | ||||||
|                           Column( |                           Column( | ||||||
|                             children: [ |                             children: [ | ||||||
|                               const Text('Total Mutual Fund', |                               const Text( | ||||||
|  |                                 'Total Mutual Fund', | ||||||
|                                 style: TextStyle( |                                 style: TextStyle( | ||||||
|                                   fontWeight: FontWeight.w600, |                                     fontWeight: FontWeight.w600, | ||||||
|                                   fontSize: 18, |                                     fontSize: 18, | ||||||
|                                   color: ColorPalette.slate400 |                                     color: ColorPalette.slate400), | ||||||
|                                 ), |  | ||||||
|                               ), |                               ), | ||||||
|                               Text(listInvestmentType.map((e) => e.mutualFunds).reduce((value, element) => value + element).toString(), |                               Text( | ||||||
|                                 style: const TextStyle( |                                   listInvestmentType | ||||||
|                                     fontSize: 44, |                                       .map((e) => e.mutualFunds) | ||||||
|                                     fontWeight: FontWeight.w700 |                                       .reduce( | ||||||
|                                 ) |                                           (value, element) => value + element) | ||||||
|                               ) |                                       .toString(), | ||||||
|                               , |                                   style: const TextStyle( | ||||||
|  |                                       fontSize: 44, | ||||||
|  |                                       fontWeight: FontWeight.w700)), | ||||||
|                             ], |                             ], | ||||||
|                           ) |                           ) | ||||||
|                         ]), |                         ]), | ||||||
| @@ -147,9 +150,31 @@ class _PortofolioViewState extends State<PortofolioView> { | |||||||
|                         ), |                         ), | ||||||
|                         menuPortofolio(), |                         menuPortofolio(), | ||||||
|                         const SizedBox( |                         const SizedBox( | ||||||
|                           height: 24, |                           height: 12, | ||||||
|                         ), |                         ), | ||||||
|                         ...listColumnPortofolio(), |                         const Padding( | ||||||
|  |                           padding: EdgeInsets.symmetric(horizontal: 24, vertical: 12), | ||||||
|  |                           child: Row( | ||||||
|  |                             mainAxisAlignment: MainAxisAlignment.spaceBetween, | ||||||
|  |                             children: [ | ||||||
|  |                               TextTitle(title: 'My Portfolio', fontSize: 16), | ||||||
|  |                               Row( | ||||||
|  |                                 children: [ | ||||||
|  |                                   Icon(Icons.add, size: 18, color: ColorPalette.primary), | ||||||
|  |                                   SizedBox(width: 4), | ||||||
|  |                                   const Text('Create', | ||||||
|  |                                     style: TextStyle( | ||||||
|  |                                       color: ColorPalette.primary, | ||||||
|  |                                       fontWeight: FontWeight.w600 | ||||||
|  |                                     ), | ||||||
|  |                                   ) | ||||||
|  |                                 ], | ||||||
|  |                               ) | ||||||
|  |                             ], | ||||||
|  |                           ), | ||||||
|  |                         ), | ||||||
|  |                         // ...listColumnPortofolio(), | ||||||
|  |                         cardPortfolio() | ||||||
|                       ], |                       ], | ||||||
|                     ), |                     ), | ||||||
|                   ), |                   ), | ||||||
| @@ -168,7 +193,7 @@ class _PortofolioViewState extends State<PortofolioView> { | |||||||
|       children: [ |       children: [ | ||||||
|         Row( |         Row( | ||||||
|           children: [ |           children: [ | ||||||
|             const Text('Portofolio Value', |             const Text('Portfolio Value', | ||||||
|                 style: TextStyle(color: Colors.white)), |                 style: TextStyle(color: Colors.white)), | ||||||
|             const SizedBox( |             const SizedBox( | ||||||
|               width: 8, |               width: 8, | ||||||
| @@ -179,8 +204,12 @@ class _PortofolioViewState extends State<PortofolioView> { | |||||||
|                     seePortofolioValue = !seePortofolioValue; |                     seePortofolioValue = !seePortofolioValue; | ||||||
|                   }); |                   }); | ||||||
|                 }, |                 }, | ||||||
|                 child: const Icon(Icons.visibility_outlined, |                 child: Icon( | ||||||
|                     color: Color(0xff93C5FD))) |                     seePortofolioValue | ||||||
|  |                         ? Icons.visibility_off_outlined | ||||||
|  |                         : Icons.visibility_outlined, | ||||||
|  |                     size: 18, | ||||||
|  |                     color: const Color(0xff93C5FD))) | ||||||
|           ], |           ], | ||||||
|         ), |         ), | ||||||
|         const SizedBox( |         const SizedBox( | ||||||
| @@ -197,7 +226,10 @@ class _PortofolioViewState extends State<PortofolioView> { | |||||||
|               firstChild: RichText( |               firstChild: RichText( | ||||||
|                   text: const TextSpan( |                   text: const TextSpan( | ||||||
|                       text: 'Rp ', |                       text: 'Rp ', | ||||||
|                       style: TextStyle(fontSize: 32, color: Color(0xff93C5FD), fontFamily: 'Manrope'), |                       style: TextStyle( | ||||||
|  |                           fontSize: 32, | ||||||
|  |                           color: Color(0xff93C5FD), | ||||||
|  |                           fontFamily: 'Manrope'), | ||||||
|                       children: [ |                       children: [ | ||||||
|                     TextSpan( |                     TextSpan( | ||||||
|                       text: '22.500.000', |                       text: '22.500.000', | ||||||
| @@ -205,8 +237,7 @@ class _PortofolioViewState extends State<PortofolioView> { | |||||||
|                           fontSize: 32, |                           fontSize: 32, | ||||||
|                           fontFamily: 'Manrope', |                           fontFamily: 'Manrope', | ||||||
|                           fontWeight: FontWeight.bold, |                           fontWeight: FontWeight.bold, | ||||||
|                           color: Colors.white |                           color: Colors.white), | ||||||
|                       ), |  | ||||||
|                     ) |                     ) | ||||||
|                   ])), |                   ])), | ||||||
|               secondChild: Padding( |               secondChild: Padding( | ||||||
| @@ -276,8 +307,8 @@ class _PortofolioViewState extends State<PortofolioView> { | |||||||
|                   width: 58, |                   width: 58, | ||||||
|                   alignment: Alignment.center, |                   alignment: Alignment.center, | ||||||
|                   decoration: BoxDecoration( |                   decoration: BoxDecoration( | ||||||
|                       shape: BoxShape.circle, |                     shape: BoxShape.circle, | ||||||
|                       color: bgContentColor[e.key], |                     color: bgContentColor[e.key], | ||||||
|                   ), |                   ), | ||||||
|                   child: Text( |                   child: Text( | ||||||
|                     '${e.value.value}%', |                     '${e.value.value}%', | ||||||
| @@ -353,4 +384,85 @@ class _PortofolioViewState extends State<PortofolioView> { | |||||||
|       ); |       ); | ||||||
|     }).toList(); |     }).toList(); | ||||||
|   } |   } | ||||||
|  |  | ||||||
|  |   Widget cardPortfolio() { | ||||||
|  |     return GestureDetector( | ||||||
|  |       onTap: () { | ||||||
|  |         // routePush(context, page: const PortfolioDetailView()); | ||||||
|  |       }, | ||||||
|  |       child: Container( | ||||||
|  |         margin: const EdgeInsets.symmetric(horizontal: 24), | ||||||
|  |         padding: const EdgeInsets.all(16), | ||||||
|  |         decoration: BoxDecoration( | ||||||
|  |           borderRadius: BorderRadius.circular(8), | ||||||
|  |           border: Border.all(color: ColorPalette.slate200) | ||||||
|  |         ), | ||||||
|  |         child: Column( | ||||||
|  |           children: [ | ||||||
|  |             Row( | ||||||
|  |               children: [ | ||||||
|  |                 Container( | ||||||
|  |                     padding: const EdgeInsets.all(4), | ||||||
|  |                     decoration: BoxDecoration( | ||||||
|  |                         color: ColorPalette.blue200.withOpacity(0.5), | ||||||
|  |                         borderRadius: BorderRadius.circular(8) | ||||||
|  |                     ), | ||||||
|  |                     child: ImageView( | ||||||
|  |                         image: PathAssets.goalInvestIcon['Education'], | ||||||
|  |                         width: SizeConfig.width * 0.07 | ||||||
|  |                     ) | ||||||
|  |                 ), | ||||||
|  |                 const SizedBox(width: 8), | ||||||
|  |                 const Column( | ||||||
|  |                   crossAxisAlignment: CrossAxisAlignment.start, | ||||||
|  |                   children: [ | ||||||
|  |                     TextTitle(title: 'Education', fontSize: 16,), | ||||||
|  |                     Text('2 Subscriptions', | ||||||
|  |                       style: TextStyle( | ||||||
|  |                         color: ColorPalette.slate400, | ||||||
|  |                         fontWeight: FontWeight.w600 | ||||||
|  |                       ), | ||||||
|  |                     ) | ||||||
|  |                   ], | ||||||
|  |                 ), | ||||||
|  |               ], | ||||||
|  |             ), | ||||||
|  |             const Padding( | ||||||
|  |               padding: EdgeInsets.symmetric(vertical: 8), | ||||||
|  |               child: Divider(height: 1, color: ColorPalette.slate200), | ||||||
|  |             ), | ||||||
|  |             const Row( | ||||||
|  |               mainAxisAlignment: MainAxisAlignment.spaceBetween, | ||||||
|  |               children: [ | ||||||
|  |                 Column( | ||||||
|  |                   crossAxisAlignment: CrossAxisAlignment.start, | ||||||
|  |                   children: [ | ||||||
|  |                     Text('Portfolio Value', | ||||||
|  |                       style: TextStyle( | ||||||
|  |                           color: ColorPalette.slate400, | ||||||
|  |                           fontWeight: FontWeight.w400 | ||||||
|  |                       ), | ||||||
|  |                     ), | ||||||
|  |                     TextTitle(title: 'Rp 2.000.000', fontSize: 14,) | ||||||
|  |                   ], | ||||||
|  |                 ), | ||||||
|  |                 Column( | ||||||
|  |                   crossAxisAlignment: CrossAxisAlignment.end, | ||||||
|  |                   children: [ | ||||||
|  |                     Text('Advantages', | ||||||
|  |                       style: TextStyle( | ||||||
|  |                           color: ColorPalette.slate400, | ||||||
|  |                           fontWeight: FontWeight.w400 | ||||||
|  |                       ), | ||||||
|  |                     ), | ||||||
|  |                     TextTitle(title: 'Rp 2.000.000', fontSize: 14) | ||||||
|  |                   ], | ||||||
|  |                 ) | ||||||
|  |               ], | ||||||
|  |             ) | ||||||
|  |           ], | ||||||
|  |         ), | ||||||
|  |       ), | ||||||
|  |     ); | ||||||
|  |   } | ||||||
| } | } | ||||||
|   | |||||||
| @@ -0,0 +1,171 @@ | |||||||
|  | import 'dart:math'; | ||||||
|  |  | ||||||
|  | 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/numeric_pad/numeric_pad.dart'; | ||||||
|  | import 'package:cims_apps/application/component/subscribe/input_investment_view.dart'; | ||||||
|  | import 'package:cims_apps/application/component/text_title/text_title.dart'; | ||||||
|  | import 'package:cims_apps/application/theme/color_palette.dart'; | ||||||
|  | import 'package:cims_apps/core/utils/number_formatter.dart'; | ||||||
|  | import 'package:cims_apps/core/utils/size_config.dart'; | ||||||
|  | import 'package:cims_apps/features/dashboard/dashboard_account/view/portfolio/redeem_product/view/redeem_product.dart'; | ||||||
|  | import 'package:cims_apps/features/dashboard/dashboard_account/view/portfolio/redeem_product/view_model/redeem_product_view_model.dart'; | ||||||
|  | import 'package:flutter/material.dart'; | ||||||
|  | import 'package:provider/provider.dart'; | ||||||
|  |  | ||||||
|  | class ChangeAmount extends StatefulWidget { | ||||||
|  |   final int totalAmount; | ||||||
|  |   const ChangeAmount({super.key, required this.totalAmount}); | ||||||
|  |  | ||||||
|  |   @override | ||||||
|  |   State<ChangeAmount> createState() => _ChangeAmountState(); | ||||||
|  | } | ||||||
|  |  | ||||||
|  | class _ChangeAmountState extends State<ChangeAmount> { | ||||||
|  |   TextEditingController amountController = TextEditingController(); | ||||||
|  |  | ||||||
|  |   @override | ||||||
|  |   void initState() { | ||||||
|  |     // TODO: implement initState | ||||||
|  |     super.initState(); | ||||||
|  |     amountController.text = NumberFormatter.numberCurrency(widget.totalAmount, 'Rp ', 'id_ID', decimalDigits: 0); | ||||||
|  |   } | ||||||
|  |  | ||||||
|  |   @override | ||||||
|  |   void dispose() { | ||||||
|  |     // TODO: implement dispose | ||||||
|  |     super.dispose(); | ||||||
|  |     amountController.dispose(); | ||||||
|  |   } | ||||||
|  |  | ||||||
|  |   @override | ||||||
|  |   Widget build(BuildContext context) { | ||||||
|  |     return ChangeNotifierProvider( | ||||||
|  |       create: (context) => RedeemProductViewModel(), | ||||||
|  |       child: Consumer<RedeemProductViewModel>( | ||||||
|  |         builder: (context, provider, child) { | ||||||
|  |           return Column( | ||||||
|  |             mainAxisSize: MainAxisSize.min, | ||||||
|  |             children: [ | ||||||
|  |               Padding( | ||||||
|  |                 padding: const EdgeInsets.symmetric(vertical: 16, horizontal: 24), | ||||||
|  |                 child: Row( | ||||||
|  |                   mainAxisAlignment: MainAxisAlignment.spaceBetween, | ||||||
|  |                   children: [ | ||||||
|  |                     GestureDetector( | ||||||
|  |                         onTap: () { | ||||||
|  |                           Navigator.pop(context); | ||||||
|  |                           showModalBottomSheet( | ||||||
|  |                             context: context, | ||||||
|  |                             isScrollControlled: true, | ||||||
|  |                             builder: (context) { | ||||||
|  |                               return const RedeemProduct(); | ||||||
|  |                             }, | ||||||
|  |                           ); | ||||||
|  |                         }, | ||||||
|  |                         child: const Icon(Icons.arrow_back_rounded) | ||||||
|  |                     ), | ||||||
|  |                     const Text('Type amount', | ||||||
|  |                       style: TextStyle( | ||||||
|  |                           fontWeight: FontWeight.w600, | ||||||
|  |                           fontSize: 16, | ||||||
|  |                           color: ColorPalette.slate800 | ||||||
|  |                       ), | ||||||
|  |                     ), | ||||||
|  |                     GestureDetector( | ||||||
|  |                         onTap: () { | ||||||
|  |                           Navigator.pop(context); | ||||||
|  |                         }, | ||||||
|  |                         child: const Icon(Icons.close_rounded) | ||||||
|  |                     ) | ||||||
|  |                   ], | ||||||
|  |                 ), | ||||||
|  |               ), | ||||||
|  |               const Divider(height: 1, color: ColorPalette.slate200,), | ||||||
|  |               Column( | ||||||
|  |                 crossAxisAlignment: CrossAxisAlignment.start, | ||||||
|  |                 children: [ | ||||||
|  |                   Padding( | ||||||
|  |                     padding: EdgeInsets.all(24), | ||||||
|  |                     child: cardProduct() | ||||||
|  |                   ), | ||||||
|  |                   InputInvestmentView( | ||||||
|  |                     minimumPrice: (provider.getCurrentProduct.priceUnit! * 1).toInt(), | ||||||
|  |                     maximumPrice: (provider.getCurrentProduct.priceUnit! * provider.getCurrentProduct.totalUnit!).toInt(), | ||||||
|  |                     currentPrice: provider.getAmount!.toInt(), | ||||||
|  |                     nextMove: (value) { | ||||||
|  |                       String formatValueInput = value.replaceAll('Rp ', '').replaceAll('.', ''); | ||||||
|  |                       provider.setAmount(double.parse(formatValueInput)); | ||||||
|  |                       Navigator.pop(context); | ||||||
|  |                       showModalBottomSheet( | ||||||
|  |                         context: context, | ||||||
|  |                         isScrollControlled: true, | ||||||
|  |                         builder: (context) { | ||||||
|  |                           return const RedeemProduct(); | ||||||
|  |                         }, | ||||||
|  |                       ); | ||||||
|  |                     }, | ||||||
|  |                   ) | ||||||
|  |                 ], | ||||||
|  |               ), | ||||||
|  |               SizedBox(height: 16,) | ||||||
|  |             ], | ||||||
|  |           ); | ||||||
|  |         } | ||||||
|  |       ), | ||||||
|  |     ); | ||||||
|  |   } | ||||||
|  |  | ||||||
|  |   Widget cardProduct() { | ||||||
|  |     return Container( | ||||||
|  |       padding: const EdgeInsets.all(16), | ||||||
|  |       decoration: BoxDecoration( | ||||||
|  |           color: Colors.white, | ||||||
|  |           borderRadius: BorderRadius.circular(12), | ||||||
|  |           border: Border.all(color: ColorPalette.slate200), | ||||||
|  |           boxShadow: [ | ||||||
|  |             BoxShadow( | ||||||
|  |                 color: const Color(0xff1E293B).withOpacity(0.04), | ||||||
|  |                 blurRadius: 8, | ||||||
|  |                 spreadRadius: 2 | ||||||
|  |             ) | ||||||
|  |           ] | ||||||
|  |       ), | ||||||
|  |       child: Row( | ||||||
|  |         crossAxisAlignment: CrossAxisAlignment.start, | ||||||
|  |         children: [ | ||||||
|  |           ImageView( | ||||||
|  |             image: PathAssets.imgProduct, | ||||||
|  |             width: SizeConfig.width * .13, | ||||||
|  |           ), | ||||||
|  |           const SizedBox(width: 8), | ||||||
|  |           Expanded( | ||||||
|  |             child: Column( | ||||||
|  |               crossAxisAlignment: CrossAxisAlignment.start, | ||||||
|  |               children: [ | ||||||
|  |                 const TextTitle(title: 'Gemilang Dana Kas Maxima', fontSize: 16,), | ||||||
|  |                 const SizedBox(height: 4), | ||||||
|  |                 Container( | ||||||
|  |                   padding: const EdgeInsets.all(6), | ||||||
|  |                   decoration: BoxDecoration( | ||||||
|  |                       borderRadius: BorderRadius.circular(40), | ||||||
|  |                       color: ColorPalette.investTypeBgColor['Money Market']?.withOpacity(0.5) ?? Colors.white, | ||||||
|  |                       border: Border.all(width: 2, color: ColorPalette.investTypeColor['Money Market']?.withOpacity(0.4) ?? Colors.white) | ||||||
|  |                   ), | ||||||
|  |                   child: Text( | ||||||
|  |                     'Money Market' ?? '', | ||||||
|  |                     style: TextStyle( | ||||||
|  |                         color: ColorPalette.investTypeColor['Money Market'], | ||||||
|  |                         fontWeight: FontWeight.w600 | ||||||
|  |                     ), | ||||||
|  |                   ), | ||||||
|  |                 ) | ||||||
|  |               ], | ||||||
|  |             ), | ||||||
|  |           ) | ||||||
|  |         ], | ||||||
|  |       ), | ||||||
|  |     ); | ||||||
|  |   } | ||||||
|  | } | ||||||
| @@ -0,0 +1,191 @@ | |||||||
|  | import 'package:cims_apps/application/component/button/button_view.dart'; | ||||||
|  | import 'package:cims_apps/application/theme/color_palette.dart'; | ||||||
|  | import 'package:cims_apps/features/dashboard/dashboard_account/view/portfolio/redeem_product/view/redeem_product.dart'; | ||||||
|  | import 'package:cims_apps/features/dashboard/dashboard_account/view/portfolio/redeem_product/view_model/redeem_product_view_model.dart'; | ||||||
|  | import 'package:flutter/material.dart'; | ||||||
|  | import 'package:provider/provider.dart'; | ||||||
|  |  | ||||||
|  | class ChangeDestinationAccount extends StatelessWidget { | ||||||
|  |   const ChangeDestinationAccount({super.key}); | ||||||
|  |  | ||||||
|  |   @override | ||||||
|  |   Widget build(BuildContext context) { | ||||||
|  |     List<Account> listAccount = [ | ||||||
|  |       Account('Muhamad Rosyidin', 'BRI', '902139012324'), | ||||||
|  |       Account('Achmad Muhaimin', 'BCA', '21391283928') | ||||||
|  |     ]; | ||||||
|  |  | ||||||
|  |     return ChangeNotifierProvider( | ||||||
|  |       create: (context) => RedeemProductViewModel(), | ||||||
|  |       child: Consumer<RedeemProductViewModel>( | ||||||
|  |         builder: (context, provider, child) { | ||||||
|  |           return Column( | ||||||
|  |             mainAxisSize: MainAxisSize.min, | ||||||
|  |             children: [ | ||||||
|  |               Padding( | ||||||
|  |                 padding: const EdgeInsets.symmetric(vertical: 16, horizontal: 24), | ||||||
|  |                 child: Row( | ||||||
|  |                   mainAxisAlignment: MainAxisAlignment.spaceBetween, | ||||||
|  |                   children: [ | ||||||
|  |                     GestureDetector( | ||||||
|  |                       onTap: () { | ||||||
|  |                         Navigator.pop(context); | ||||||
|  |                         showModalBottomSheet( | ||||||
|  |                           context: context, | ||||||
|  |                           isScrollControlled: true, | ||||||
|  |                           builder: (context) { | ||||||
|  |                             return const RedeemProduct(); | ||||||
|  |                           }, | ||||||
|  |                         ); | ||||||
|  |                       }, | ||||||
|  |                       child: const Icon(Icons.arrow_back_rounded) | ||||||
|  |                     ), | ||||||
|  |                     const Text('Change Destination Account', | ||||||
|  |                       style: TextStyle( | ||||||
|  |                         fontWeight: FontWeight.w600, | ||||||
|  |                         fontSize: 16, | ||||||
|  |                         color: ColorPalette.slate800 | ||||||
|  |                       ), | ||||||
|  |                     ), | ||||||
|  |                     GestureDetector( | ||||||
|  |                       onTap: () { | ||||||
|  |                         Navigator.pop(context); | ||||||
|  |                       }, | ||||||
|  |                       child: const Icon(Icons.close_rounded) | ||||||
|  |                     ) | ||||||
|  |                   ], | ||||||
|  |                 ), | ||||||
|  |               ), | ||||||
|  |               const Divider(height: 1, color: ColorPalette.slate200,), | ||||||
|  |               Padding( | ||||||
|  |                 padding: const EdgeInsets.all(24), | ||||||
|  |                 child: Column( | ||||||
|  |                   children: [ | ||||||
|  |                     ...listAccount.asMap().entries.map((e) { | ||||||
|  |                       return GestureDetector( | ||||||
|  |                         onTap: () => provider.setSelectedAcc(e.value), | ||||||
|  |                         child: Padding( | ||||||
|  |                           padding: EdgeInsets.only(top: e.key != 0 ? 16 : 0), | ||||||
|  |                           child: cardAccount(e.value, provider.selectedAccount?.number ?? provider.getCurrentAccount.number), | ||||||
|  |                         ), | ||||||
|  |                       ); | ||||||
|  |                     }), | ||||||
|  |                     const SizedBox(height: 24), | ||||||
|  |                     GestureDetector( | ||||||
|  |                       child: const Row( | ||||||
|  |                         mainAxisSize: MainAxisSize.min, | ||||||
|  |                         mainAxisAlignment: MainAxisAlignment.center, | ||||||
|  |                         children: [ | ||||||
|  |                           Icon(Icons.add, size: 24, color: ColorPalette.primary), | ||||||
|  |                           SizedBox(width: 12,), | ||||||
|  |                           Text('New Bank', | ||||||
|  |                             style: TextStyle( | ||||||
|  |                                 color: ColorPalette.primary, | ||||||
|  |                                 fontSize: 20, | ||||||
|  |                                 fontWeight: FontWeight.w600 | ||||||
|  |                             ), | ||||||
|  |                           ) | ||||||
|  |                         ], | ||||||
|  |                       ), | ||||||
|  |                     ), | ||||||
|  |                     const SizedBox(height: 32), | ||||||
|  |                     ButtonView( | ||||||
|  |                       name: 'Save', | ||||||
|  |                       textSize: 20, | ||||||
|  |                       marginVertical: 0, | ||||||
|  |                       onPressed: () { | ||||||
|  |                         Navigator.pop(context); | ||||||
|  |                         showModalBottomSheet( | ||||||
|  |                           context: context, | ||||||
|  |                           isScrollControlled: true, | ||||||
|  |                           builder: (context) { | ||||||
|  |                             provider.setCurrentAcc(provider.selectedAccount!); | ||||||
|  |                             return const RedeemProduct(); | ||||||
|  |                           }, | ||||||
|  |                         ); | ||||||
|  |                       }, | ||||||
|  |                     ) | ||||||
|  |                   ], | ||||||
|  |                 ), | ||||||
|  |               ), | ||||||
|  |             ], | ||||||
|  |           ); | ||||||
|  |         } | ||||||
|  |       ), | ||||||
|  |     ); | ||||||
|  |   } | ||||||
|  |  | ||||||
|  |   Widget cardAccount(Account account, String numberSelected) { | ||||||
|  |     List<String> listNumber = []; | ||||||
|  |  | ||||||
|  |     List.generate(account.number.length, (index) { | ||||||
|  |       if(index > 3 && index < account.number.length - 4){ | ||||||
|  |         listNumber.add('*'); | ||||||
|  |       }else{ | ||||||
|  |         listNumber.add(account.number[index]); | ||||||
|  |       } | ||||||
|  |     }); | ||||||
|  |  | ||||||
|  |     return Container( | ||||||
|  |       padding: const EdgeInsets.all(16), | ||||||
|  |       decoration: BoxDecoration( | ||||||
|  |           borderRadius: BorderRadius.circular(14), | ||||||
|  |           border: Border.all(color: ColorPalette.slate200) | ||||||
|  |       ), | ||||||
|  |       child: Row( | ||||||
|  |         children: [ | ||||||
|  |           Expanded( | ||||||
|  |             child: Row( | ||||||
|  |               mainAxisAlignment: MainAxisAlignment.spaceBetween, | ||||||
|  |               children: [ | ||||||
|  |                 Column( | ||||||
|  |                   crossAxisAlignment: CrossAxisAlignment.start, | ||||||
|  |                   children: [ | ||||||
|  |                     Text(account.nameOwner, | ||||||
|  |                       style: const TextStyle( | ||||||
|  |                           fontSize: 16, | ||||||
|  |                           fontWeight: FontWeight.w600, | ||||||
|  |                           color: ColorPalette.slate800 | ||||||
|  |                       ), | ||||||
|  |                     ), | ||||||
|  |                     Text( | ||||||
|  |                       '${account.nameBank} - ${listNumber.join("")}', | ||||||
|  |                       style: const TextStyle( | ||||||
|  |                           fontSize: 16, | ||||||
|  |                           fontWeight: FontWeight.w600, | ||||||
|  |                           color: ColorPalette.slate400 | ||||||
|  |                       ), | ||||||
|  |                     ) | ||||||
|  |                   ], | ||||||
|  |                 ), | ||||||
|  |               ], | ||||||
|  |             ), | ||||||
|  |           ), | ||||||
|  |           AnimatedContainer( | ||||||
|  |             margin: const EdgeInsets.only(top: 4), | ||||||
|  |             duration: const Duration(milliseconds: 200), | ||||||
|  |             height: 16, | ||||||
|  |             width: 16, | ||||||
|  |             padding: const EdgeInsets.all(1), | ||||||
|  |             alignment: Alignment.center, | ||||||
|  |             decoration: BoxDecoration( | ||||||
|  |                 shape: BoxShape.circle, | ||||||
|  |                 border: Border.all( | ||||||
|  |                     color: numberSelected == account.number | ||||||
|  |                         ? ColorPalette.primary | ||||||
|  |                         : ColorPalette.slate200)), | ||||||
|  |             child: AnimatedContainer( | ||||||
|  |               duration: const Duration(milliseconds: 200), | ||||||
|  |               child: Container( | ||||||
|  |                 decoration: BoxDecoration( | ||||||
|  |                     color: | ||||||
|  |                     numberSelected == account.number ? ColorPalette.primary : ColorPalette.white, | ||||||
|  |                     shape: BoxShape.circle), | ||||||
|  |               ), | ||||||
|  |             ), | ||||||
|  |           ) | ||||||
|  |         ], | ||||||
|  |       ), | ||||||
|  |     ); | ||||||
|  |   } | ||||||
|  | } | ||||||
| @@ -0,0 +1,360 @@ | |||||||
|  | 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_form/text_form_view.dart'; | ||||||
|  | import 'package:cims_apps/application/component/text_title/text_title.dart'; | ||||||
|  | import 'package:cims_apps/application/theme/color_palette.dart'; | ||||||
|  | import 'package:cims_apps/core/utils/number_formatter.dart'; | ||||||
|  | import 'package:cims_apps/core/utils/size_config.dart'; | ||||||
|  | import 'package:cims_apps/features/dashboard/dashboard_account/view/portfolio/redeem_product/view/change_amount.dart'; | ||||||
|  | import 'package:cims_apps/features/dashboard/dashboard_account/view/portfolio/redeem_product/view/change_destination_account.dart'; | ||||||
|  | import 'package:cims_apps/features/dashboard/dashboard_account/view/portfolio/redeem_product/view/total_redeem.dart'; | ||||||
|  | import 'package:cims_apps/features/dashboard/dashboard_account/view/portfolio/redeem_product/view_model/redeem_product_view_model.dart'; | ||||||
|  | import 'package:flutter/material.dart'; | ||||||
|  | import 'package:provider/provider.dart'; | ||||||
|  |  | ||||||
|  | class RedeemProduct extends StatefulWidget { | ||||||
|  |   const RedeemProduct({super.key}); | ||||||
|  |  | ||||||
|  |   @override | ||||||
|  |   State<RedeemProduct> createState() => _RedeemProductState(); | ||||||
|  | } | ||||||
|  |  | ||||||
|  | class _RedeemProductState extends State<RedeemProduct> { | ||||||
|  |   TextEditingController amountController = TextEditingController(); | ||||||
|  |  | ||||||
|  |   @override | ||||||
|  |   void initState() { | ||||||
|  |     // TODO: implement initState | ||||||
|  |     super.initState(); | ||||||
|  |   } | ||||||
|  |  | ||||||
|  |   @override | ||||||
|  |   void dispose() { | ||||||
|  |     // TODO: implement dispose | ||||||
|  |     super.dispose(); | ||||||
|  |     amountController.dispose(); | ||||||
|  |   } | ||||||
|  |  | ||||||
|  |   @override | ||||||
|  |   Widget build(BuildContext context) { | ||||||
|  |     return ChangeNotifierProvider( | ||||||
|  |       create: (context) => RedeemProductViewModel(), | ||||||
|  |       child: Consumer<RedeemProductViewModel>( | ||||||
|  |         builder: (context, provider, child) { | ||||||
|  |           amountController.text = NumberFormatter.numberCurrency(provider.getAmount!.toInt(), 'Rp ', 'id_ID', decimalDigits: 0); | ||||||
|  |           return Column( | ||||||
|  |             mainAxisSize: MainAxisSize.min, | ||||||
|  |             children: [ | ||||||
|  |               Padding( | ||||||
|  |                 padding: const EdgeInsets.symmetric(horizontal: 24, vertical: 16), | ||||||
|  |                 child: Row( | ||||||
|  |                   mainAxisAlignment: MainAxisAlignment.spaceBetween, | ||||||
|  |                   children: [ | ||||||
|  |                     const Text('Products to be Redeemed', | ||||||
|  |                       style: TextStyle( | ||||||
|  |                         fontWeight: FontWeight.w600, | ||||||
|  |                         color: ColorPalette.slate800, | ||||||
|  |                         fontSize: 16 | ||||||
|  |                       ), | ||||||
|  |                     ), | ||||||
|  |                     GestureDetector( | ||||||
|  |                       onTap: () => Navigator.pop(context), | ||||||
|  |                       child: const Icon(Icons.close_rounded, color: ColorPalette.slate800,) | ||||||
|  |                     ) | ||||||
|  |                   ], | ||||||
|  |                 ), | ||||||
|  |               ), | ||||||
|  |               const Divider(height: 1, color: ColorPalette.slate200,), | ||||||
|  |               Padding( | ||||||
|  |                 padding: const EdgeInsets.symmetric(horizontal: 24, vertical: 16), | ||||||
|  |                 child: Column( | ||||||
|  |                   crossAxisAlignment: CrossAxisAlignment.start, | ||||||
|  |                   children: [ | ||||||
|  |                     cardProduct(), | ||||||
|  |                     const SizedBox(height: 16), | ||||||
|  |                     segmentAmount( | ||||||
|  |                       context, | ||||||
|  |                       provider.getAmount!, | ||||||
|  |                       provider.getUnit!, | ||||||
|  |                       (value) { | ||||||
|  |                         provider.setUnit(value); | ||||||
|  |                       }, | ||||||
|  |                     ), | ||||||
|  |                     const SizedBox(height: 16), | ||||||
|  |                     segmentDestinationAcc(provider.getCurrentAccount), | ||||||
|  |                     const SizedBox(height: 36), | ||||||
|  |                     ButtonView( | ||||||
|  |                       name: 'Redeem', | ||||||
|  |                       textSize: 20, | ||||||
|  |                       marginVertical: 0, | ||||||
|  |                       onPressed: () { | ||||||
|  |                         Navigator.pop(context); | ||||||
|  |                         showModalBottomSheet( | ||||||
|  |                           context: context, | ||||||
|  |                           isScrollControlled: true, | ||||||
|  |                           builder: (context) { | ||||||
|  |                             return TotalRedeem(); | ||||||
|  |                           }, | ||||||
|  |                         ); | ||||||
|  |                       }, | ||||||
|  |                     ), | ||||||
|  |                     const SizedBox(height: 16) | ||||||
|  |                   ], | ||||||
|  |                 ), | ||||||
|  |               ) | ||||||
|  |             ], | ||||||
|  |           ); | ||||||
|  |         } | ||||||
|  |       ), | ||||||
|  |     ); | ||||||
|  |   } | ||||||
|  |  | ||||||
|  |   Widget cardProduct() { | ||||||
|  |     return Container( | ||||||
|  |       padding: const EdgeInsets.all(16), | ||||||
|  |       decoration: BoxDecoration( | ||||||
|  |           color: Colors.white, | ||||||
|  |           borderRadius: BorderRadius.circular(12), | ||||||
|  |           border: Border.all(color: ColorPalette.slate200), | ||||||
|  |           boxShadow: [ | ||||||
|  |             BoxShadow( | ||||||
|  |                 color: const Color(0xff1E293B).withOpacity(0.04), | ||||||
|  |                 blurRadius: 8, | ||||||
|  |                 spreadRadius: 2 | ||||||
|  |             ) | ||||||
|  |           ] | ||||||
|  |       ), | ||||||
|  |       child: Row( | ||||||
|  |         crossAxisAlignment: CrossAxisAlignment.start, | ||||||
|  |         children: [ | ||||||
|  |           ImageView( | ||||||
|  |             image: PathAssets.imgProduct, | ||||||
|  |             width: SizeConfig.width * .13, | ||||||
|  |           ), | ||||||
|  |           const SizedBox(width: 8), | ||||||
|  |           Expanded( | ||||||
|  |             child: Column( | ||||||
|  |               crossAxisAlignment: CrossAxisAlignment.start, | ||||||
|  |               children: [ | ||||||
|  |                 const TextTitle(title: 'Gemilang Dana Kas Maxima', fontSize: 16,), | ||||||
|  |                 const SizedBox(height: 4), | ||||||
|  |                 Container( | ||||||
|  |                   padding: const EdgeInsets.all(6), | ||||||
|  |                   decoration: BoxDecoration( | ||||||
|  |                       borderRadius: BorderRadius.circular(40), | ||||||
|  |                       color: ColorPalette.investTypeBgColor['Money Market']?.withOpacity(0.5) ?? Colors.white, | ||||||
|  |                       border: Border.all(width: 2, color: ColorPalette.investTypeColor['Money Market']?.withOpacity(0.4) ?? Colors.white) | ||||||
|  |                   ), | ||||||
|  |                   child: Text( | ||||||
|  |                     'Money Market' ?? '', | ||||||
|  |                     style: TextStyle( | ||||||
|  |                         color: ColorPalette.investTypeColor['Money Market'], | ||||||
|  |                         fontWeight: FontWeight.w600 | ||||||
|  |                     ), | ||||||
|  |                   ), | ||||||
|  |                 ) | ||||||
|  |               ], | ||||||
|  |             ), | ||||||
|  |           ) | ||||||
|  |         ], | ||||||
|  |       ), | ||||||
|  |     ); | ||||||
|  |   } | ||||||
|  |  | ||||||
|  |   Widget segmentAmount(context, double currentAmount, double currentUnit, void Function(double value) setUnit) { | ||||||
|  |     double sliderValue = currentUnit / Provider.of<RedeemProductViewModel>(context, listen: false).getCurrentProduct.totalUnit!; | ||||||
|  |     return Column( | ||||||
|  |       children: [ | ||||||
|  |         const Align( | ||||||
|  |           alignment: Alignment.centerLeft, | ||||||
|  |           child: Text('Amount', | ||||||
|  |             style: TextStyle( | ||||||
|  |               fontWeight: FontWeight.w600, | ||||||
|  |               color: ColorPalette.slate800, | ||||||
|  |               fontSize: 16 | ||||||
|  |             ), | ||||||
|  |           ), | ||||||
|  |         ), | ||||||
|  |         TextField( | ||||||
|  |           controller: amountController, | ||||||
|  |           textAlign: TextAlign.center, | ||||||
|  |           style: const TextStyle( | ||||||
|  |               fontSize: 28, | ||||||
|  |               fontWeight: FontWeight.w700, | ||||||
|  |               color: ColorPalette.slate800 | ||||||
|  |           ), | ||||||
|  |           keyboardType: TextInputType.number, | ||||||
|  |           readOnly: true, | ||||||
|  |           decoration: InputDecoration( | ||||||
|  |             enabledBorder: const UnderlineInputBorder( | ||||||
|  |               borderSide: BorderSide( | ||||||
|  |                   color: ColorPalette.slate200, | ||||||
|  |                   width: 1 | ||||||
|  |               ), | ||||||
|  |             ), | ||||||
|  |             suffixIcon: GestureDetector( | ||||||
|  |               onTap: () { | ||||||
|  |                 Navigator.pop(context); | ||||||
|  |                 showModalBottomSheet( | ||||||
|  |                   context: context, | ||||||
|  |                   isScrollControlled: true, | ||||||
|  |                   builder: (context) { | ||||||
|  |                     return ChangeAmount( | ||||||
|  |                       totalAmount: currentAmount.toInt(), | ||||||
|  |                     ); | ||||||
|  |                   }, | ||||||
|  |                 ); | ||||||
|  |               }, | ||||||
|  |               child: const Icon(Icons.edit, color: ColorPalette.primary), | ||||||
|  |             ) | ||||||
|  |           ), | ||||||
|  |         ), | ||||||
|  |         Padding( | ||||||
|  |           padding: const EdgeInsets.symmetric(vertical: 20), | ||||||
|  |           child: Row( | ||||||
|  |             mainAxisAlignment: MainAxisAlignment.center, | ||||||
|  |             children: [ | ||||||
|  |               Text(currentUnit.toStringAsFixed(2).replaceAll('.', ','), | ||||||
|  |                 style: const TextStyle( | ||||||
|  |                   fontWeight: FontWeight.w700, | ||||||
|  |                   fontSize: 18, | ||||||
|  |                   color: ColorPalette.slate800 | ||||||
|  |                 ), | ||||||
|  |               ), | ||||||
|  |               const Text(' unit', | ||||||
|  |                 style: TextStyle( | ||||||
|  |                   fontWeight: FontWeight.w600, | ||||||
|  |                   color: ColorPalette.slate400 | ||||||
|  |                 ), | ||||||
|  |               ) | ||||||
|  |             ], | ||||||
|  |           ), | ||||||
|  |         ), | ||||||
|  |         Row( | ||||||
|  |           children: [ | ||||||
|  |             Expanded( | ||||||
|  |               child: SliderTheme( | ||||||
|  |                 data: SliderTheme.of(context).copyWith( | ||||||
|  |                   trackHeight: 4.0, | ||||||
|  |                   thumbColor: ColorPalette.primary, | ||||||
|  |                   thumbShape: const RoundSliderThumbShape(enabledThumbRadius: 10.0), | ||||||
|  |                   overlayColor:Colors.deepPurple, | ||||||
|  |                   inactiveTickMarkColor: ColorPalette.primary, | ||||||
|  |                   inactiveTrackColor: ColorPalette.slate200, | ||||||
|  |                   overlayShape: SliderComponentShape.noOverlay | ||||||
|  |                 ), | ||||||
|  |                 child: Slider( | ||||||
|  |                   value: sliderValue, | ||||||
|  |                   onChanged: setUnit, | ||||||
|  |                   label: sliderValue.round().toString(), | ||||||
|  |                 ), | ||||||
|  |               ), | ||||||
|  |             ), | ||||||
|  |             SizedBox(width: 12), | ||||||
|  |             Text('${(sliderValue * 100).toStringAsFixed(2)} %', | ||||||
|  |               style: const TextStyle( | ||||||
|  |                 color: ColorPalette.slate800, | ||||||
|  |                 fontWeight: FontWeight.w600 | ||||||
|  |               ), | ||||||
|  |             ) | ||||||
|  |           ], | ||||||
|  |         ) | ||||||
|  |       ], | ||||||
|  |     ); | ||||||
|  |   } | ||||||
|  |  | ||||||
|  |   Widget segmentDestinationAcc(Account account) { | ||||||
|  |     List<String> listNumber = []; | ||||||
|  |  | ||||||
|  |     List.generate(account.number.length, (index) { | ||||||
|  |       if(index > 3 && index < account.number.length - 4){ | ||||||
|  |         listNumber.add('*'); | ||||||
|  |       }else{ | ||||||
|  |         listNumber.add(account.number[index]); | ||||||
|  |       } | ||||||
|  |     }); | ||||||
|  |  | ||||||
|  |     return Column( | ||||||
|  |       crossAxisAlignment: CrossAxisAlignment.start, | ||||||
|  |       children: [ | ||||||
|  |         const Text('Destination Account', | ||||||
|  |           style: TextStyle( | ||||||
|  |               fontWeight: FontWeight.w600, | ||||||
|  |               color: ColorPalette.slate800, | ||||||
|  |               fontSize: 16 | ||||||
|  |           ), | ||||||
|  |         ), | ||||||
|  |         const SizedBox(height: 16), | ||||||
|  |         Container( | ||||||
|  |           padding: const EdgeInsets.all(16), | ||||||
|  |           decoration: BoxDecoration( | ||||||
|  |             borderRadius: BorderRadius.circular(14), | ||||||
|  |             border: Border.all(color: ColorPalette.slate200) | ||||||
|  |           ), | ||||||
|  |           child: Row( | ||||||
|  |             mainAxisAlignment: MainAxisAlignment.spaceBetween, | ||||||
|  |             children: [ | ||||||
|  |               Expanded( | ||||||
|  |                 child: Row( | ||||||
|  |                   mainAxisAlignment: MainAxisAlignment.spaceBetween, | ||||||
|  |                   children: [ | ||||||
|  |                     Column( | ||||||
|  |                       crossAxisAlignment: CrossAxisAlignment.start, | ||||||
|  |                       children: [ | ||||||
|  |                         Text(account.nameOwner, | ||||||
|  |                           style: const TextStyle( | ||||||
|  |                             fontSize: 16, | ||||||
|  |                             fontWeight: FontWeight.w600, | ||||||
|  |                             color: ColorPalette.slate800 | ||||||
|  |                           ), | ||||||
|  |                         ), | ||||||
|  |                         Text('${account.nameBank} - ${listNumber.join("")}', | ||||||
|  |                           style: const TextStyle( | ||||||
|  |                               fontSize: 16, | ||||||
|  |                               fontWeight: FontWeight.w600, | ||||||
|  |                               color: ColorPalette.slate400 | ||||||
|  |                           ), | ||||||
|  |                         ) | ||||||
|  |                       ], | ||||||
|  |                     ), | ||||||
|  |                   ], | ||||||
|  |                 ), | ||||||
|  |               ), | ||||||
|  |               GestureDetector( | ||||||
|  |                 onTap: () { | ||||||
|  |                   Navigator.pop(context); | ||||||
|  |                   showModalBottomSheet( | ||||||
|  |                     context: context, | ||||||
|  |                     isScrollControlled: true, | ||||||
|  |                     builder: (context) => const ChangeDestinationAccount(), | ||||||
|  |                   ); | ||||||
|  |                 }, | ||||||
|  |                 child: Container( | ||||||
|  |                   padding: const EdgeInsets.symmetric(horizontal: 12, vertical: 6), | ||||||
|  |                   decoration: BoxDecoration( | ||||||
|  |                     borderRadius: BorderRadius.circular(18), | ||||||
|  |                     color: ColorPalette.blue200.withOpacity(0.5) | ||||||
|  |                   ), | ||||||
|  |                   child: const Row( | ||||||
|  |                     children: [ | ||||||
|  |                       Icon(Icons.change_circle_outlined, color: ColorPalette.primary, size: 20), | ||||||
|  |                       SizedBox(width: 4), | ||||||
|  |                       Text('Change', | ||||||
|  |                         style: TextStyle( | ||||||
|  |                             fontSize: 16, | ||||||
|  |                             fontWeight: FontWeight.w600, | ||||||
|  |                             color: ColorPalette.primary | ||||||
|  |                         ), | ||||||
|  |                       ) | ||||||
|  |                     ], | ||||||
|  |                   ), | ||||||
|  |                 ), | ||||||
|  |               ) | ||||||
|  |             ], | ||||||
|  |           ), | ||||||
|  |         ) | ||||||
|  |       ], | ||||||
|  |     ); | ||||||
|  |   } | ||||||
|  | } | ||||||
| @@ -0,0 +1,205 @@ | |||||||
|  | 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/radio_agreement.dart'; | ||||||
|  | import 'package:cims_apps/application/component/text_title/text_title.dart'; | ||||||
|  | import 'package:cims_apps/application/theme/color_palette.dart'; | ||||||
|  | import 'package:cims_apps/core/utils/number_formatter.dart'; | ||||||
|  | import 'package:cims_apps/core/utils/size_config.dart'; | ||||||
|  | import 'package:cims_apps/features/dashboard/dashboard_account/view/portfolio/redeem_product/view_model/redeem_product_view_model.dart'; | ||||||
|  | import 'package:flutter/material.dart'; | ||||||
|  | import 'package:provider/provider.dart'; | ||||||
|  |  | ||||||
|  | class TotalRedeem extends StatelessWidget { | ||||||
|  |   const TotalRedeem({super.key}); | ||||||
|  |  | ||||||
|  |   @override | ||||||
|  |   Widget build(BuildContext context) { | ||||||
|  |     return ChangeNotifierProvider( | ||||||
|  |       create: (context) => RedeemProductViewModel(), | ||||||
|  |       child: Consumer<RedeemProductViewModel>( | ||||||
|  |         builder: (context, provider, child) { | ||||||
|  |           return Column( | ||||||
|  |             mainAxisSize: MainAxisSize.min, | ||||||
|  |             children: [ | ||||||
|  |               Padding( | ||||||
|  |                 padding: const EdgeInsets.symmetric(horizontal: 24, vertical: 16), | ||||||
|  |                 child: Row( | ||||||
|  |                   mainAxisAlignment: MainAxisAlignment.spaceBetween, | ||||||
|  |                   children: [ | ||||||
|  |                     const Text('Investment Funds that You Cash Out', | ||||||
|  |                       style: TextStyle( | ||||||
|  |                           fontWeight: FontWeight.w600, | ||||||
|  |                           color: ColorPalette.slate800, | ||||||
|  |                           fontSize: 16 | ||||||
|  |                       ), | ||||||
|  |                     ), | ||||||
|  |                     GestureDetector( | ||||||
|  |                         onTap: () => Navigator.pop(context), | ||||||
|  |                         child: const Icon(Icons.close_rounded, color: ColorPalette.slate800,) | ||||||
|  |                     ) | ||||||
|  |                   ], | ||||||
|  |                 ), | ||||||
|  |               ), | ||||||
|  |               const Divider(height: 1, color: ColorPalette.slate200,), | ||||||
|  |               Padding( | ||||||
|  |                 padding: const EdgeInsets.symmetric(horizontal: 24, vertical: 16), | ||||||
|  |                 child: cardProduct(provider.getCurrentProduct, provider.getUnit!), | ||||||
|  |               ), | ||||||
|  |               const Padding( | ||||||
|  |                 padding: EdgeInsets.symmetric(horizontal: 24), | ||||||
|  |                 child: Row( | ||||||
|  |                   mainAxisAlignment: MainAxisAlignment.spaceBetween, | ||||||
|  |                   children: [ | ||||||
|  |                     Text('Sales Commission', | ||||||
|  |                       style: TextStyle( | ||||||
|  |                         color: ColorPalette.slate400, | ||||||
|  |                         fontSize: 16 | ||||||
|  |                       ), | ||||||
|  |                     ), | ||||||
|  |                     Text('Free', | ||||||
|  |                       style: TextStyle( | ||||||
|  |                         fontWeight: FontWeight.w600, | ||||||
|  |                         color: ColorPalette.primary, | ||||||
|  |                         fontSize: 16 | ||||||
|  |                       ), | ||||||
|  |                     ) | ||||||
|  |                   ], | ||||||
|  |                 ), | ||||||
|  |               ), | ||||||
|  |               const SizedBox(height: 16), | ||||||
|  |               const Padding( | ||||||
|  |                 padding: EdgeInsets.symmetric(horizontal: 24), | ||||||
|  |                 child: Row( | ||||||
|  |                   mainAxisAlignment: MainAxisAlignment.spaceBetween, | ||||||
|  |                   children: [ | ||||||
|  |                     Text('Cash Out Method', | ||||||
|  |                       style: TextStyle( | ||||||
|  |                           color: ColorPalette.slate400, | ||||||
|  |                           fontSize: 16 | ||||||
|  |                       ), | ||||||
|  |                     ), | ||||||
|  |                     Text('Regular', | ||||||
|  |                       style: TextStyle( | ||||||
|  |                           fontWeight: FontWeight.w600, | ||||||
|  |                           color: ColorPalette.primary, | ||||||
|  |                           fontSize: 16 | ||||||
|  |                       ), | ||||||
|  |                     ) | ||||||
|  |                   ], | ||||||
|  |                 ), | ||||||
|  |               ), | ||||||
|  |               const SizedBox(height: 16,), | ||||||
|  |               Container( | ||||||
|  |                 padding: EdgeInsets.symmetric(horizontal: 24, vertical: 16), | ||||||
|  |                 color: ColorPalette.slate200.withOpacity(0.5), | ||||||
|  |                 child: Row( | ||||||
|  |                   mainAxisAlignment: MainAxisAlignment.spaceBetween, | ||||||
|  |                   children: [ | ||||||
|  |                     Expanded( | ||||||
|  |                       child: TextTitle( | ||||||
|  |                         title: 'Estimated Funds Disbursed', | ||||||
|  |                         color: ColorPalette.slate500, | ||||||
|  |                         fontSize: 16, | ||||||
|  |                       ) | ||||||
|  |                     ), | ||||||
|  |                     Expanded( | ||||||
|  |                       child: Text( | ||||||
|  |                         NumberFormatter.numberCurrency((provider.getCurrentProduct.priceUnit! * provider.getUnit!).toInt(), 'Rp ', 'id_ID', decimalDigits: 0), | ||||||
|  |                         textAlign: TextAlign.end, | ||||||
|  |                         style: TextStyle( | ||||||
|  |                           color: ColorPalette.slate800, | ||||||
|  |                           fontWeight: FontWeight.w700, | ||||||
|  |                           fontSize: 18 | ||||||
|  |                         ), | ||||||
|  |                       ) | ||||||
|  |                     ) | ||||||
|  |                   ], | ||||||
|  |                 ), | ||||||
|  |               ), | ||||||
|  |               RadioAgreement( | ||||||
|  |                 isAgree: provider.isAgree, | ||||||
|  |                 desc: 'I agree to the sale of the mutual funds listed on this page. I understand that the total funds disbursed are approximate. The amount received may change according to the closing price of the mutual fund on the day of sale.', | ||||||
|  |                 onTap: provider.setAgree | ||||||
|  |               ), | ||||||
|  |               const SizedBox(height: 24), | ||||||
|  |               ButtonView( | ||||||
|  |                 disabled: !provider.isAgree, | ||||||
|  |                 name: 'Redeem', | ||||||
|  |                 textSize: 20, | ||||||
|  |                 marginVertical: 0, | ||||||
|  |                 disabledBgColor: ColorPalette.slate200.withOpacity(0.5), | ||||||
|  |                 textColor: !provider.isAgree ? ColorPalette.slate400 : Colors.white, | ||||||
|  |                 onPressed: () { | ||||||
|  |                   Navigator.pop(context); | ||||||
|  |                   showModalBottomSheet( | ||||||
|  |                     context: context, | ||||||
|  |                     isScrollControlled: true, | ||||||
|  |                     builder: (context) { | ||||||
|  |                       return TotalRedeem(); | ||||||
|  |                     }, | ||||||
|  |                   ); | ||||||
|  |                 }, | ||||||
|  |               ), | ||||||
|  |               const SizedBox(height: 24) | ||||||
|  |             ], | ||||||
|  |           ); | ||||||
|  |         } | ||||||
|  |       ), | ||||||
|  |     ); | ||||||
|  |   } | ||||||
|  |  | ||||||
|  |   Widget cardProduct(PortfolioProduct product, double currentUnit) { | ||||||
|  |     return Container( | ||||||
|  |       padding: const EdgeInsets.all(16), | ||||||
|  |       decoration: BoxDecoration( | ||||||
|  |           color: Colors.white, | ||||||
|  |           borderRadius: BorderRadius.circular(12), | ||||||
|  |           border: Border.all(color: ColorPalette.slate200), | ||||||
|  |           boxShadow: [ | ||||||
|  |             BoxShadow( | ||||||
|  |                 color: const Color(0xff1E293B).withOpacity(0.04), | ||||||
|  |                 blurRadius: 8, | ||||||
|  |                 spreadRadius: 2 | ||||||
|  |             ) | ||||||
|  |           ] | ||||||
|  |       ), | ||||||
|  |       child: Row( | ||||||
|  |         crossAxisAlignment: CrossAxisAlignment.start, | ||||||
|  |         children: [ | ||||||
|  |           ImageView( | ||||||
|  |             image: PathAssets.imgProduct, | ||||||
|  |             width: SizeConfig.width * .13, | ||||||
|  |           ), | ||||||
|  |           const SizedBox(width: 8), | ||||||
|  |           Expanded( | ||||||
|  |             child: Column( | ||||||
|  |               crossAxisAlignment: CrossAxisAlignment.start, | ||||||
|  |               children: [ | ||||||
|  |                 TextTitle(title: product.name ?? '', fontSize: 16,), | ||||||
|  |                 const SizedBox(height: 4), | ||||||
|  |                 Row( | ||||||
|  |                   children: [ | ||||||
|  |                     Text(currentUnit.toStringAsFixed(2).replaceAll('.', ','), | ||||||
|  |                       style: const TextStyle( | ||||||
|  |                           fontWeight: FontWeight.w700, | ||||||
|  |                           fontSize: 18, | ||||||
|  |                           color: ColorPalette.slate800 | ||||||
|  |                       ), | ||||||
|  |                     ), | ||||||
|  |                     const Text(' unit', | ||||||
|  |                       style: TextStyle( | ||||||
|  |                           fontWeight: FontWeight.w600, | ||||||
|  |                           color: ColorPalette.slate400 | ||||||
|  |                       ), | ||||||
|  |                     ) | ||||||
|  |                   ], | ||||||
|  |                 ), | ||||||
|  |               ], | ||||||
|  |             ), | ||||||
|  |           ) | ||||||
|  |         ], | ||||||
|  |       ), | ||||||
|  |     ); | ||||||
|  |   } | ||||||
|  | } | ||||||
| @@ -0,0 +1,73 @@ | |||||||
|  | import 'package:flutter/material.dart'; | ||||||
|  |  | ||||||
|  | class Account { | ||||||
|  |   String nameOwner, nameBank, number; | ||||||
|  |  | ||||||
|  |   Account(this.nameOwner, this.nameBank, this.number); | ||||||
|  | } | ||||||
|  |  | ||||||
|  | class PortfolioProduct { | ||||||
|  |   String? name, type; | ||||||
|  |   double? yield; | ||||||
|  |   double? priceUnit, funds, totalPercent, totalUnit; | ||||||
|  |  | ||||||
|  |   PortfolioProduct({this.name, this.type, this.yield, this.priceUnit, this.funds, this.totalPercent = 1, this.totalUnit}); | ||||||
|  | } | ||||||
|  |  | ||||||
|  | class RedeemProductViewModel extends ChangeNotifier { | ||||||
|  |   static Account currentAccount = Account('Muhamad Rosyidin', 'BRI', '902139012324'); | ||||||
|  |   static PortfolioProduct currentProduct = | ||||||
|  |     PortfolioProduct( | ||||||
|  |       name: 'Gemilang Dana Kas Maxima', | ||||||
|  |       type: '', | ||||||
|  |       yield: 8.17, | ||||||
|  |       priceUnit: 2600.79, | ||||||
|  |       funds: 6300000, | ||||||
|  |       totalUnit: 25 | ||||||
|  |   ); | ||||||
|  |  | ||||||
|  |   static double? amount; | ||||||
|  |   static double? unit; | ||||||
|  |   Account? selectedAccount; | ||||||
|  |  | ||||||
|  |   Account get getCurrentAccount => currentAccount; | ||||||
|  |   PortfolioProduct get getCurrentProduct => currentProduct; | ||||||
|  |   double? get getAmount => amount; | ||||||
|  |   double? get getUnit => unit; | ||||||
|  |  | ||||||
|  |   bool isAgree = false; | ||||||
|  |  | ||||||
|  |   void setCurrentAcc(Account account) { | ||||||
|  |     currentAccount = account; | ||||||
|  |     notifyListeners(); | ||||||
|  |   } | ||||||
|  |  | ||||||
|  |   void setSelectedAcc(Account account){ | ||||||
|  |     selectedAccount = account; | ||||||
|  |     notifyListeners(); | ||||||
|  |   } | ||||||
|  |  | ||||||
|  |   void setAmount(double amount) { | ||||||
|  |     amount = amount; | ||||||
|  |     unit = (amount / currentProduct.priceUnit!); | ||||||
|  |     notifyListeners(); | ||||||
|  |   } | ||||||
|  |  | ||||||
|  |   void setUnit(double value){ | ||||||
|  |     unit = currentProduct.totalUnit! * value; | ||||||
|  |     amount = unit! * currentProduct.priceUnit!; | ||||||
|  |     notifyListeners(); | ||||||
|  |   } | ||||||
|  |  | ||||||
|  |   void setProduct(PortfolioProduct product) { | ||||||
|  |     currentProduct = product; | ||||||
|  |     amount = product.priceUnit! * (product.totalUnit! / 2.0); | ||||||
|  |     unit = (product.totalUnit! / 2.0); | ||||||
|  |     notifyListeners(); | ||||||
|  |   } | ||||||
|  |  | ||||||
|  |   void setAgree() { | ||||||
|  |     isAgree = !isAgree; | ||||||
|  |     notifyListeners(); | ||||||
|  |   } | ||||||
|  | } | ||||||
| @@ -13,6 +13,7 @@ import 'package:cims_apps/features/dashboard/dashboard_account/view/product/view | |||||||
| import 'package:cims_apps/features/dashboard/dashboard_account/view/product/view/step_subscribe/select_goal_investing.dart'; | import 'package:cims_apps/features/dashboard/dashboard_account/view/product/view/step_subscribe/select_goal_investing.dart'; | ||||||
| import 'package:cims_apps/features/dashboard/dashboard_account/view/product/view_model/product_view_model.dart'; | import 'package:cims_apps/features/dashboard/dashboard_account/view/product/view_model/product_view_model.dart'; | ||||||
| import 'package:flutter/material.dart'; | import 'package:flutter/material.dart'; | ||||||
|  | import 'package:flutter/services.dart'; | ||||||
| import 'package:group_button/group_button.dart'; | import 'package:group_button/group_button.dart'; | ||||||
| import 'package:provider/provider.dart'; | import 'package:provider/provider.dart'; | ||||||
|  |  | ||||||
| @@ -24,8 +25,9 @@ class Time { | |||||||
| } | } | ||||||
|  |  | ||||||
| class ProductView extends StatefulWidget { | class ProductView extends StatefulWidget { | ||||||
|   final String investType; |   final bool seeMore; | ||||||
|   const ProductView(this.investType, {super.key}); |   final Product selectedProduct; | ||||||
|  |   const ProductView({super.key, required this.selectedProduct, this.seeMore = false}); | ||||||
|  |  | ||||||
|   @override |   @override | ||||||
|   State<ProductView> createState() => _ProductViewState(); |   State<ProductView> createState() => _ProductViewState(); | ||||||
| @@ -78,6 +80,8 @@ class _ProductViewState extends State<ProductView> { | |||||||
|     }); |     }); | ||||||
|   } |   } | ||||||
|  |  | ||||||
|  |   double currentScroll = 0; | ||||||
|  |  | ||||||
|   @override |   @override | ||||||
|   void initState() { |   void initState() { | ||||||
|     machineController.text = NumberFormatter.numberCurrency(100000, 'Rp ', 'id_ID', decimalDigits: 0); |     machineController.text = NumberFormatter.numberCurrency(100000, 'Rp ', 'id_ID', decimalDigits: 0); | ||||||
| @@ -103,48 +107,91 @@ class _ProductViewState extends State<ProductView> { | |||||||
|     return ChangeNotifierProvider( |     return ChangeNotifierProvider( | ||||||
|       create: (context) => ProductViewModel(), |       create: (context) => ProductViewModel(), | ||||||
|       child: Scaffold( |       child: Scaffold( | ||||||
|         body: SizedBox( |         body: NotificationListener<ScrollNotification>( | ||||||
|           child: Stack( |           onNotification: (notification) { | ||||||
|             children: [ |             setState(() { | ||||||
|               const ImageView(image: PathAssets.imgDashboardAccount), |               currentScroll = notification.metrics.pixels; | ||||||
|               Column( |             }); | ||||||
|                 children: [ |             return false; | ||||||
|                   const SizedBox( |           }, | ||||||
|                     height: 50, |           child: CustomScrollView( | ||||||
|                   ), |             slivers: [ | ||||||
|                   const Padding( |               SliverAppBar( | ||||||
|                     padding: EdgeInsets.symmetric(horizontal: 24), |                 toolbarHeight: 70, | ||||||
|                     child: Row( |                 expandedHeight: 170, | ||||||
|                       mainAxisAlignment: MainAxisAlignment.spaceBetween, |                 leadingWidth: 0, | ||||||
|                       children: [ |                 floating: false, | ||||||
|                         BackButtonView(), |                 automaticallyImplyLeading: false, | ||||||
|                         Wrap( |                 title: AnimatedCrossFade( | ||||||
|                           spacing: 12, |                   firstChild:  Text( | ||||||
|                           children: [ |                     widget.selectedProduct.name ?? '', | ||||||
|                             Icon(Icons.search_rounded, color: ColorPalette.blue200, size: 32), |                     maxLines: 2, | ||||||
|                             Icon(Icons.file_download_outlined, color: ColorPalette.blue200, size: 32), |                     overflow: TextOverflow.ellipsis, | ||||||
|                             Icon(Icons.star_outline_rounded, color: ColorPalette.blue200, size: 32) |                     style: TextStyle( | ||||||
|                           ], |                         color: Colors.white, | ||||||
|                         ) |                         fontWeight: FontWeight.w700, | ||||||
|                       ], |                         fontSize: 18 | ||||||
|                     ), |                     ), | ||||||
|                   ), |                   ), | ||||||
|                   const SizedBox( |                   secondChild: Padding( | ||||||
|                     height: 24, |                     padding: const EdgeInsets.only(left: 8), | ||||||
|  |                     child: BackButtonView(), | ||||||
|                   ), |                   ), | ||||||
|                   headContainer(), |                   crossFadeState: currentScroll >= 85 ? CrossFadeState.showFirst : CrossFadeState.showSecond, | ||||||
|                   const SizedBox( |                   duration: Duration(milliseconds: 200) | ||||||
|                     height: 24, |                 ), | ||||||
|  |                 centerTitle: false, | ||||||
|  |                 snap: false, | ||||||
|  |                 pinned: true, | ||||||
|  |                 backgroundColor: Color(0xFF1745C8).withOpacity(currentScroll >= 95 ? 1 : currentScroll / 95), | ||||||
|  |                 surfaceTintColor: ColorPalette.primary, | ||||||
|  |                 actions: [ | ||||||
|  |                   Wrap( | ||||||
|  |                     spacing: 12, | ||||||
|  |                     children: [ | ||||||
|  |                       Icon(Icons.search_rounded, color: ColorPalette.blue200, size: 32), | ||||||
|  |                       Icon(Icons.file_download_outlined, color: ColorPalette.blue200, size: 32), | ||||||
|  |                       Icon(Icons.star_outline_rounded, color: ColorPalette.blue200, size: 32) | ||||||
|  |                     ], | ||||||
|                   ), |                   ), | ||||||
|                   Expanded( |                   SizedBox(width: 24,) | ||||||
|                     child: contentContainer() |  | ||||||
|                   ) |  | ||||||
|                 ], |                 ], | ||||||
|  |                 flexibleSpace: Opacity( | ||||||
|  |                   opacity: currentScroll > 0 ? ((95 - currentScroll) / 95) > 0.01 ? ((95 - currentScroll) / 95) : 0 : 1, | ||||||
|  |                   child: Stack( | ||||||
|  |                     children: [ | ||||||
|  |                       ImageView(image: PathAssets.imgDashboardAccount, width: SizeConfig.width, height: 200), | ||||||
|  |                       Column( | ||||||
|  |                         mainAxisAlignment: MainAxisAlignment.end, | ||||||
|  |                         children: [ | ||||||
|  |                           headContainer(), | ||||||
|  |                           const SizedBox( | ||||||
|  |                             height: 24, | ||||||
|  |                           ), | ||||||
|  |                           Container( | ||||||
|  |                             height: 12, | ||||||
|  |                             decoration: BoxDecoration( | ||||||
|  |                                 color: Colors.white, | ||||||
|  |                                 borderRadius: BorderRadius.only( | ||||||
|  |                                     topLeft: Radius.circular(12), | ||||||
|  |                                     topRight: Radius.circular(12) | ||||||
|  |                                 ) | ||||||
|  |                             ), | ||||||
|  |                           ) | ||||||
|  |                         ], | ||||||
|  |                       ) | ||||||
|  |                     ], | ||||||
|  |                   ), | ||||||
|  |                 ), | ||||||
|  |               ), | ||||||
|  |               SliverToBoxAdapter( | ||||||
|  |                 child: contentContainer(), | ||||||
|               ) |               ) | ||||||
|             ], |             ], | ||||||
|           ), |           ), | ||||||
|         ), |         ), | ||||||
|         bottomNavigationBar: Container( |         bottomNavigationBar: !widget.seeMore ? | ||||||
|  |         Container( | ||||||
|           height: SizeConfig.height * .1, |           height: SizeConfig.height * .1, | ||||||
|           padding: const EdgeInsets.symmetric(horizontal: 24), |           padding: const EdgeInsets.symmetric(horizontal: 24), | ||||||
|           child: ButtonView( |           child: ButtonView( | ||||||
| @@ -159,7 +206,7 @@ class _ProductViewState extends State<ProductView> { | |||||||
|             height: SizeConfig.height * 0.06, |             height: SizeConfig.height * 0.06, | ||||||
|             marginVertical: 16, |             marginVertical: 16, | ||||||
|           ), |           ), | ||||||
|         ), |         ) : SizedBox(), | ||||||
|       ), |       ), | ||||||
|     ); |     ); | ||||||
|   } |   } | ||||||
| @@ -177,7 +224,7 @@ class _ProductViewState extends State<ProductView> { | |||||||
|                   SizedBox(width: 8), |                   SizedBox(width: 8), | ||||||
|                   Expanded( |                   Expanded( | ||||||
|                     child: Text( |                     child: Text( | ||||||
|                       'Gemilang Dana Kas Maxima', |                       widget.selectedProduct.name ?? '', | ||||||
|                       maxLines: 2, |                       maxLines: 2, | ||||||
|                       overflow: TextOverflow.ellipsis, |                       overflow: TextOverflow.ellipsis, | ||||||
|                       style: TextStyle( |                       style: TextStyle( | ||||||
| @@ -190,17 +237,18 @@ class _ProductViewState extends State<ProductView> { | |||||||
|                 ], |                 ], | ||||||
|               ), |               ), | ||||||
|             ), |             ), | ||||||
|  |             SizedBox(width: 12), | ||||||
|             Container( |             Container( | ||||||
|               padding: const EdgeInsets.all(6), |               padding: const EdgeInsets.all(6), | ||||||
|               decoration: BoxDecoration( |               decoration: BoxDecoration( | ||||||
|                   borderRadius: BorderRadius.circular(40), |                   borderRadius: BorderRadius.circular(40), | ||||||
|                   color: ColorPalette.investTypeBgColor[widget.investType] ?? Colors.white, |                   color: ColorPalette.investTypeBgColor[widget.selectedProduct.type] ?? Colors.white, | ||||||
|                   border: Border.all(width: 2, color: ColorPalette.investTypeColor[widget.investType] ?? Colors.white) |                   border: Border.all(width: 2, color: ColorPalette.investTypeColor[widget.selectedProduct.type] ?? Colors.white) | ||||||
|               ), |               ), | ||||||
|               child: Text( |               child: Text( | ||||||
|                 widget.investType, |                 widget.selectedProduct.type ?? '', | ||||||
|                 style: TextStyle( |                 style: TextStyle( | ||||||
|                     color: ColorPalette.investTypeColor[widget.investType], |                     color: ColorPalette.investTypeColor[widget.selectedProduct.type], | ||||||
|                     fontWeight: FontWeight.w600 |                     fontWeight: FontWeight.w600 | ||||||
|                 ), |                 ), | ||||||
|               ), |               ), | ||||||
| @@ -217,8 +265,11 @@ class _ProductViewState extends State<ProductView> { | |||||||
|         decoration: BoxDecoration( |         decoration: BoxDecoration( | ||||||
|           color: Colors.white, |           color: Colors.white, | ||||||
|         ), |         ), | ||||||
|         child: ListView( |         child: Column( | ||||||
|           children: [ |           children: [ | ||||||
|  |             const SizedBox( | ||||||
|  |               height: 12, | ||||||
|  |             ), | ||||||
|             ProductChartView( |             ProductChartView( | ||||||
|               tabType: listTab[selectedTab], |               tabType: listTab[selectedTab], | ||||||
|               lastTime: selectedTime.completeName, |               lastTime: selectedTime.completeName, | ||||||
|   | |||||||
| @@ -2,6 +2,7 @@ import 'package:cims_apps/application/component/subscribe/goal_investing_view.da | |||||||
| import 'package:cims_apps/application/component/subscribe/input_investment_view.dart'; | import 'package:cims_apps/application/component/subscribe/input_investment_view.dart'; | ||||||
| import 'package:cims_apps/application/component/subscribe/total_payment_view.dart'; | import 'package:cims_apps/application/component/subscribe/total_payment_view.dart'; | ||||||
| import 'package:cims_apps/application/theme/color_palette.dart'; | import 'package:cims_apps/application/theme/color_palette.dart'; | ||||||
|  | import 'package:cims_apps/features/dashboard/dashboard_account/view/plan/view_model/plan_view_model.dart'; | ||||||
| import 'package:cims_apps/features/dashboard/dashboard_account/view/product/view_model/product_view_model.dart'; | import 'package:cims_apps/features/dashboard/dashboard_account/view/product/view_model/product_view_model.dart'; | ||||||
| import 'package:flutter/material.dart'; | import 'package:flutter/material.dart'; | ||||||
| import 'package:provider/provider.dart'; | import 'package:provider/provider.dart'; | ||||||
| @@ -11,10 +12,9 @@ class SelectGoalInvesting extends StatelessWidget { | |||||||
|  |  | ||||||
|   @override |   @override | ||||||
|   Widget build(BuildContext context) { |   Widget build(BuildContext context) { | ||||||
|     return MultiProvider( |  | ||||||
|       providers: [ |     return ChangeNotifierProvider( | ||||||
|         ChangeNotifierProvider(create: (context) => ProductViewModel(),) |       create: (context) => ProductViewModel(), | ||||||
|       ], |  | ||||||
|       child: Consumer<ProductViewModel>( |       child: Consumer<ProductViewModel>( | ||||||
|         builder: (context, provider, child) { |         builder: (context, provider, child) { | ||||||
|           return Container( |           return Container( | ||||||
| @@ -51,23 +51,50 @@ class SelectGoalInvesting extends StatelessWidget { | |||||||
|                       context: context, |                       context: context, | ||||||
|                       isScrollControlled: true, |                       isScrollControlled: true, | ||||||
|                       builder: (context) { |                       builder: (context) { | ||||||
|                         return InputInvestmentView( |                         return ChangeNotifierProvider( | ||||||
|                           selectedPlan: p0, |                           create: (context) => ProductViewModel(), | ||||||
|                           nextMove: (value) { |                           child: Consumer<ProductViewModel>( | ||||||
|                             Navigator.pop(context); |                             builder: (context, provider, child) { | ||||||
|                             int formatIntParse = int.parse(value.replaceAll('Rp ', '').replaceAll(',', '')); |                               return Padding( | ||||||
|                             showModalBottomSheet( |                                 padding: EdgeInsets.symmetric(vertical: 16), | ||||||
|                               context: context, |                                 child: InputInvestmentView( | ||||||
|                               isScrollControlled: true, |                                   currentPlan: p0, | ||||||
|                               builder: (context) => |                                   changePlan: () { | ||||||
|                                 TotalPaymentView( |                                     Navigator.pop(context); | ||||||
|                                   listProduct: [ |                                     showModalBottomSheet( | ||||||
|                                     provider.getSelectedProduct |                                       context: context, | ||||||
|                                   ], |                                       isScrollControlled: true, | ||||||
|                                   totalInvest: formatIntParse, |                                       builder: (context) => SelectGoalInvesting(), | ||||||
|                                 ) |                                     ); | ||||||
|                             ); |                                   }, | ||||||
|                           }, |                                   nextMove: (value) { | ||||||
|  |                                     Navigator.pop(context); | ||||||
|  |                                     int formatIntParse = int.parse(value.replaceAll('Rp ', '').replaceAll('.', '')); | ||||||
|  |                                     showModalBottomSheet( | ||||||
|  |                                       context: context, | ||||||
|  |                                       isScrollControlled: true, | ||||||
|  |                                       builder: (context) => | ||||||
|  |                                         ChangeNotifierProvider( | ||||||
|  |                                           create: (context) => ProductViewModel(), | ||||||
|  |                                           child: Consumer<ProductViewModel>( | ||||||
|  |                                               builder: (context, provider, child) { | ||||||
|  |                                                 return TotalPaymentView( | ||||||
|  |                                                   listProduct: [ | ||||||
|  |                                                     provider.getSelectedProduct | ||||||
|  |                                                   ], | ||||||
|  |                                                   totalInvest: formatIntParse, | ||||||
|  |                                                   isAgree: provider.isAgree, | ||||||
|  |                                                   onTapAgree: provider.setAgree, | ||||||
|  |                                                 ); | ||||||
|  |                                               } | ||||||
|  |                                             ), | ||||||
|  |                                           ) | ||||||
|  |                                     ); | ||||||
|  |                                   }, | ||||||
|  |                                 ), | ||||||
|  |                               ); | ||||||
|  |                             } | ||||||
|  |                           ), | ||||||
|                         ); |                         ); | ||||||
|                       }, |                       }, | ||||||
|                     ); |                     ); | ||||||
|   | |||||||
| @@ -14,6 +14,7 @@ class ProductViewModel extends ChangeNotifier { | |||||||
|   Product get getSelectedProduct => selectedProduct; |   Product get getSelectedProduct => selectedProduct; | ||||||
|  |  | ||||||
|   double totalInvestment = 0; |   double totalInvestment = 0; | ||||||
|  |   bool isAgree = false; | ||||||
|  |  | ||||||
|   void setSelectedProduct(Product product) { |   void setSelectedProduct(Product product) { | ||||||
|     selectedProduct = product; |     selectedProduct = product; | ||||||
| @@ -24,4 +25,9 @@ class ProductViewModel extends ChangeNotifier { | |||||||
|     totalInvestment = value; |     totalInvestment = value; | ||||||
|     notifyListeners(); |     notifyListeners(); | ||||||
|   } |   } | ||||||
|  |  | ||||||
|  |   void setAgree() { | ||||||
|  |     isAgree = !isAgree; | ||||||
|  |     notifyListeners(); | ||||||
|  |   } | ||||||
| } | } | ||||||
| @@ -0,0 +1,165 @@ | |||||||
|  | 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_title/text_title.dart'; | ||||||
|  | import 'package:cims_apps/application/theme/color_palette.dart'; | ||||||
|  | import 'package:cims_apps/core/utils/size_config.dart'; | ||||||
|  | import 'package:cims_apps/features/dashboard/dashboard_account/view/profile/view_model/profile_view_model.dart'; | ||||||
|  | import 'package:flutter/material.dart'; | ||||||
|  | import 'package:provider/provider.dart'; | ||||||
|  |  | ||||||
|  | class RouteNavigation { | ||||||
|  |   String icon; | ||||||
|  |   String title; | ||||||
|  |   Widget destination; | ||||||
|  |  | ||||||
|  |   RouteNavigation(this.icon, this.title, this.destination); | ||||||
|  | } | ||||||
|  |  | ||||||
|  | class ProfileView extends StatelessWidget { | ||||||
|  |   const ProfileView({Key? key}) : super(key: key); | ||||||
|  |  | ||||||
|  |   @override | ||||||
|  |   Widget build(BuildContext context) { | ||||||
|  |     List<RouteNavigation> listGeneral = [ | ||||||
|  |       RouteNavigation(PathAssets.iconProfile, 'Personal Data', Container()), | ||||||
|  |       RouteNavigation(PathAssets.iconPadlock, 'Change Password', Container()), | ||||||
|  |       RouteNavigation(PathAssets.iconCard, 'Add Card', Container()), | ||||||
|  |       RouteNavigation(PathAssets.iconSetting, 'Settings', Container()) | ||||||
|  |     ]; | ||||||
|  |  | ||||||
|  |     List<RouteNavigation> listPreferences = [ | ||||||
|  |       RouteNavigation(PathAssets.iconFaqs, 'FAQs', Container()), | ||||||
|  |       RouteNavigation(PathAssets.iconLogout, 'Log Out', Container()) | ||||||
|  |     ]; | ||||||
|  |  | ||||||
|  |     return Provider( | ||||||
|  |       create: (context) => ProfileViewModel(), | ||||||
|  |       child: Scaffold( | ||||||
|  |         body: SizedBox( | ||||||
|  |           width: SizeConfig.width, | ||||||
|  |           height: SizeConfig.height, | ||||||
|  |           child: Stack( | ||||||
|  |             children: [ | ||||||
|  |               const Positioned( | ||||||
|  |                 left: 0, | ||||||
|  |                 right: 0, | ||||||
|  |                 top: 0, | ||||||
|  |                 bottom: 0, | ||||||
|  |                 child: ImageView(image: PathAssets.imgDashboardProfile) | ||||||
|  |               ), | ||||||
|  |               Consumer<ProfileViewModel>( | ||||||
|  |                 builder: (context, provider, child) { | ||||||
|  |                   return ListView( | ||||||
|  |                     padding: const EdgeInsets.all(0), | ||||||
|  |                     children: [ | ||||||
|  |                       const SizedBox( | ||||||
|  |                         height: 50, | ||||||
|  |                       ), | ||||||
|  |                       const Center( | ||||||
|  |                         child: TextTitle(title: 'Profile', color: Colors.white, fontSize: 20,) | ||||||
|  |                       ), | ||||||
|  |                       SizedBox( | ||||||
|  |                         height: SizeConfig.height * 0.05, | ||||||
|  |                       ), | ||||||
|  |                       Container( | ||||||
|  |                         alignment: Alignment.center, | ||||||
|  |                         decoration: BoxDecoration( | ||||||
|  |                           shape: BoxShape.circle, | ||||||
|  |                           color: Colors.white, | ||||||
|  |                           border: Border.all(color: ColorPalette.slate200, width: 1.5) | ||||||
|  |                         ), | ||||||
|  |                         padding: const EdgeInsets.all(8), | ||||||
|  |                         child: ImageView(image: PathAssets.iconCat, width: SizeConfig.width * 0.14,), | ||||||
|  |                       ), | ||||||
|  |                       const SizedBox(height: 16), | ||||||
|  |                       Center( | ||||||
|  |                         child: TextTitle(title: provider.getUser.name ?? '', color: Colors.white, fontSize: 24,)), | ||||||
|  |                       Text('Investor ${provider.getUser.risk}', | ||||||
|  |                         textAlign: TextAlign.center, | ||||||
|  |                         style: TextStyle( | ||||||
|  |                           fontSize: 16, | ||||||
|  |                           color: ColorPalette.textRiskColor[provider.getUser.risk] | ||||||
|  |                         ), | ||||||
|  |                       ), | ||||||
|  |                       const SizedBox(height: 24), | ||||||
|  |                       boxNavigation('General', listGeneral), | ||||||
|  |                       const SizedBox(height: 24), | ||||||
|  |                       boxNavigation('Preferences', listPreferences) | ||||||
|  |                     ], | ||||||
|  |                   ); | ||||||
|  |                 } | ||||||
|  |               ) | ||||||
|  |             ], | ||||||
|  |           ), | ||||||
|  |         ), | ||||||
|  |       ), | ||||||
|  |     ); | ||||||
|  |   } | ||||||
|  |  | ||||||
|  |   Widget boxNavigation(String title, List<RouteNavigation> list) { | ||||||
|  |     return Container( | ||||||
|  |       padding: const EdgeInsets.all(16), | ||||||
|  |       margin: const EdgeInsets.symmetric(horizontal: 24), | ||||||
|  |       decoration: BoxDecoration( | ||||||
|  |         color: Colors.white, | ||||||
|  |         borderRadius: BorderRadius.circular(12), | ||||||
|  |       ), | ||||||
|  |       child: Column( | ||||||
|  |         crossAxisAlignment: CrossAxisAlignment.start, | ||||||
|  |         children: [ | ||||||
|  |           Text(title, | ||||||
|  |             style: const TextStyle( | ||||||
|  |                 fontWeight: FontWeight.w700, | ||||||
|  |                 color: ColorPalette.slate400 | ||||||
|  |             ), | ||||||
|  |           ), | ||||||
|  |           const SizedBox(height: 16), | ||||||
|  |           Wrap( | ||||||
|  |             runSpacing: 16, | ||||||
|  |             children: list.map((e) { | ||||||
|  |               return rowNavigation( | ||||||
|  |                   e.icon, | ||||||
|  |                   e.title, | ||||||
|  |                   e.destination | ||||||
|  |               ); | ||||||
|  |             }).toList(), | ||||||
|  |           ) | ||||||
|  |         ], | ||||||
|  |       ), | ||||||
|  |     ); | ||||||
|  |   } | ||||||
|  |  | ||||||
|  |   Widget rowNavigation(String icon, String text, Widget destination) { | ||||||
|  |     bool isLogout = text == 'Log Out'; | ||||||
|  |     Color textColor = isLogout ? ColorPalette.red600 : ColorPalette.slate800; | ||||||
|  |     Color bgLeadingColor = isLogout ? ColorPalette.red50 : ColorPalette.blue50; | ||||||
|  |     Color iconColor = isLogout ? ColorPalette.red600 : ColorPalette.blue600; | ||||||
|  |  | ||||||
|  |     return Row( | ||||||
|  |       children: [ | ||||||
|  |         Container( | ||||||
|  |           alignment: Alignment.center, | ||||||
|  |           padding: const EdgeInsets.all(4), | ||||||
|  |           decoration: BoxDecoration( | ||||||
|  |             shape: BoxShape.circle, | ||||||
|  |             color: bgLeadingColor | ||||||
|  |           ), | ||||||
|  |           child: Image.asset(icon, width: SizeConfig.width * 0.05, color: iconColor) | ||||||
|  |         ), | ||||||
|  |         Expanded( | ||||||
|  |           child: Padding( | ||||||
|  |             padding: const EdgeInsets.symmetric(horizontal: 16), | ||||||
|  |             child: Text(text, | ||||||
|  |               style: TextStyle( | ||||||
|  |                 fontWeight: FontWeight.w600, | ||||||
|  |                 fontSize: 16, | ||||||
|  |                 color: textColor | ||||||
|  |               ), | ||||||
|  |             ), | ||||||
|  |           ), | ||||||
|  |         ), | ||||||
|  |         const Icon(Icons.chevron_right_outlined, size: 28, color: ColorPalette.slate400) | ||||||
|  |       ], | ||||||
|  |     ); | ||||||
|  |   } | ||||||
|  | } | ||||||
| @@ -0,0 +1,11 @@ | |||||||
|  | class User { | ||||||
|  |   String? name, risk; | ||||||
|  |  | ||||||
|  |   User({this.name, this.risk}); | ||||||
|  | } | ||||||
|  |  | ||||||
|  | class ProfileViewModel { | ||||||
|  |   static final User _user = User(name: 'Muhammad Rosyidin', risk: 'Conservative'); | ||||||
|  |  | ||||||
|  |   User get getUser => _user; | ||||||
|  | } | ||||||
| @@ -0,0 +1,14 @@ | |||||||
|  | class LoginGmailModel { | ||||||
|  |   String idToken; | ||||||
|  |   String accessToken; | ||||||
|  |  | ||||||
|  |   LoginGmailModel({ | ||||||
|  |     required this.idToken, | ||||||
|  |     required this.accessToken, | ||||||
|  |   }); | ||||||
|  |  | ||||||
|  |   Map<String, String> toJson() => { | ||||||
|  |         "idToken": idToken, | ||||||
|  |         "accessToken": accessToken, | ||||||
|  |       }; | ||||||
|  | } | ||||||
| @@ -5,9 +5,10 @@ import 'package:cims_apps/application/theme/color_palette.dart'; | |||||||
| import 'package:cims_apps/core/route/route.dart'; | import 'package:cims_apps/core/route/route.dart'; | ||||||
| import 'package:cims_apps/core/utils/size_config.dart'; | import 'package:cims_apps/core/utils/size_config.dart'; | ||||||
| import 'package:cims_apps/features/auth/login/view/login_view.dart'; | import 'package:cims_apps/features/auth/login/view/login_view.dart'; | ||||||
| import 'package:cims_apps/features/auth/registration/view/initial_registration_step.dart'; |  | ||||||
| import 'package:cims_apps/features/auth/registration/view/registration_view.dart'; | import 'package:cims_apps/features/auth/registration/view/registration_view.dart'; | ||||||
|  | import 'package:cims_apps/features/dashboard/dashboard_public/viewmodel/dashboard_public_viewmodel.dart'; | ||||||
| import 'package:flutter/material.dart'; | import 'package:flutter/material.dart'; | ||||||
|  | import 'package:provider/provider.dart'; | ||||||
|  |  | ||||||
| class DashboardPublicView extends StatelessWidget { | class DashboardPublicView extends StatelessWidget { | ||||||
|   static const routeName = '/DashboardPublicView'; |   static const routeName = '/DashboardPublicView'; | ||||||
| @@ -37,88 +38,97 @@ class DashboardPublicView extends StatelessWidget { | |||||||
|  |  | ||||||
|   @override |   @override | ||||||
|   Widget build(BuildContext context) { |   Widget build(BuildContext context) { | ||||||
|     return Scaffold( |     return ChangeNotifierProvider( | ||||||
|       body: SingleChildScrollView( |         create: (context) => DashboardPublicViewModel(), | ||||||
|         padding: const EdgeInsets.only( |         builder: (context, child) { | ||||||
|           top: 32.0, |           return Scaffold( | ||||||
|           bottom: 8.0, |             body: SingleChildScrollView( | ||||||
|           left: 24.0, |               padding: const EdgeInsets.only( | ||||||
|           right: 24.0, |                 bottom: 24.0, | ||||||
|         ), |                 left: 24.0, | ||||||
|         child: Column( |                 right: 24.0, | ||||||
|           crossAxisAlignment: CrossAxisAlignment.start, |  | ||||||
|           mainAxisAlignment: MainAxisAlignment.spaceBetween, |  | ||||||
|           children: [ |  | ||||||
|             ImageView( |  | ||||||
|               image: PathAssets.icon1, |  | ||||||
|               width: SizeConfig.width * .35, |  | ||||||
|             ), |  | ||||||
|             Align( |  | ||||||
|                 alignment: Alignment.center, |  | ||||||
|                 heightFactor: 1, |  | ||||||
|                 child: _caption()), |  | ||||||
|             Align( |  | ||||||
|               alignment: Alignment.center, |  | ||||||
|               child: ImageView( |  | ||||||
|                 image: PathAssets.imgDashboard, |  | ||||||
|                 width: SizeConfig.width * .7, |  | ||||||
|               ), |               ), | ||||||
|  |               child: Consumer<DashboardPublicViewModel>( | ||||||
|  |                   builder: (context, provider, child) { | ||||||
|  |                 return Column( | ||||||
|  |                   crossAxisAlignment: CrossAxisAlignment.start, | ||||||
|  |                   mainAxisAlignment: MainAxisAlignment.spaceBetween, | ||||||
|  |                   children: [ | ||||||
|  |                     SizedBox(height: SizeConfig.height * .06), | ||||||
|  |                     ImageView( | ||||||
|  |                       image: PathAssets.icon1, | ||||||
|  |                       width: SizeConfig.width * .35, | ||||||
|  |                     ), | ||||||
|  |                     SizedBox(height: SizeConfig.height * .02), | ||||||
|  |                     Align( | ||||||
|  |                         alignment: Alignment.center, | ||||||
|  |                         heightFactor: 1, | ||||||
|  |                         child: _caption()), | ||||||
|  |                     Align( | ||||||
|  |                       alignment: Alignment.center, | ||||||
|  |                       child: ImageView( | ||||||
|  |                         image: PathAssets.imgDashboard, | ||||||
|  |                         width: SizeConfig.width * .8, | ||||||
|  |                       ), | ||||||
|  |                     ), | ||||||
|  |                     Row( | ||||||
|  |                       mainAxisAlignment: MainAxisAlignment.spaceBetween, | ||||||
|  |                       children: [ | ||||||
|  |                         ButtonView( | ||||||
|  |                           name: 'Sign in', | ||||||
|  |                           isOutlined: true, | ||||||
|  |                           width: SizeConfig.width * .43, | ||||||
|  |                           height: SizeConfig.height * .06, | ||||||
|  |                           onPressed: () { | ||||||
|  |                             routePush(context, page: const LoginView()); | ||||||
|  |                           }, | ||||||
|  |                         ), | ||||||
|  |                         ButtonView( | ||||||
|  |                           name: 'Sign Up', | ||||||
|  |                           width: SizeConfig.width * .43, | ||||||
|  |                           height: SizeConfig.height * .06, | ||||||
|  |                           onPressed: () { | ||||||
|  |                             routePush(context, page: const RegistrationView()); | ||||||
|  |                           }, | ||||||
|  |                         ), | ||||||
|  |                       ], | ||||||
|  |                     ), | ||||||
|  |                     const ImageView(image: PathAssets.iconConnect), | ||||||
|  |                     ButtonView( | ||||||
|  |                       name: 'Google', | ||||||
|  |                       isSecondaryColor: true, | ||||||
|  |                       isOutlined: true, | ||||||
|  |                       prefixIcon: const ImageView( | ||||||
|  |                         image: PathAssets.iconGoogle, | ||||||
|  |                         width: 26, | ||||||
|  |                       ), | ||||||
|  |                       onPressed: () { | ||||||
|  |                         provider.loginGoogle(context); | ||||||
|  |                       }, | ||||||
|  |                     ), | ||||||
|  |                     SizedBox(height: SizeConfig.height * .07), | ||||||
|  |                     Row( | ||||||
|  |                       mainAxisAlignment: MainAxisAlignment.spaceBetween, | ||||||
|  |                       children: [ | ||||||
|  |                         ImageView( | ||||||
|  |                           image: PathAssets.iconOjk, | ||||||
|  |                           width: SizeConfig.width * .20, | ||||||
|  |                         ), | ||||||
|  |                         ImageView( | ||||||
|  |                           image: PathAssets.iconInklusi, | ||||||
|  |                           width: SizeConfig.width * .20, | ||||||
|  |                         ), | ||||||
|  |                         ImageView( | ||||||
|  |                           image: PathAssets.iconReksadana, | ||||||
|  |                           width: SizeConfig.width * .20, | ||||||
|  |                         ), | ||||||
|  |                       ], | ||||||
|  |                     ) | ||||||
|  |                   ], | ||||||
|  |                 ); | ||||||
|  |               }), | ||||||
|             ), |             ), | ||||||
|             Row( |           ); | ||||||
|               mainAxisAlignment: MainAxisAlignment.spaceBetween, |         }); | ||||||
|               children: [ |  | ||||||
|                 ButtonView( |  | ||||||
|                   name: 'Sign in', |  | ||||||
|                   isOutlined: true, |  | ||||||
|                   width: SizeConfig.width * .43, |  | ||||||
|                   height: SizeConfig.height * .06, |  | ||||||
|                   onPressed: () { |  | ||||||
|                     routePush(context, page: const LoginView()); |  | ||||||
|                   }, |  | ||||||
|                 ), |  | ||||||
|                 ButtonView( |  | ||||||
|                   name: 'Sign Up', |  | ||||||
|                   width: SizeConfig.width * .43, |  | ||||||
|                   height: SizeConfig.height * .06, |  | ||||||
|                   onPressed: () { |  | ||||||
|                     routePush(context, page: const RegistrationView()); |  | ||||||
|                   }, |  | ||||||
|                 ), |  | ||||||
|               ], |  | ||||||
|             ), |  | ||||||
|             const ImageView(image: PathAssets.iconConnect), |  | ||||||
|             ButtonView( |  | ||||||
|               name: 'Google', |  | ||||||
|               isSecondaryColor: true, |  | ||||||
|               isOutlined: true, |  | ||||||
|               prefixIcon: const ImageView( |  | ||||||
|                 image: PathAssets.iconGoogle, |  | ||||||
|                 width: 26, |  | ||||||
|               ), |  | ||||||
|               onPressed: () { |  | ||||||
|                 routePush(context, page: const InitialRegistrationStep()); |  | ||||||
|               }, |  | ||||||
|             ), |  | ||||||
|             Row( |  | ||||||
|               mainAxisAlignment: MainAxisAlignment.spaceBetween, |  | ||||||
|               children: [ |  | ||||||
|                 ImageView( |  | ||||||
|                   image: PathAssets.iconOjk, |  | ||||||
|                   width: SizeConfig.width * .20, |  | ||||||
|                 ), |  | ||||||
|                 ImageView( |  | ||||||
|                   image: PathAssets.iconInklusi, |  | ||||||
|                   width: SizeConfig.width * .20, |  | ||||||
|                 ), |  | ||||||
|                 ImageView( |  | ||||||
|                   image: PathAssets.iconReksadana, |  | ||||||
|                   width: SizeConfig.width * .20, |  | ||||||
|                 ), |  | ||||||
|               ], |  | ||||||
|             ) |  | ||||||
|           ], |  | ||||||
|         ), |  | ||||||
|       ), |  | ||||||
|     ); |  | ||||||
|   } |   } | ||||||
| } | } | ||||||
|   | |||||||
| @@ -0,0 +1,50 @@ | |||||||
|  | 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/dashboard/dashboard_public/model/login_gmail_model.dart'; | ||||||
|  | import 'package:flutter/material.dart'; | ||||||
|  | import 'package:google_sign_in/google_sign_in.dart'; | ||||||
|  |  | ||||||
|  | class DashboardPublicViewModel extends ChangeNotifier { | ||||||
|  |   String emailGoogle = ''; | ||||||
|  |   final GoogleSignIn googleSignIn = GoogleSignIn( | ||||||
|  |     scopes: [ | ||||||
|  |       'email', | ||||||
|  |       'https://www.googleapis.com/auth/contacts.readonly', | ||||||
|  |     ], | ||||||
|  |   ); | ||||||
|  |   Future<LoginGmailModel?> _getGmail() async { | ||||||
|  |     LoginGmailModel? loginGmailModel; | ||||||
|  |     try { | ||||||
|  |       final signInResult = await googleSignIn.signIn(); | ||||||
|  |       if (signInResult != null) { | ||||||
|  |         emailGoogle = signInResult.email; | ||||||
|  |         final signInAuth = await signInResult.authentication; | ||||||
|  |         final accessToken = signInAuth.accessToken; | ||||||
|  |         final idToken = signInAuth.idToken; | ||||||
|  |         if (idToken != null && accessToken != null) { | ||||||
|  |           loginGmailModel = LoginGmailModel( | ||||||
|  |             accessToken: accessToken, | ||||||
|  |             idToken: idToken, | ||||||
|  |           ); | ||||||
|  |         } | ||||||
|  |       } | ||||||
|  |     } catch (e) { | ||||||
|  |       debugPrint('catch error $e'); | ||||||
|  |     } | ||||||
|  |     return loginGmailModel; | ||||||
|  |   } | ||||||
|  |  | ||||||
|  |   Future<bool> loginGoogle(BuildContext context) async { | ||||||
|  |     bool loginSuccess = false; | ||||||
|  |     loginSuccess = await _getGmail().then((payload) async { | ||||||
|  |       bool result = false; | ||||||
|  |       if (payload != null) { | ||||||
|  |         debugPrint('objectzz ${payload.toJson()}'); | ||||||
|  |         routePush(context, page: InitialRegistrationStep()); | ||||||
|  |         googleSignIn.disconnect(); | ||||||
|  |       } | ||||||
|  |       return result; | ||||||
|  |     }); | ||||||
|  |     return loginSuccess; | ||||||
|  |   } | ||||||
|  | } | ||||||
							
								
								
									
										35
									
								
								lib/features/transaction/view/cancel_view.dart
									
									
									
									
									
										Normal file
									
								
							
							
						
						| @@ -0,0 +1,35 @@ | |||||||
|  | import 'package:cims_apps/application/component/card_transaction/card_transaction_view.dart'; | ||||||
|  | import 'package:cims_apps/application/component/card_transaction/empty_card_transaction.dart'; | ||||||
|  | import 'package:cims_apps/features/transaction/viewmodel/transaction_viewmodel.dart'; | ||||||
|  | import 'package:flutter/material.dart'; | ||||||
|  | import 'package:provider/provider.dart'; | ||||||
|  |  | ||||||
|  | class CancelView extends StatelessWidget { | ||||||
|  |   const CancelView({Key? key}) : super(key: key); | ||||||
|  |  | ||||||
|  |   @override | ||||||
|  |   Widget build(BuildContext context) { | ||||||
|  |     return SingleChildScrollView( | ||||||
|  |       child: Consumer<TransactionViewModel>( | ||||||
|  |         builder: (context, provider, child) => Column( | ||||||
|  |           children: [ | ||||||
|  |             if (provider.listOnProcessTransaction.isEmpty) | ||||||
|  |               EmptyCardTransaction( | ||||||
|  |                 onPressedButton: () {}, | ||||||
|  |               ), | ||||||
|  |             ...provider.listOnProcessTransaction.map((e) { | ||||||
|  |               return CardTransactionView( | ||||||
|  |                 step: 'cancel', | ||||||
|  |                 type: 'type', | ||||||
|  |                 amount: 'amount', | ||||||
|  |                 iconPath: 'iconPath', | ||||||
|  |                 subs: 'subs', | ||||||
|  |                 onTap: () {}, | ||||||
|  |               ); | ||||||
|  |             }), | ||||||
|  |           ], | ||||||
|  |         ), | ||||||
|  |       ), | ||||||
|  |     ); | ||||||
|  |   } | ||||||
|  | } | ||||||
							
								
								
									
										37
									
								
								lib/features/transaction/view/done_view.dart
									
									
									
									
									
										Normal file
									
								
							
							
						
						| @@ -0,0 +1,37 @@ | |||||||
|  | import 'package:cims_apps/application/component/card_transaction/card_transaction_view.dart'; | ||||||
|  | import 'package:cims_apps/application/component/card_transaction/empty_card_transaction.dart'; | ||||||
|  | import 'package:cims_apps/features/transaction/viewmodel/transaction_viewmodel.dart'; | ||||||
|  | import 'package:flutter/material.dart'; | ||||||
|  | import 'package:provider/provider.dart'; | ||||||
|  |  | ||||||
|  | class DoneView extends StatelessWidget { | ||||||
|  |   const DoneView({Key? key}) : super(key: key); | ||||||
|  |  | ||||||
|  |   @override | ||||||
|  |   Widget build(BuildContext context) { | ||||||
|  |     return SingleChildScrollView( | ||||||
|  |       child: Consumer<TransactionViewModel>( | ||||||
|  |         builder: (context, provider, child) { | ||||||
|  |           return Column( | ||||||
|  |             children: [ | ||||||
|  |               if (provider.listOnProcessTransaction.isEmpty) | ||||||
|  |                 EmptyCardTransaction( | ||||||
|  |                   onPressedButton: () {}, | ||||||
|  |                 ), | ||||||
|  |               ...provider.listOnProcessTransaction.map((e) { | ||||||
|  |                 return CardTransactionView( | ||||||
|  |                   step: 'done', | ||||||
|  |                   type: 'type', | ||||||
|  |                   amount: 'amount', | ||||||
|  |                   iconPath: 'iconPath', | ||||||
|  |                   subs: 'subs', | ||||||
|  |                   onTap: () {}, | ||||||
|  |                 ); | ||||||
|  |               }), | ||||||
|  |             ], | ||||||
|  |           ); | ||||||
|  |         }, | ||||||
|  |       ), | ||||||
|  |     ); | ||||||
|  |   } | ||||||
|  | } | ||||||
							
								
								
									
										34
									
								
								lib/features/transaction/view/onprocess_view.dart
									
									
									
									
									
										Normal file
									
								
							
							
						
						| @@ -0,0 +1,34 @@ | |||||||
|  | import 'package:cims_apps/application/component/card_transaction/card_transaction_view.dart'; | ||||||
|  | import 'package:cims_apps/application/component/card_transaction/empty_card_transaction.dart'; | ||||||
|  | import 'package:cims_apps/features/transaction/viewmodel/transaction_viewmodel.dart'; | ||||||
|  | import 'package:flutter/material.dart'; | ||||||
|  | import 'package:provider/provider.dart'; | ||||||
|  |  | ||||||
|  | class OnProcessView extends StatelessWidget { | ||||||
|  |   const OnProcessView({Key? key}) : super(key: key); | ||||||
|  |  | ||||||
|  |   @override | ||||||
|  |   Widget build(BuildContext context) { | ||||||
|  |     return SingleChildScrollView( | ||||||
|  |       child: | ||||||
|  |           Consumer<TransactionViewModel>(builder: (context, provider, child) { | ||||||
|  |         return Column(children: [ | ||||||
|  |           if (provider.listOnProcessTransaction.isEmpty) | ||||||
|  |             EmptyCardTransaction( | ||||||
|  |               onPressedButton: () {}, | ||||||
|  |             ), | ||||||
|  |           ...provider.listOnProcessTransaction.map((e) { | ||||||
|  |             return CardTransactionView( | ||||||
|  |               step: 'on process', | ||||||
|  |               type: 'type', | ||||||
|  |               amount: 'amount', | ||||||
|  |               iconPath: 'iconPath', | ||||||
|  |               subs: 'subs', | ||||||
|  |               onTap: () {}, | ||||||
|  |             ); | ||||||
|  |           }), | ||||||
|  |         ]); | ||||||
|  |       }), | ||||||
|  |     ); | ||||||
|  |   } | ||||||
|  | } | ||||||
							
								
								
									
										124
									
								
								lib/features/transaction/view/transaction_view.dart
									
									
									
									
									
										Normal file
									
								
							
							
						
						| @@ -0,0 +1,124 @@ | |||||||
|  | import 'package:cims_apps/application/assets/path_assets.dart'; | ||||||
|  | import 'package:cims_apps/application/component/image/image_view.dart'; | ||||||
|  | import 'package:cims_apps/application/theme/color_palette.dart'; | ||||||
|  | import 'package:cims_apps/core/utils/size_config.dart'; | ||||||
|  | import 'package:cims_apps/features/transaction/view/cancel_view.dart'; | ||||||
|  | import 'package:cims_apps/features/transaction/view/done_view.dart'; | ||||||
|  | import 'package:cims_apps/features/transaction/view/onprocess_view.dart'; | ||||||
|  | import 'package:cims_apps/features/transaction/view/waiting_view.dart'; | ||||||
|  | import 'package:cims_apps/features/transaction/viewmodel/transaction_viewmodel.dart'; | ||||||
|  | import 'package:flutter/material.dart'; | ||||||
|  | import 'package:flutter_toggle_tab/flutter_toggle_tab.dart'; | ||||||
|  | import 'package:provider/provider.dart'; | ||||||
|  |  | ||||||
|  | class TransactionView extends StatelessWidget { | ||||||
|  |   const TransactionView({Key? key}) : super(key: key); | ||||||
|  |  | ||||||
|  |   @override | ||||||
|  |   Widget build(BuildContext context) { | ||||||
|  |     List<Tab> textTabs = const [ | ||||||
|  |       Tab(text: 'Waiting'), | ||||||
|  |       Tab(text: 'On process'), | ||||||
|  |       Tab(text: 'Done'), | ||||||
|  |       Tab(text: 'Cancel'), | ||||||
|  |     ]; | ||||||
|  |     List<Widget> listTabBarView = const [ | ||||||
|  |       WaitingView(), | ||||||
|  |       OnProcessView(), | ||||||
|  |       DoneView(), | ||||||
|  |       CancelView(), | ||||||
|  |     ]; | ||||||
|  |  | ||||||
|  |     return ChangeNotifierProvider( | ||||||
|  |         create: (context) => TransactionViewModel(), | ||||||
|  |         builder: (context, child) { | ||||||
|  |           return Scaffold( | ||||||
|  |             backgroundColor: ColorPalette.primary, | ||||||
|  |             body: SizedBox( | ||||||
|  |               child: Stack( | ||||||
|  |                 children: [ | ||||||
|  |                   const ImageView(image: PathAssets.imgDashboardAccount), | ||||||
|  |                   Column( | ||||||
|  |                     children: [ | ||||||
|  |                       SizedBox( | ||||||
|  |                         height: SizeConfig.height * .05, | ||||||
|  |                       ), | ||||||
|  |                       const Center( | ||||||
|  |                         child: Text( | ||||||
|  |                           'Transaction', | ||||||
|  |                           style: TextStyle( | ||||||
|  |                               fontSize: 20, | ||||||
|  |                               fontWeight: FontWeight.w700, | ||||||
|  |                               color: Colors.white), | ||||||
|  |                         ), | ||||||
|  |                       ), | ||||||
|  |                       SizedBox( | ||||||
|  |                         height: SizeConfig.height * .04, | ||||||
|  |                       ), | ||||||
|  |                       Container( | ||||||
|  |                         margin: const EdgeInsets.symmetric(horizontal: 24), | ||||||
|  |                         child: FlutterToggleTab( | ||||||
|  |                           height: SizeConfig.height * .065, | ||||||
|  |                           width: SizeConfig.width * .2, | ||||||
|  |                           marginSelected: const EdgeInsets.all(8.0), | ||||||
|  |                           isScroll: false, | ||||||
|  |                           selectedTextStyle: const TextStyle( | ||||||
|  |                             color: ColorPalette.primary, | ||||||
|  |                             fontWeight: FontWeight.w700, | ||||||
|  |                           ), | ||||||
|  |                           unSelectedTextStyle: const TextStyle( | ||||||
|  |                             color: ColorPalette.blackFont, | ||||||
|  |                             fontWeight: FontWeight.w700, | ||||||
|  |                           ), | ||||||
|  |                           unSelectedBackgroundColors: const [ | ||||||
|  |                             ColorPalette.blue50 | ||||||
|  |                           ], | ||||||
|  |                           selectedBackgroundColors: const [ColorPalette.white], | ||||||
|  |                           labels: const ['Subscribe', 'Reedem'], | ||||||
|  |                           selectedLabelIndex: (p0) {}, | ||||||
|  |                           selectedIndex: 0, | ||||||
|  |                         ), | ||||||
|  |                       ), | ||||||
|  |                       Expanded( | ||||||
|  |                           child: DefaultTabController( | ||||||
|  |                         length: textTabs.length, | ||||||
|  |                         child: Container( | ||||||
|  |                           color: Colors.transparent, | ||||||
|  |                           padding: const EdgeInsets.only(top: 32.0), | ||||||
|  |                           child: Container( | ||||||
|  |                             margin: const EdgeInsets.only(top: 24), | ||||||
|  |                             padding: const EdgeInsets.only(top: 16.0), | ||||||
|  |                             decoration: const BoxDecoration( | ||||||
|  |                               color: Colors.white, | ||||||
|  |                               borderRadius: BorderRadius.only( | ||||||
|  |                                   topLeft: Radius.circular(24), | ||||||
|  |                                   topRight: Radius.circular(24)), | ||||||
|  |                             ), | ||||||
|  |                             child: Column( | ||||||
|  |                               children: [ | ||||||
|  |                                 TabBar( | ||||||
|  |                                   tabs: textTabs, | ||||||
|  |                                   indicatorColor: Colors.blueAccent, | ||||||
|  |                                 ), | ||||||
|  |                                 Expanded( | ||||||
|  |                                     child: Padding( | ||||||
|  |                                   padding: const EdgeInsets.symmetric( | ||||||
|  |                                     horizontal: 16.0, | ||||||
|  |                                     vertical: 4.0, | ||||||
|  |                                   ), | ||||||
|  |                                   child: TabBarView(children: listTabBarView), | ||||||
|  |                                 )) | ||||||
|  |                               ], | ||||||
|  |                             ), | ||||||
|  |                           ), | ||||||
|  |                         ), | ||||||
|  |                       )), | ||||||
|  |                     ], | ||||||
|  |                   ) | ||||||
|  |                 ], | ||||||
|  |               ), | ||||||
|  |             ), | ||||||
|  |           ); | ||||||
|  |         }); | ||||||
|  |   } | ||||||
|  | } | ||||||
							
								
								
									
										42
									
								
								lib/features/transaction/view/waiting_view.dart
									
									
									
									
									
										Normal file
									
								
							
							
						
						| @@ -0,0 +1,42 @@ | |||||||
|  | import 'package:cims_apps/application/assets/path_assets.dart'; | ||||||
|  | import 'package:cims_apps/application/component/card_transaction/card_transaction_view.dart'; | ||||||
|  | import 'package:cims_apps/application/component/card_transaction/empty_card_transaction.dart'; | ||||||
|  | import 'package:cims_apps/core/utils/number_formatter.dart'; | ||||||
|  | import 'package:cims_apps/core/utils/string_utils.dart'; | ||||||
|  | import 'package:cims_apps/features/transaction/viewmodel/transaction_viewmodel.dart'; | ||||||
|  | import 'package:flutter/material.dart'; | ||||||
|  | import 'package:provider/provider.dart'; | ||||||
|  |  | ||||||
|  | class WaitingView extends StatelessWidget { | ||||||
|  |   const WaitingView({Key? key}) : super(key: key); | ||||||
|  |  | ||||||
|  |   @override | ||||||
|  |   Widget build(BuildContext context) { | ||||||
|  |     return SingleChildScrollView( | ||||||
|  |       child: | ||||||
|  |           Consumer<TransactionViewModel>(builder: (context, provider, child) { | ||||||
|  |         return Column( | ||||||
|  |           children: [ | ||||||
|  |             provider.listWaitingTransaction.isNotEmpty | ||||||
|  |                 ? CardTransactionView( | ||||||
|  |                     onTap: () {}, | ||||||
|  |                     iconPath: PathAssets.iconEducation, | ||||||
|  |                     type: 'Education', | ||||||
|  |                     amount: NumberFormatter.numberCurrency( | ||||||
|  |                       6000000, | ||||||
|  |                       'Rp ', | ||||||
|  |                       'id_ID', | ||||||
|  |                       decimalDigits: 0, | ||||||
|  |                     ), | ||||||
|  |                     timeTransaction: StringUtils.formatTime(DateTime.now()), | ||||||
|  |                     subs: '3 Subscription', | ||||||
|  |                     step: 'waiting') | ||||||
|  |                 : EmptyCardTransaction( | ||||||
|  |                     onPressedButton: () {}, | ||||||
|  |                   ), | ||||||
|  |           ], | ||||||
|  |         ); | ||||||
|  |       }), | ||||||
|  |     ); | ||||||
|  |   } | ||||||
|  | } | ||||||
| @@ -0,0 +1,8 @@ | |||||||
|  | import 'package:flutter/material.dart'; | ||||||
|  |  | ||||||
|  | class TransactionViewModel extends ChangeNotifier { | ||||||
|  |   List listWaitingTransaction = [1]; | ||||||
|  |   List listOnProcessTransaction = []; | ||||||
|  |   List listDoneTransaction = []; | ||||||
|  |   List listCancelTransaction = []; | ||||||
|  | } | ||||||
							
								
								
									
										114
									
								
								lib/main.dart
									
									
									
									
									
								
							
							
						
						| @@ -20,68 +20,66 @@ class MyApp extends StatelessWidget { | |||||||
|       title: 'CIMS', |       title: 'CIMS', | ||||||
|       debugShowCheckedModeBanner: false, |       debugShowCheckedModeBanner: false, | ||||||
|       theme: ThemeData( |       theme: ThemeData( | ||||||
|         appBarTheme: const AppBarTheme( |           appBarTheme: const AppBarTheme( | ||||||
|             centerTitle: true, |               centerTitle: true, | ||||||
|             backgroundColor: Colors.white, |               backgroundColor: Colors.white, | ||||||
|             elevation: 1, |               elevation: 1, | ||||||
|             foregroundColor: Colors.black, |               foregroundColor: Colors.black, | ||||||
|             titleTextStyle: TextStyle( |               titleTextStyle: TextStyle( | ||||||
|               fontSize: 20, |                 fontSize: 20, | ||||||
|               fontWeight: FontWeight.w700, |                 fontWeight: FontWeight.w700, | ||||||
|               fontFamily: 'Manrope', |                 fontFamily: 'Manrope', | ||||||
|  |                 color: ColorPalette.slate800, | ||||||
|  |               )), | ||||||
|  |           fontFamily: 'Manrope', | ||||||
|  |           scaffoldBackgroundColor: Colors.white, | ||||||
|  |           textTheme: const TextTheme( | ||||||
|  |             displaySmall: TextStyle( | ||||||
|  |               fontSize: 14, | ||||||
|  |               fontWeight: FontWeight.w500, | ||||||
|               color: ColorPalette.slate800, |               color: ColorPalette.slate800, | ||||||
|             )), |             ), | ||||||
|         fontFamily: 'Manrope', |             displayMedium: TextStyle( | ||||||
|         scaffoldBackgroundColor: Colors.white, |               fontSize: 16, | ||||||
|         textTheme: const TextTheme( |               fontWeight: FontWeight.w600, | ||||||
|           displaySmall: TextStyle( |               color: ColorPalette.slate800, | ||||||
|             fontSize: 14, |             ), | ||||||
|             fontWeight: FontWeight.w500, |             displayLarge: TextStyle( | ||||||
|             color: ColorPalette.slate800, |               fontSize: 16, | ||||||
|  |               fontWeight: FontWeight.bold, | ||||||
|  |               color: ColorPalette.slate800, | ||||||
|  |             ), | ||||||
|  |             bodyMedium: TextStyle( | ||||||
|  |               fontSize: 14, | ||||||
|  |               fontWeight: FontWeight.w600, | ||||||
|  |               color: ColorPalette.slate500, | ||||||
|  |             ), | ||||||
|  |             bodyLarge: TextStyle( | ||||||
|  |               fontSize: 16, | ||||||
|  |               fontWeight: FontWeight.bold, | ||||||
|  |               color: ColorPalette.slate500, | ||||||
|  |             ), | ||||||
|  |             headlineSmall: TextStyle( | ||||||
|  |               fontSize: 16, | ||||||
|  |               fontWeight: FontWeight.bold, | ||||||
|  |               color: ColorPalette.slate800, | ||||||
|  |             ), | ||||||
|  |             headlineLarge: TextStyle( | ||||||
|  |               fontSize: 28, | ||||||
|  |               fontWeight: FontWeight.bold, | ||||||
|  |               color: ColorPalette.slate800, | ||||||
|  |             ), | ||||||
|           ), |           ), | ||||||
|           displayMedium: TextStyle( |           colorScheme: const ColorScheme.light().copyWith( | ||||||
|             fontSize: 16, |             primary: const Color(0xff2563EB), | ||||||
|             fontWeight: FontWeight.w600, |             onPrimary: const Color(0xFFFF9130), | ||||||
|             color: ColorPalette.slate800, |             secondary: const Color(0xFFFECDA6), | ||||||
|  |             onBackground: const Color(0xFFA9A9A9), | ||||||
|           ), |           ), | ||||||
|           displayLarge: TextStyle( |           bottomSheetTheme: const BottomSheetThemeData( | ||||||
|             fontSize: 16, |               backgroundColor: Colors.white, surfaceTintColor: Colors.white) | ||||||
|             fontWeight: FontWeight.bold, |           // useMaterial3: true, | ||||||
|             color: ColorPalette.slate800, |  | ||||||
|           ), |           ), | ||||||
|           bodyMedium: TextStyle( |  | ||||||
|             fontSize: 14, |  | ||||||
|             fontWeight: FontWeight.w600, |  | ||||||
|             color: ColorPalette.slate500, |  | ||||||
|           ), |  | ||||||
|           bodyLarge: TextStyle( |  | ||||||
|             fontSize: 16, |  | ||||||
|             fontWeight: FontWeight.bold, |  | ||||||
|             color: ColorPalette.slate500, |  | ||||||
|           ), |  | ||||||
|           headlineSmall: TextStyle( |  | ||||||
|             fontSize: 16, |  | ||||||
|             fontWeight: FontWeight.bold, |  | ||||||
|             color: ColorPalette.slate800, |  | ||||||
|           ), |  | ||||||
|           headlineLarge: TextStyle( |  | ||||||
|             fontSize: 28, |  | ||||||
|             fontWeight: FontWeight.bold, |  | ||||||
|             color: ColorPalette.slate800, |  | ||||||
|           ), |  | ||||||
|         ), |  | ||||||
|         colorScheme: const ColorScheme.light().copyWith( |  | ||||||
|           primary: const Color(0xff2563EB), |  | ||||||
|           onPrimary: const Color(0xFFFF9130), |  | ||||||
|           secondary: const Color(0xFFFECDA6), |  | ||||||
|           onBackground: const Color(0xFFA9A9A9), |  | ||||||
|         ), |  | ||||||
|         bottomSheetTheme: BottomSheetThemeData( |  | ||||||
|           backgroundColor: Colors.white, |  | ||||||
|           surfaceTintColor: Colors.white |  | ||||||
|         ) |  | ||||||
|         // useMaterial3: true, |  | ||||||
|       ), |  | ||||||
|       initialRoute: initialRoute, |       initialRoute: initialRoute, | ||||||
|       onGenerateRoute: generateRoutes, |       onGenerateRoute: generateRoutes, | ||||||
|       navigatorObservers: [ |       navigatorObservers: [ | ||||||
|   | |||||||
							
								
								
									
										76
									
								
								pubspec.lock
									
									
									
									
									
								
							
							
						
						| @@ -49,6 +49,14 @@ packages: | |||||||
|       url: "https://pub.dev" |       url: "https://pub.dev" | ||||||
|     source: hosted |     source: hosted | ||||||
|     version: "1.1.1" |     version: "1.1.1" | ||||||
|  |   calendar_date_picker2: | ||||||
|  |     dependency: "direct main" | ||||||
|  |     description: | ||||||
|  |       name: calendar_date_picker2 | ||||||
|  |       sha256: b91d51b8d0928f9745e0113e86d06b161ac48c52b7530337a3b77283cbc6be27 | ||||||
|  |       url: "https://pub.dev" | ||||||
|  |     source: hosted | ||||||
|  |     version: "0.5.3" | ||||||
|   camera: |   camera: | ||||||
|     dependency: "direct main" |     dependency: "direct main" | ||||||
|     description: |     description: | ||||||
| @@ -251,11 +259,67 @@ packages: | |||||||
|     description: flutter |     description: flutter | ||||||
|     source: sdk |     source: sdk | ||||||
|     version: "0.0.0" |     version: "0.0.0" | ||||||
|  |   flutter_toggle_tab: | ||||||
|  |     dependency: "direct main" | ||||||
|  |     description: | ||||||
|  |       name: flutter_toggle_tab | ||||||
|  |       sha256: "90ad0d050f656df677998825f985637d010117a1793828cd7e6dadada4ecd2c5" | ||||||
|  |       url: "https://pub.dev" | ||||||
|  |     source: hosted | ||||||
|  |     version: "1.4.1" | ||||||
|   flutter_web_plugins: |   flutter_web_plugins: | ||||||
|     dependency: transitive |     dependency: transitive | ||||||
|     description: flutter |     description: flutter | ||||||
|     source: sdk |     source: sdk | ||||||
|     version: "0.0.0" |     version: "0.0.0" | ||||||
|  |   google_identity_services_web: | ||||||
|  |     dependency: transitive | ||||||
|  |     description: | ||||||
|  |       name: google_identity_services_web | ||||||
|  |       sha256: "0c56c2c5d60d6dfaf9725f5ad4699f04749fb196ee5a70487a46ef184837ccf6" | ||||||
|  |       url: "https://pub.dev" | ||||||
|  |     source: hosted | ||||||
|  |     version: "0.3.0+2" | ||||||
|  |   google_sign_in: | ||||||
|  |     dependency: "direct main" | ||||||
|  |     description: | ||||||
|  |       name: google_sign_in | ||||||
|  |       sha256: "0b8787cb9c1a68ad398e8010e8c8766bfa33556d2ab97c439fb4137756d7308f" | ||||||
|  |       url: "https://pub.dev" | ||||||
|  |     source: hosted | ||||||
|  |     version: "6.2.1" | ||||||
|  |   google_sign_in_android: | ||||||
|  |     dependency: transitive | ||||||
|  |     description: | ||||||
|  |       name: google_sign_in_android | ||||||
|  |       sha256: bfd42c81c30c6faba16e0f62968d5505a87504aaa672b3155ee931461abb0a49 | ||||||
|  |       url: "https://pub.dev" | ||||||
|  |     source: hosted | ||||||
|  |     version: "6.1.21" | ||||||
|  |   google_sign_in_ios: | ||||||
|  |     dependency: transitive | ||||||
|  |     description: | ||||||
|  |       name: google_sign_in_ios | ||||||
|  |       sha256: f3336d9e44d4d28063ac90271f6db5caf99f0480cb07281330e7a432edb95226 | ||||||
|  |       url: "https://pub.dev" | ||||||
|  |     source: hosted | ||||||
|  |     version: "5.7.3" | ||||||
|  |   google_sign_in_platform_interface: | ||||||
|  |     dependency: transitive | ||||||
|  |     description: | ||||||
|  |       name: google_sign_in_platform_interface | ||||||
|  |       sha256: "1f6e5787d7a120cc0359ddf315c92309069171306242e181c09472d1b00a2971" | ||||||
|  |       url: "https://pub.dev" | ||||||
|  |     source: hosted | ||||||
|  |     version: "2.4.5" | ||||||
|  |   google_sign_in_web: | ||||||
|  |     dependency: transitive | ||||||
|  |     description: | ||||||
|  |       name: google_sign_in_web | ||||||
|  |       sha256: a278ea2d01013faf341cbb093da880d0f2a552bbd1cb6ee90b5bebac9ba69d77 | ||||||
|  |       url: "https://pub.dev" | ||||||
|  |     source: hosted | ||||||
|  |     version: "0.12.3+2" | ||||||
|   group_button: |   group_button: | ||||||
|     dependency: "direct main" |     dependency: "direct main" | ||||||
|     description: |     description: | ||||||
| @@ -292,10 +356,10 @@ packages: | |||||||
|     dependency: transitive |     dependency: transitive | ||||||
|     description: |     description: | ||||||
|       name: js |       name: js | ||||||
|       sha256: "4186c61b32f99e60f011f7160e32c89a758ae9b1d0c6d28e2c02ef0382300e2b" |       sha256: c1b2e9b5ea78c45e1a0788d29606ba27dc5f71f019f32ca5140f61ef071838cf | ||||||
|       url: "https://pub.dev" |       url: "https://pub.dev" | ||||||
|     source: hosted |     source: hosted | ||||||
|     version: "0.7.0" |     version: "0.7.1" | ||||||
|   lints: |   lints: | ||||||
|     dependency: transitive |     dependency: transitive | ||||||
|     description: |     description: | ||||||
| @@ -625,18 +689,18 @@ packages: | |||||||
|     dependency: transitive |     dependency: transitive | ||||||
|     description: |     description: | ||||||
|       name: syncfusion_flutter_core |       name: syncfusion_flutter_core | ||||||
|       sha256: e8580e201c7197feac830b501889e877796a9fabbe20dcdbe90a981603939101 |       sha256: "9f98e2726af42967497eaef68f3373261700bbfcd33bd97da4ec85cb56fcdaf7" | ||||||
|       url: "https://pub.dev" |       url: "https://pub.dev" | ||||||
|     source: hosted |     source: hosted | ||||||
|     version: "24.2.4" |     version: "24.2.7" | ||||||
|   syncfusion_flutter_signaturepad: |   syncfusion_flutter_signaturepad: | ||||||
|     dependency: "direct main" |     dependency: "direct main" | ||||||
|     description: |     description: | ||||||
|       name: syncfusion_flutter_signaturepad |       name: syncfusion_flutter_signaturepad | ||||||
|       sha256: "878e1063b909a83c83677627261780d42d532d0b5e7e259d84da805008e7fb0d" |       sha256: d51d5e346c70b938a8e1f2318a073213172aea7b99e33073c379657b1066c001 | ||||||
|       url: "https://pub.dev" |       url: "https://pub.dev" | ||||||
|     source: hosted |     source: hosted | ||||||
|     version: "24.2.4" |     version: "24.2.7" | ||||||
|   synchronized: |   synchronized: | ||||||
|     dependency: transitive |     dependency: transitive | ||||||
|     description: |     description: | ||||||
|   | |||||||
| @@ -51,6 +51,10 @@ dependencies: | |||||||
|   syncfusion_flutter_signaturepad: ^24.2.4 |   syncfusion_flutter_signaturepad: ^24.2.4 | ||||||
|   dotted_border: ^2.1.0 |   dotted_border: ^2.1.0 | ||||||
|   shared_preferences: ^2.2.2 |   shared_preferences: ^2.2.2 | ||||||
|  |   calendar_date_picker2: ^0.5.3 | ||||||
|  |   google_sign_in: ^6.2.1 | ||||||
|  |   flutter_toggle_tab: ^1.4.1 | ||||||
|  |  | ||||||
|  |  | ||||||
|  |  | ||||||
|  |  | ||||||
|   | |||||||