Compare commits
52 Commits
466d49312d
...
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 | |||
83211e76f9 | |||
99db140a0c | |||
57a4e828c9 | |||
0762a8ab0c | |||
66ace5b217 |
BIN
assets/icons/icon-bag.png
Normal file
After Width: | Height: | Size: 2.3 KiB |
BIN
assets/icons/icon-car.png
Normal file
After Width: | Height: | Size: 1.9 KiB |
BIN
assets/icons/icon-card.png
Normal file
After Width: | Height: | Size: 1.0 KiB |
BIN
assets/icons/icon-cart.png
Normal file
After Width: | Height: | Size: 1.8 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-gadget.png
Normal file
After Width: | Height: | Size: 1.4 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-market.png
Normal file
After Width: | Height: | Size: 1.4 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-plane.png
Normal file
After Width: | Height: | Size: 1.7 KiB |
BIN
assets/icons/icon-portofolio.png
Normal file
After Width: | Height: | Size: 1.5 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/icons/icon-thumb.png
Normal file
After Width: | Height: | Size: 1.6 KiB |
BIN
assets/icons/icon-ticket.png
Normal file
After Width: | Height: | Size: 1.5 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 |
BIN
assets/images/img-open-shopping.png
Normal file
After Width: | Height: | Size: 101 KiB |
BIN
assets/images/img-payment-success.png
Normal file
After Width: | Height: | Size: 74 KiB |
@@ -40,6 +40,39 @@ class PathAssets {
|
|||||||
static const String iconChecklistOutlined =
|
static const String iconChecklistOutlined =
|
||||||
'assets/icons/icon-ceklis-outline.png';
|
'assets/icons/icon-ceklis-outline.png';
|
||||||
static const String iconLock = 'assets/icons/icon-lock.png';
|
static const String iconLock = 'assets/icons/icon-lock.png';
|
||||||
|
static const String iconThumb = 'assets/icons/icon-thumb.png';
|
||||||
|
static const String iconPortofolio = 'assets/icons/icon-portofolio.png';
|
||||||
|
static const String iconPlane = 'assets/icons/icon-plane.png';
|
||||||
|
static const String iconCart = 'assets/icons/icon-cart.png';
|
||||||
|
static const String iconBag = 'assets/icons/icon-bag.png';
|
||||||
|
static const String iconMarket = 'assets/icons/icon-market.png';
|
||||||
|
static const String iconTicket = 'assets/icons/icon-ticket.png';
|
||||||
|
static const String iconGadget = 'assets/icons/icon-gadget.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';
|
||||||
@@ -73,6 +106,29 @@ class PathAssets {
|
|||||||
static const String imgGuideBank = 'assets/images/img-guide-bank.png';
|
static const String imgGuideBank = 'assets/images/img-guide-bank.png';
|
||||||
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 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,
|
||||||
|
};
|
||||||
}
|
}
|
||||||
|
@@ -9,7 +9,7 @@ class ButtonView extends StatelessWidget {
|
|||||||
final double? height, width, widthSuffix, widthPrefix, marginVertical;
|
final double? height, width, widthSuffix, widthPrefix, marginVertical;
|
||||||
final EdgeInsetsGeometry? contentPadding;
|
final EdgeInsetsGeometry? contentPadding;
|
||||||
final bool isSecondaryColor, isOutlined, heightWrapContent, disabled;
|
final bool isSecondaryColor, isOutlined, heightWrapContent, disabled;
|
||||||
final Color? backgroundColor, textColor, borderColor;
|
final Color? backgroundColor, textColor, borderColor, disabledBgColor;
|
||||||
final MainAxisAlignment? mainAxisAlignmentContent;
|
final MainAxisAlignment? mainAxisAlignmentContent;
|
||||||
// final _widthBtn = SizeConfig.screenWidth / 1.5;
|
// final _widthBtn = SizeConfig.screenWidth / 1.5;
|
||||||
final _widthBtn = SizeConfig.width * .9;
|
final _widthBtn = SizeConfig.width * .9;
|
||||||
@@ -34,6 +34,7 @@ class ButtonView extends StatelessWidget {
|
|||||||
this.backgroundColor,
|
this.backgroundColor,
|
||||||
this.borderColor,
|
this.borderColor,
|
||||||
this.textColor,
|
this.textColor,
|
||||||
|
this.disabledBgColor,
|
||||||
this.textWeight = FontWeight.bold,
|
this.textWeight = FontWeight.bold,
|
||||||
this.textSize,
|
this.textSize,
|
||||||
this.textAlign = TextAlign.center,
|
this.textAlign = TextAlign.center,
|
||||||
@@ -65,7 +66,7 @@ class ButtonView extends StatelessWidget {
|
|||||||
height: heightWrapContent ? null : height ?? _heightBtn,
|
height: heightWrapContent ? null : height ?? _heightBtn,
|
||||||
child: ElevatedButton(
|
child: ElevatedButton(
|
||||||
style: ElevatedButton.styleFrom(
|
style: ElevatedButton.styleFrom(
|
||||||
disabledBackgroundColor: isOutlined ? Colors.white : color.surface,
|
disabledBackgroundColor: disabledBgColor ?? (isOutlined ? Colors.white : color.surface),
|
||||||
padding: contentPadding,
|
padding: contentPadding,
|
||||||
backgroundColor: backgroundColor ??
|
backgroundColor: backgroundColor ??
|
||||||
(isOutlined
|
(isOutlined
|
||||||
|
@@ -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,
|
||||||
|
),
|
||||||
|
),
|
||||||
|
],
|
||||||
|
),
|
||||||
|
),
|
||||||
|
),
|
||||||
|
);
|
||||||
|
}
|
||||||
|
}
|
41
lib/application/component/modal_redirect_app.dart
Normal file
@@ -0,0 +1,41 @@
|
|||||||
|
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:flutter/material.dart';
|
||||||
|
|
||||||
|
class TypeApp {
|
||||||
|
String img, title;
|
||||||
|
|
||||||
|
TypeApp(this.img, this.title);
|
||||||
|
}
|
||||||
|
|
||||||
|
class ModalRedirectApp extends StatelessWidget {
|
||||||
|
final String value;
|
||||||
|
const ModalRedirectApp({super.key, required this.value});
|
||||||
|
|
||||||
|
@override
|
||||||
|
Widget build(BuildContext context) {
|
||||||
|
Map<String, TypeApp> typeApp = {
|
||||||
|
'Shopping Pay': TypeApp(PathAssets.imgOpenShopping, 'Shopping App'),
|
||||||
|
};
|
||||||
|
|
||||||
|
return Column(
|
||||||
|
children: [
|
||||||
|
ImageView(image: typeApp[value]!.img),
|
||||||
|
Text('Open ${typeApp[value]!.title}',
|
||||||
|
style: TextStyle(
|
||||||
|
fontSize: 22,
|
||||||
|
fontWeight: FontWeight.w600,
|
||||||
|
color: ColorPalette.slate800
|
||||||
|
),
|
||||||
|
),
|
||||||
|
Text('You will be redirected to the ${typeApp[value]!.title.toLowerCase()} to continue the payment',
|
||||||
|
style: TextStyle(
|
||||||
|
fontSize: 16,
|
||||||
|
color: ColorPalette.slate400
|
||||||
|
),
|
||||||
|
)
|
||||||
|
],
|
||||||
|
);
|
||||||
|
}
|
||||||
|
}
|
@@ -36,6 +36,18 @@ class NumericPad extends StatelessWidget {
|
|||||||
],
|
],
|
||||||
),
|
),
|
||||||
dividerGradient(true, Alignment.centerLeft, Alignment.centerRight),
|
dividerGradient(true, Alignment.centerLeft, Alignment.centerRight),
|
||||||
|
Row(
|
||||||
|
mainAxisAlignment: MainAxisAlignment.spaceEvenly,
|
||||||
|
crossAxisAlignment: CrossAxisAlignment.start,
|
||||||
|
children: [
|
||||||
|
numberWidget('7'),
|
||||||
|
dividerGradient(false, Alignment.center, Alignment.center, fullColor: true),
|
||||||
|
numberWidget('8'),
|
||||||
|
dividerGradient(false, Alignment.center, Alignment.center, fullColor: true),
|
||||||
|
numberWidget('9')
|
||||||
|
],
|
||||||
|
),
|
||||||
|
dividerGradient(true, Alignment.centerLeft, Alignment.centerRight),
|
||||||
Row(
|
Row(
|
||||||
mainAxisAlignment: MainAxisAlignment.spaceEvenly,
|
mainAxisAlignment: MainAxisAlignment.spaceEvenly,
|
||||||
crossAxisAlignment: CrossAxisAlignment.center,
|
crossAxisAlignment: CrossAxisAlignment.center,
|
||||||
@@ -54,7 +66,7 @@ class NumericPad extends StatelessWidget {
|
|||||||
Widget dividerGradient(bool isHorizontal, AlignmentGeometry gradientFrom, AlignmentGeometry gradientTo, {bool fullColor = false}) {
|
Widget dividerGradient(bool isHorizontal, AlignmentGeometry gradientFrom, AlignmentGeometry gradientTo, {bool fullColor = false}) {
|
||||||
return Container(
|
return Container(
|
||||||
width: isHorizontal ? SizeConfig.width : 1,
|
width: isHorizontal ? SizeConfig.width : 1,
|
||||||
height: isHorizontal ? 1 : SizeConfig.height * 0.11,
|
height: isHorizontal ? 1 : SizeConfig.height * 0.097,
|
||||||
decoration: BoxDecoration(
|
decoration: BoxDecoration(
|
||||||
gradient: LinearGradient(
|
gradient: LinearGradient(
|
||||||
colors: [
|
colors: [
|
||||||
@@ -72,7 +84,7 @@ class NumericPad extends StatelessWidget {
|
|||||||
}
|
}
|
||||||
|
|
||||||
Widget spaceWidget() {
|
Widget spaceWidget() {
|
||||||
return Expanded(
|
return const Expanded(
|
||||||
child: SizedBox()
|
child: SizedBox()
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
@@ -84,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
|
||||||
),
|
),
|
||||||
),
|
),
|
||||||
),
|
),
|
||||||
@@ -100,9 +114,19 @@ class NumericPad extends StatelessWidget {
|
|||||||
|
|
||||||
Widget removeWidget() {
|
Widget removeWidget() {
|
||||||
return Expanded(
|
return Expanded(
|
||||||
child: Icon(
|
child: GestureDetector(
|
||||||
Icons.highlight_remove,
|
onTap: () {
|
||||||
size: 28,
|
onNumberSelected('');
|
||||||
|
},
|
||||||
|
child: Container(
|
||||||
|
color: Colors.transparent,
|
||||||
|
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,
|
||||||
|
)
|
||||||
|
)
|
||||||
|
],
|
||||||
|
),
|
||||||
|
);
|
||||||
|
}
|
||||||
|
}
|
213
lib/application/component/risk_profile.dart
Normal file
@@ -0,0 +1,213 @@
|
|||||||
|
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/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:flutter/material.dart';
|
||||||
|
|
||||||
|
class RiskProfile extends StatelessWidget {
|
||||||
|
final int totalScore;
|
||||||
|
final bool rowSuitableProduct;
|
||||||
|
const RiskProfile({super.key, required this.totalScore, required this.rowSuitableProduct});
|
||||||
|
|
||||||
|
@override
|
||||||
|
Widget build(BuildContext context) {
|
||||||
|
List<RiskProfileResult> listRiskProfileResult = [
|
||||||
|
RiskProfileResult(
|
||||||
|
'Conservative',
|
||||||
|
PathAssets.imgCat,
|
||||||
|
ColorPalette.green500,
|
||||||
|
'Investors with a conservative risk profile are risk-averse or do not want to experience large losses. Therefore, mutual fund products that are suitable for conservative investors are products that have low risk and stable returns.',
|
||||||
|
[
|
||||||
|
{'desc': 'Money Market Mutual Fund', 'icon': PathAssets.iconStrongBox},
|
||||||
|
{'desc': 'Fixed Income Mutual Fund', 'icon': PathAssets.iconMoneyReceive},
|
||||||
|
{'desc': 'Balanced Mutual Fund', 'icon': PathAssets.iconBalance},
|
||||||
|
]
|
||||||
|
),
|
||||||
|
RiskProfileResult(
|
||||||
|
'Moderate',
|
||||||
|
PathAssets.imgDeer,
|
||||||
|
ColorPalette.orange500,
|
||||||
|
'Investors with a moderate risk profile are investors who are ready to accept moderate risk to get higher returns than conservative mutual fund products. Therefore, mutual fund products that are suitable for moderate investors are products that have moderate risk and higher returns than conservative mutual fund products.',
|
||||||
|
[
|
||||||
|
{'desc': 'Fixed Income Mutual Fund', 'icon': PathAssets.iconMoneyReceive},
|
||||||
|
{'desc': 'Balanced Mutual Fund', 'icon': PathAssets.iconBalance},
|
||||||
|
]
|
||||||
|
),
|
||||||
|
RiskProfileResult(
|
||||||
|
'Aggressive',
|
||||||
|
PathAssets.imgLion,
|
||||||
|
ColorPalette.purple500,
|
||||||
|
'Investors with an aggressive risk profile are investors who are ready to accept high risks to get high returns. Therefore, mutual fund products that are suitable for aggressive investors are products that have high risk and high returns.',
|
||||||
|
[
|
||||||
|
{'desc': 'Equity Mutual Fund', 'icon': PathAssets.iconCoins},
|
||||||
|
{'desc': 'Aggressive Balanced Fund', 'icon': PathAssets.iconBalance},
|
||||||
|
]
|
||||||
|
)
|
||||||
|
];
|
||||||
|
RiskProfileResult riskProfile;
|
||||||
|
if(totalScore <= 25){
|
||||||
|
riskProfile = listRiskProfileResult[0];
|
||||||
|
}else if(totalScore <= 50){
|
||||||
|
riskProfile = listRiskProfileResult[1];
|
||||||
|
}else{
|
||||||
|
riskProfile = listRiskProfileResult[2];
|
||||||
|
}
|
||||||
|
|
||||||
|
return Column(
|
||||||
|
crossAxisAlignment: CrossAxisAlignment.start,
|
||||||
|
children: [
|
||||||
|
ClipRRect(
|
||||||
|
borderRadius: BorderRadius.circular(8),
|
||||||
|
child: Container(
|
||||||
|
decoration: BoxDecoration(
|
||||||
|
color: riskProfile.color,
|
||||||
|
image: DecorationImage(image: AssetImage(riskProfile.img), alignment: Alignment.centerRight),
|
||||||
|
boxShadow: [
|
||||||
|
BoxShadow(
|
||||||
|
color: riskProfile.color.withOpacity(0.2),
|
||||||
|
blurRadius: 30
|
||||||
|
)
|
||||||
|
]
|
||||||
|
),
|
||||||
|
child: Row(
|
||||||
|
mainAxisAlignment: MainAxisAlignment.spaceBetween,
|
||||||
|
children: [
|
||||||
|
Container(
|
||||||
|
padding: const EdgeInsets.all(24),
|
||||||
|
child: Column(
|
||||||
|
crossAxisAlignment: CrossAxisAlignment.start,
|
||||||
|
children: [
|
||||||
|
Text(
|
||||||
|
riskProfile.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,
|
||||||
|
),
|
||||||
|
ExpandableWidget(
|
||||||
|
content: riskProfile.desc,
|
||||||
|
hideTextMore: true,
|
||||||
|
hideIconMore: false,
|
||||||
|
maxLinesToShow: 4,
|
||||||
|
alignmentMore: Alignment.center,
|
||||||
|
),
|
||||||
|
const SizedBox(
|
||||||
|
height: 24,
|
||||||
|
),
|
||||||
|
const Text(
|
||||||
|
'Suitable Product',
|
||||||
|
style: TextStyle(
|
||||||
|
color: ColorPalette.slate800,
|
||||||
|
fontWeight: FontWeight.bold,
|
||||||
|
fontSize: 18
|
||||||
|
),
|
||||||
|
),
|
||||||
|
const SizedBox(
|
||||||
|
height: 16,
|
||||||
|
),
|
||||||
|
rowSuitableProduct ?
|
||||||
|
Row(
|
||||||
|
children: riskProfile.suitableProduct.asMap().entries.map((e) {
|
||||||
|
return Expanded(
|
||||||
|
child: Container(
|
||||||
|
margin: EdgeInsets.only(left: e.key != 0 ? 12 : 0),
|
||||||
|
padding: const EdgeInsets.all(16),
|
||||||
|
decoration: BoxDecoration(
|
||||||
|
border: Border.all(color: ColorPalette.slate200),
|
||||||
|
borderRadius: BorderRadius.circular(6)
|
||||||
|
),
|
||||||
|
child: Column(
|
||||||
|
crossAxisAlignment: CrossAxisAlignment.start,
|
||||||
|
children: [
|
||||||
|
Container(
|
||||||
|
padding: const EdgeInsets.all(8),
|
||||||
|
decoration: BoxDecoration(
|
||||||
|
shape: BoxShape.circle,
|
||||||
|
color: riskProfile.color.withOpacity(0.1)
|
||||||
|
),
|
||||||
|
child: Image.asset(e.value['icon'], width: SizeConfig.width * 0.07, color: riskProfile.color)
|
||||||
|
),
|
||||||
|
const SizedBox(
|
||||||
|
height: 12,
|
||||||
|
),
|
||||||
|
Text(e.value['desc'],
|
||||||
|
style: const TextStyle(
|
||||||
|
fontSize: 16,
|
||||||
|
fontWeight: FontWeight.bold,
|
||||||
|
color: ColorPalette.slate800
|
||||||
|
),
|
||||||
|
)
|
||||||
|
],
|
||||||
|
),
|
||||||
|
)
|
||||||
|
);
|
||||||
|
}).toList(),
|
||||||
|
)
|
||||||
|
: Wrap(
|
||||||
|
runSpacing: 16,
|
||||||
|
children: riskProfile.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: riskProfile.color.withOpacity(0.1)
|
||||||
|
),
|
||||||
|
child: Image.asset(e['icon'], width: SizeConfig.width * 0.07, color: riskProfile.color)
|
||||||
|
),
|
||||||
|
const SizedBox(
|
||||||
|
width: 12,
|
||||||
|
),
|
||||||
|
Expanded(
|
||||||
|
child: Text(e['desc'],
|
||||||
|
style: const TextStyle(
|
||||||
|
fontSize: 18,
|
||||||
|
fontWeight: FontWeight.bold,
|
||||||
|
color: ColorPalette.slate800
|
||||||
|
),
|
||||||
|
),
|
||||||
|
)
|
||||||
|
],
|
||||||
|
),
|
||||||
|
);
|
||||||
|
}).toList(),
|
||||||
|
)
|
||||||
|
],
|
||||||
|
);
|
||||||
|
}
|
||||||
|
}
|
@@ -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);
|
||||||
|
}
|
||||||
},
|
},
|
||||||
)
|
)
|
||||||
],
|
],
|
||||||
|
@@ -1,5 +1,7 @@
|
|||||||
import 'package:cims_apps/application/assets/path_assets.dart';
|
import 'package:cims_apps/application/assets/path_assets.dart';
|
||||||
|
import 'package:cims_apps/application/component/subscribe/other_plan_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:flutter/material.dart';
|
import 'package:flutter/material.dart';
|
||||||
|
|
||||||
@@ -11,7 +13,8 @@ class GoalInvest {
|
|||||||
}
|
}
|
||||||
|
|
||||||
class GoalInvestingView extends StatelessWidget {
|
class GoalInvestingView extends StatelessWidget {
|
||||||
const GoalInvestingView({super.key});
|
final void Function(String) onListSelected;
|
||||||
|
const GoalInvestingView({super.key, required this.onListSelected});
|
||||||
|
|
||||||
@override
|
@override
|
||||||
Widget build(BuildContext context) {
|
Widget build(BuildContext context) {
|
||||||
@@ -19,7 +22,7 @@ class GoalInvestingView extends StatelessWidget {
|
|||||||
GoalInvest(PathAssets.iconToga, 'Education'),
|
GoalInvest(PathAssets.iconToga, 'Education'),
|
||||||
GoalInvest(PathAssets.iconCake, 'Marriage'),
|
GoalInvest(PathAssets.iconCake, 'Marriage'),
|
||||||
GoalInvest(PathAssets.iconHouse, 'Old age days'),
|
GoalInvest(PathAssets.iconHouse, 'Old age days'),
|
||||||
GoalInvest(PathAssets.iconCreatePlan, 'Create Plan'),
|
GoalInvest(PathAssets.iconCreatePlan, 'Other Plan'),
|
||||||
];
|
];
|
||||||
|
|
||||||
return Column(
|
return Column(
|
||||||
@@ -28,6 +31,20 @@ class GoalInvestingView extends StatelessWidget {
|
|||||||
return Padding(
|
return Padding(
|
||||||
padding: EdgeInsets.only(top: e.key != 0 ? 16 : 0),
|
padding: EdgeInsets.only(top: e.key != 0 ? 16 : 0),
|
||||||
child: ListTile(
|
child: ListTile(
|
||||||
|
onTap: () {
|
||||||
|
if(e.value.title == 'Other Plan'){
|
||||||
|
routePush(
|
||||||
|
context,
|
||||||
|
page: OtherPlanView(
|
||||||
|
selectedPlan: (val) {
|
||||||
|
onListSelected(val);
|
||||||
|
},
|
||||||
|
)
|
||||||
|
);
|
||||||
|
}else{
|
||||||
|
onListSelected(e.value.title);
|
||||||
|
}
|
||||||
|
},
|
||||||
shape: RoundedRectangleBorder(
|
shape: RoundedRectangleBorder(
|
||||||
side: BorderSide(color: ColorPalette.slate200),
|
side: BorderSide(color: ColorPalette.slate200),
|
||||||
borderRadius: BorderRadius.circular(14)
|
borderRadius: BorderRadius.circular(14)
|
||||||
@@ -47,10 +64,11 @@ class GoalInvestingView extends StatelessWidget {
|
|||||||
title: Text(e.value.title,
|
title: Text(e.value.title,
|
||||||
style: TextStyle(
|
style: TextStyle(
|
||||||
fontWeight: FontWeight.w600,
|
fontWeight: FontWeight.w600,
|
||||||
fontSize: 16
|
fontSize: 16,
|
||||||
|
color: ColorPalette.slate800
|
||||||
),
|
),
|
||||||
),
|
),
|
||||||
trailing: Icon(Icons.chevron_right_rounded),
|
trailing: Icon(Icons.chevron_right_rounded, color: ColorPalette.slate400),
|
||||||
),
|
),
|
||||||
);
|
);
|
||||||
}).toList()
|
}).toList()
|
177
lib/application/component/subscribe/input_investment_view.dart
Normal file
@@ -0,0 +1,177 @@
|
|||||||
|
import 'dart:math';
|
||||||
|
|
||||||
|
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/theme/color_palette.dart';
|
||||||
|
import 'package:cims_apps/core/utils/number_formatter.dart';
|
||||||
|
import 'package:cims_apps/core/utils/size_config.dart';
|
||||||
|
import 'package:flutter/material.dart';
|
||||||
|
|
||||||
|
class InputInvestmentView extends StatefulWidget {
|
||||||
|
final String? currentPlan;
|
||||||
|
final void Function()? changePlan;
|
||||||
|
final int? currentPrice;
|
||||||
|
final int? minimumPrice;
|
||||||
|
final int? maximumPrice;
|
||||||
|
final void Function(String value) nextMove;
|
||||||
|
const InputInvestmentView({super.key, required this.nextMove, this.currentPlan, this.minimumPrice, this.maximumPrice, this.currentPrice, this.changePlan});
|
||||||
|
|
||||||
|
@override
|
||||||
|
State<InputInvestmentView> createState() => _InputInvestmentViewState();
|
||||||
|
}
|
||||||
|
|
||||||
|
class _InputInvestmentViewState extends State<InputInvestmentView> {
|
||||||
|
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
|
||||||
|
void initState() {
|
||||||
|
// TODO: implement initState
|
||||||
|
if(widget.currentPrice != null){
|
||||||
|
inputController.text = NumberFormatter.numberCurrency(widget.currentPrice, 'Rp ', 'id_ID', decimalDigits: 0);
|
||||||
|
}else{
|
||||||
|
inputController.text = 'Rp 0';
|
||||||
|
}
|
||||||
|
super.initState();
|
||||||
|
}
|
||||||
|
|
||||||
|
@override
|
||||||
|
void dispose() {
|
||||||
|
// TODO: implement dispose
|
||||||
|
super.dispose();
|
||||||
|
inputController.dispose();
|
||||||
|
}
|
||||||
|
|
||||||
|
@override
|
||||||
|
Widget build(BuildContext context) {
|
||||||
|
return Container(
|
||||||
|
decoration: BoxDecoration(
|
||||||
|
color: Colors.white,
|
||||||
|
borderRadius: BorderRadius.circular(16)
|
||||||
|
),
|
||||||
|
child: Column(
|
||||||
|
mainAxisSize: MainAxisSize.min,
|
||||||
|
children: [
|
||||||
|
Padding(
|
||||||
|
padding: const EdgeInsets.symmetric(horizontal: 24, vertical: 12),
|
||||||
|
child: Column(
|
||||||
|
crossAxisAlignment: CrossAxisAlignment.start,
|
||||||
|
children: [
|
||||||
|
if(widget.currentPlan != null)
|
||||||
|
Row(
|
||||||
|
mainAxisAlignment: MainAxisAlignment.spaceBetween,
|
||||||
|
children: [
|
||||||
|
Text(widget.currentPlan ?? '',
|
||||||
|
style: const TextStyle(
|
||||||
|
fontSize: 20,
|
||||||
|
fontWeight: FontWeight.w700,
|
||||||
|
),
|
||||||
|
),
|
||||||
|
InkWell(
|
||||||
|
borderRadius: BorderRadius.circular(16),
|
||||||
|
onTap: widget.changePlan,
|
||||||
|
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
|
||||||
|
),
|
||||||
|
)
|
||||||
|
],
|
||||||
|
),
|
||||||
|
)
|
||||||
|
],
|
||||||
|
),
|
||||||
|
TextField(
|
||||||
|
controller: inputController,
|
||||||
|
textAlign: TextAlign.center,
|
||||||
|
style: const TextStyle(
|
||||||
|
fontSize: 28,
|
||||||
|
fontWeight: FontWeight.w600,
|
||||||
|
color: ColorPalette.slate800
|
||||||
|
),
|
||||||
|
keyboardType: TextInputType.number,
|
||||||
|
onChanged: (value) {
|
||||||
|
validationInputValue(value);
|
||||||
|
},
|
||||||
|
decoration: const InputDecoration(
|
||||||
|
enabledBorder: UnderlineInputBorder(
|
||||||
|
borderSide: BorderSide(
|
||||||
|
color: ColorPalette.primary,
|
||||||
|
width: 2
|
||||||
|
),
|
||||||
|
)
|
||||||
|
),
|
||||||
|
),
|
||||||
|
const SizedBox(height: 12),
|
||||||
|
if(widget.minimumPrice != null)
|
||||||
|
Text('Minimum ${NumberFormatter.numberCurrency(widget.minimumPrice, 'Rp ', 'id_ID')}',
|
||||||
|
style: const TextStyle(
|
||||||
|
color: ColorPalette.slate400,
|
||||||
|
fontSize: 16,
|
||||||
|
fontWeight: FontWeight.w600
|
||||||
|
),
|
||||||
|
),
|
||||||
|
if(widget.maximumPrice != null)
|
||||||
|
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) {
|
||||||
|
String currentValue = inputController.text;
|
||||||
|
if(p0.isNotEmpty){
|
||||||
|
if(currentValue != '0'){
|
||||||
|
currentValue = currentValue + p0;
|
||||||
|
}
|
||||||
|
}else{
|
||||||
|
currentValue = currentValue.substring(0, currentValue.length - 1);
|
||||||
|
}
|
||||||
|
validationInputValue(currentValue);
|
||||||
|
}),
|
||||||
|
const SizedBox(height: 24),
|
||||||
|
ButtonView(
|
||||||
|
name: 'Next',
|
||||||
|
onPressed: () {
|
||||||
|
widget.nextMove(inputController.text);
|
||||||
|
},
|
||||||
|
width: SizeConfig.width,
|
||||||
|
heightWrapContent: true,
|
||||||
|
contentPadding: const EdgeInsets.symmetric(vertical: 16),
|
||||||
|
marginVertical: 0,
|
||||||
|
)
|
||||||
|
],
|
||||||
|
),
|
||||||
|
),
|
||||||
|
],
|
||||||
|
),
|
||||||
|
);
|
||||||
|
}
|
||||||
|
}
|
190
lib/application/component/subscribe/other_plan_view.dart
Normal file
@@ -0,0 +1,190 @@
|
|||||||
|
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/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:flutter/material.dart';
|
||||||
|
|
||||||
|
class Plan {
|
||||||
|
String img, name;
|
||||||
|
|
||||||
|
Plan(this.img, this.name);
|
||||||
|
}
|
||||||
|
|
||||||
|
class OtherPlanView extends StatefulWidget {
|
||||||
|
final void Function(String value) selectedPlan;
|
||||||
|
const OtherPlanView({super.key, required this.selectedPlan});
|
||||||
|
|
||||||
|
@override
|
||||||
|
State<OtherPlanView> createState() => _OtherPlanViewState();
|
||||||
|
}
|
||||||
|
|
||||||
|
class _OtherPlanViewState extends State<OtherPlanView> {
|
||||||
|
TextEditingController createController = TextEditingController();
|
||||||
|
Plan selectedPlan = Plan('', '');
|
||||||
|
|
||||||
|
List<Plan> listPlan = [
|
||||||
|
Plan(PathAssets.iconToga, 'Education'),
|
||||||
|
Plan(PathAssets.iconCake, 'Marriage'),
|
||||||
|
Plan(PathAssets.iconHouse, 'Home'),
|
||||||
|
Plan(PathAssets.iconTicket, 'Entertainment'),
|
||||||
|
Plan(PathAssets.iconGadget, 'Gadget'),
|
||||||
|
Plan(PathAssets.iconMarket, 'Business'),
|
||||||
|
Plan(PathAssets.iconBag, 'Fashion'),
|
||||||
|
Plan(PathAssets.iconCart, 'Shop'),
|
||||||
|
Plan(PathAssets.iconCar, 'Vehicle'),
|
||||||
|
Plan(PathAssets.iconPlane, 'Holiday'),
|
||||||
|
Plan(PathAssets.iconCreatePlan, 'Create Plan'),
|
||||||
|
];
|
||||||
|
|
||||||
|
@override
|
||||||
|
void initState() {
|
||||||
|
// TODO: implement initState
|
||||||
|
super.initState();
|
||||||
|
}
|
||||||
|
|
||||||
|
@override
|
||||||
|
void dispose() {
|
||||||
|
// TODO: implement dispose
|
||||||
|
super.dispose();
|
||||||
|
createController.dispose();
|
||||||
|
}
|
||||||
|
|
||||||
|
@override
|
||||||
|
Widget build(BuildContext context) {
|
||||||
|
return Scaffold(
|
||||||
|
appBar: CustomAppBar(
|
||||||
|
height: 70,
|
||||||
|
title: 'Other Plan'
|
||||||
|
),
|
||||||
|
body: GridView(
|
||||||
|
padding: EdgeInsets.symmetric(horizontal: 24, vertical: 32),
|
||||||
|
gridDelegate: SliverGridDelegateWithFixedCrossAxisCount(crossAxisCount: 3),
|
||||||
|
children: listPlan.map((e) => cardPlan(e)).toList(),
|
||||||
|
),
|
||||||
|
bottomNavigationBar: Container(
|
||||||
|
height: 110,
|
||||||
|
padding: EdgeInsets.symmetric(horizontal: 24),
|
||||||
|
child: ButtonView(
|
||||||
|
name: 'Select',
|
||||||
|
disabled: !(selectedPlan.img != ''),
|
||||||
|
onPressed: () {
|
||||||
|
Navigator.pop(context);
|
||||||
|
print('haloo');
|
||||||
|
print(selectedPlan.name);
|
||||||
|
widget.selectedPlan(selectedPlan.name);
|
||||||
|
},
|
||||||
|
heightWrapContent: true,
|
||||||
|
width: SizeConfig.width,
|
||||||
|
contentPadding: EdgeInsets.symmetric(vertical: 12),
|
||||||
|
textColor: selectedPlan.img == '' ? ColorPalette.slate500 : ColorPalette.white,
|
||||||
|
disabledBgColor: ColorPalette.slate200,
|
||||||
|
backgroundColor: ColorPalette.primary,
|
||||||
|
),
|
||||||
|
),
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
Widget cardPlan(Plan plan) {
|
||||||
|
return GestureDetector(
|
||||||
|
onTap: () {
|
||||||
|
if(plan.name == 'Create Plan'){
|
||||||
|
showModalBottomSheet(
|
||||||
|
context: context,
|
||||||
|
isDismissible: false,
|
||||||
|
builder: (context) => modalCreatePlan(),
|
||||||
|
);
|
||||||
|
}
|
||||||
|
setState(() {
|
||||||
|
selectedPlan = plan;
|
||||||
|
});
|
||||||
|
},
|
||||||
|
child: Container(
|
||||||
|
padding: EdgeInsets.symmetric(horizontal: 16, vertical: 8),
|
||||||
|
decoration: BoxDecoration(
|
||||||
|
borderRadius: BorderRadius.circular(16),
|
||||||
|
border: Border.all(color: selectedPlan == plan ? ColorPalette.primary : Colors.transparent)
|
||||||
|
),
|
||||||
|
child: Column(
|
||||||
|
mainAxisAlignment: MainAxisAlignment.center,
|
||||||
|
children: [
|
||||||
|
Container(
|
||||||
|
width: SizeConfig.width * 0.12,
|
||||||
|
height: SizeConfig.width * 0.12,
|
||||||
|
padding: EdgeInsets.all(12),
|
||||||
|
alignment: Alignment.center,
|
||||||
|
decoration: BoxDecoration(
|
||||||
|
borderRadius: BorderRadius.circular(8),
|
||||||
|
color: ColorPalette.blue200.withOpacity(0.5)
|
||||||
|
),
|
||||||
|
child: ImageView(image: plan.img)
|
||||||
|
),
|
||||||
|
SizedBox(height: 12),
|
||||||
|
Text(plan.name,
|
||||||
|
style: TextStyle(
|
||||||
|
color: selectedPlan == plan ? ColorPalette.primary : ColorPalette.slate800,
|
||||||
|
fontWeight: FontWeight.w600
|
||||||
|
),
|
||||||
|
)
|
||||||
|
],
|
||||||
|
),
|
||||||
|
),
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
Widget modalCreatePlan() {
|
||||||
|
return Container(
|
||||||
|
padding: EdgeInsets.all(24),
|
||||||
|
child: Column(
|
||||||
|
mainAxisSize: MainAxisSize.min,
|
||||||
|
children: [
|
||||||
|
Row(
|
||||||
|
mainAxisAlignment: MainAxisAlignment.spaceBetween,
|
||||||
|
children: [
|
||||||
|
Text('Create your plan',
|
||||||
|
style: TextStyle(
|
||||||
|
fontWeight: FontWeight.w600,
|
||||||
|
color: ColorPalette.slate800,
|
||||||
|
fontSize: 16
|
||||||
|
),
|
||||||
|
),
|
||||||
|
GestureDetector(
|
||||||
|
onTap: () {
|
||||||
|
Navigator.pop(context);
|
||||||
|
setState(() {
|
||||||
|
selectedPlan = Plan('', '');
|
||||||
|
});
|
||||||
|
},
|
||||||
|
child: Icon(Icons.close_rounded),
|
||||||
|
)
|
||||||
|
],
|
||||||
|
),
|
||||||
|
TextFormView(
|
||||||
|
name: 'Objective Name',
|
||||||
|
ctrl: createController,
|
||||||
|
),
|
||||||
|
SizedBox(height: 24),
|
||||||
|
ButtonView(
|
||||||
|
name: 'Next',
|
||||||
|
marginVertical: 0,
|
||||||
|
disabled: !(createController.text != ''),
|
||||||
|
onPressed: () {
|
||||||
|
Navigator.of(context)..pop()..pop();
|
||||||
|
widget.selectedPlan(createController.text);
|
||||||
|
},
|
||||||
|
heightWrapContent: true,
|
||||||
|
width: SizeConfig.width,
|
||||||
|
contentPadding: EdgeInsets.symmetric(vertical: 16),
|
||||||
|
textColor: createController.text == '' ? ColorPalette.slate500 : ColorPalette.white,
|
||||||
|
disabledBgColor: ColorPalette.slate200,
|
||||||
|
backgroundColor: ColorPalette.primary,
|
||||||
|
),
|
||||||
|
],
|
||||||
|
),
|
||||||
|
);
|
||||||
|
}
|
||||||
|
}
|
255
lib/application/component/subscribe/total_payment_view.dart
Normal file
@@ -0,0 +1,255 @@
|
|||||||
|
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/core/route/route.dart';
|
||||||
|
import 'package:cims_apps/core/utils/number_formatter.dart';
|
||||||
|
import 'package:cims_apps/features/dashboard/dashboard_account/view/product/view/step_subscribe/payment_method_view.dart';
|
||||||
|
import 'package:cims_apps/features/dashboard/dashboard_account/view/product/view_model/product_view_model.dart';
|
||||||
|
import 'package:flutter/material.dart';
|
||||||
|
|
||||||
|
class TotalPaymentView extends StatelessWidget {
|
||||||
|
final int totalInvest;
|
||||||
|
final List<Product> listProduct;
|
||||||
|
final bool isAgree;
|
||||||
|
final void Function() onTapAgree;
|
||||||
|
const TotalPaymentView({
|
||||||
|
super.key,
|
||||||
|
required this.listProduct,
|
||||||
|
required this.totalInvest,
|
||||||
|
required this.isAgree,
|
||||||
|
required this.onTapAgree,
|
||||||
|
});
|
||||||
|
|
||||||
|
@override
|
||||||
|
Widget build(BuildContext context) {
|
||||||
|
return SingleChildScrollView(
|
||||||
|
child: Container(
|
||||||
|
decoration: BoxDecoration(
|
||||||
|
color: Colors.white, borderRadius: BorderRadius.circular(16)),
|
||||||
|
child: Column(
|
||||||
|
mainAxisSize: MainAxisSize.min,
|
||||||
|
children: [
|
||||||
|
Padding(
|
||||||
|
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))
|
||||||
|
],
|
||||||
|
),
|
||||||
|
),
|
||||||
|
...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(
|
||||||
|
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),
|
||||||
|
// ))
|
||||||
|
// ],
|
||||||
|
// ))
|
||||||
|
// ],
|
||||||
|
// ),
|
||||||
|
// );
|
||||||
|
// }
|
||||||
|
}
|
52
lib/application/component/success_view.dart
Normal file
@@ -0,0 +1,52 @@
|
|||||||
|
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 SuccessView extends StatelessWidget {
|
||||||
|
final String img;
|
||||||
|
final String textTitle;
|
||||||
|
final Widget? subtitle;
|
||||||
|
final void Function() nextRoute;
|
||||||
|
const SuccessView({super.key,
|
||||||
|
required this.img,
|
||||||
|
required this.textTitle,
|
||||||
|
required this.subtitle,
|
||||||
|
required this.nextRoute
|
||||||
|
});
|
||||||
|
|
||||||
|
@override
|
||||||
|
Widget build(BuildContext context) {
|
||||||
|
return Scaffold(
|
||||||
|
body: Center(
|
||||||
|
child: Column(
|
||||||
|
mainAxisAlignment: MainAxisAlignment.center,
|
||||||
|
children: [
|
||||||
|
ImageView(image: img, width: SizeConfig.width * .8,),
|
||||||
|
Text(textTitle,
|
||||||
|
style: TextStyle(
|
||||||
|
fontWeight: FontWeight.w700,
|
||||||
|
fontSize: 28,
|
||||||
|
),
|
||||||
|
),
|
||||||
|
subtitle ?? SizedBox()
|
||||||
|
],
|
||||||
|
),
|
||||||
|
),
|
||||||
|
bottomNavigationBar: Container(
|
||||||
|
padding: EdgeInsets.all(24),
|
||||||
|
height: 110,
|
||||||
|
width: SizeConfig.width,
|
||||||
|
child: ButtonView(
|
||||||
|
name: 'Done',
|
||||||
|
onPressed: nextRoute,
|
||||||
|
marginVertical: 0,
|
||||||
|
heightWrapContent: true,
|
||||||
|
width: SizeConfig.width,
|
||||||
|
textSize: 20,
|
||||||
|
contentPadding: EdgeInsets.symmetric(vertical: 12),
|
||||||
|
),
|
||||||
|
),
|
||||||
|
);
|
||||||
|
}
|
||||||
|
}
|
@@ -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();
|
||||||
|
@@ -5,6 +5,7 @@ import 'package:remove_emoji_input_formatter/remove_emoji_input_formatter.dart';
|
|||||||
|
|
||||||
class TextFormView extends StatelessWidget {
|
class TextFormView extends StatelessWidget {
|
||||||
final String name;
|
final String name;
|
||||||
|
final double nameSize;
|
||||||
final String? helperText;
|
final String? helperText;
|
||||||
final String? initialValue;
|
final String? initialValue;
|
||||||
final VoidCallback? onTap;
|
final VoidCallback? onTap;
|
||||||
@@ -40,6 +41,7 @@ class TextFormView extends StatelessWidget {
|
|||||||
TextFormView(
|
TextFormView(
|
||||||
{Key? key,
|
{Key? key,
|
||||||
required this.name,
|
required this.name,
|
||||||
|
this.nameSize = 16,
|
||||||
this.helperText,
|
this.helperText,
|
||||||
this.onTap,
|
this.onTap,
|
||||||
this.fontColorDisabled,
|
this.fontColorDisabled,
|
||||||
@@ -97,17 +99,17 @@ class TextFormView extends StatelessWidget {
|
|||||||
children: [
|
children: [
|
||||||
Text(
|
Text(
|
||||||
name,
|
name,
|
||||||
style: const TextStyle(
|
style: TextStyle(
|
||||||
fontSize: 16,
|
fontSize: nameSize,
|
||||||
fontWeight: FontWeight.w600,
|
fontWeight: FontWeight.w600,
|
||||||
color: ColorPalette.slate800,
|
color: ColorPalette.slate800,
|
||||||
),
|
),
|
||||||
),
|
),
|
||||||
suffixLable ??
|
suffixLable ??
|
||||||
const Text(
|
Text(
|
||||||
"",
|
"",
|
||||||
style: TextStyle(
|
style: TextStyle(
|
||||||
fontSize: 16,
|
fontSize: nameSize,
|
||||||
color: Colors.red,
|
color: Colors.red,
|
||||||
),
|
),
|
||||||
),
|
),
|
||||||
@@ -139,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,
|
||||||
@@ -161,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,
|
||||||
@@ -188,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,8 @@ 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 slate50 = Color(0xFFF8FAFC);
|
static const Color slate50 = Color(0xFFF8FAFC);
|
||||||
static const Color slate200 = Color(0xFFE2E8F0);
|
static const Color slate200 = Color(0xFFE2E8F0);
|
||||||
static const Color slate300 = Color(0xFFCBD5E1);
|
static const Color slate300 = Color(0xFFCBD5E1);
|
||||||
@@ -89,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,
|
||||||
@@ -105,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,69 +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,
|
|
||||||
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,9 +1,19 @@
|
|||||||
|
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/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/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';
|
||||||
|
|
||||||
|
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);
|
||||||
|
|
||||||
@@ -16,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,
|
||||||
@@ -60,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,23 +243,25 @@ 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(e.value.name));
|
routePush(context, page: InvestTypeView(title: e.value.name));
|
||||||
},
|
},
|
||||||
child: Container(
|
child: Container(
|
||||||
color: Colors.white,
|
color: Colors.white,
|
||||||
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),
|
||||||
),
|
|
||||||
),
|
|
||||||
),
|
),
|
||||||
],
|
),
|
||||||
)
|
],
|
||||||
)
|
))
|
||||||
],
|
],
|
||||||
),
|
),
|
||||||
);
|
);
|
||||||
|
@@ -6,95 +6,124 @@ 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';
|
||||||
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/product/product_view.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:flutter/material.dart';
|
import 'package:flutter/material.dart';
|
||||||
|
import 'package:provider/provider.dart';
|
||||||
class Product {
|
|
||||||
String name;
|
|
||||||
double yield;
|
|
||||||
double priceUnit;
|
|
||||||
double funds;
|
|
||||||
|
|
||||||
Product(this.name, this.yield, this.priceUnit, this.funds);
|
|
||||||
}
|
|
||||||
|
|
||||||
class InvestTypeView extends StatefulWidget {
|
class InvestTypeView extends StatefulWidget {
|
||||||
final String title;
|
final String title;
|
||||||
const InvestTypeView(this.title, {super.key});
|
const InvestTypeView({super.key, required this.title});
|
||||||
|
|
||||||
@override
|
@override
|
||||||
State<InvestTypeView> createState() => _InvestTypeViewState();
|
State<InvestTypeView> createState() => _InvestTypeViewState();
|
||||||
}
|
}
|
||||||
|
|
||||||
class _InvestTypeViewState extends State<InvestTypeView> {
|
class _InvestTypeViewState extends State<InvestTypeView> {
|
||||||
|
|
||||||
List<Product> listProduct = [
|
List<Product> listProduct = [
|
||||||
Product('Gemilang Dana Kas Maxima', 8.17, 2600.79, 6300000),
|
Product(
|
||||||
Product('Gemilang Dana Likuid', 6.42, 1600.79, 2340000),
|
name: 'Gemilang Dana Kas Maxima',
|
||||||
Product('Gemilang Income Fund', 8.17, 2600.79, 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
|
||||||
|
void initState() {
|
||||||
|
// TODO: implement initState
|
||||||
|
super.initState();
|
||||||
|
listProduct = listProduct.map((e) {
|
||||||
|
e.type = widget.title;
|
||||||
|
return e;
|
||||||
|
}).toList();
|
||||||
|
}
|
||||||
|
|
||||||
@override
|
@override
|
||||||
Widget build(BuildContext context) {
|
Widget build(BuildContext context) {
|
||||||
return Scaffold(
|
return ChangeNotifierProvider<ProductViewModel>(
|
||||||
body: SizedBox(
|
create: (context) => ProductViewModel(),
|
||||||
width: SizeConfig.width,
|
child: Consumer<ProductViewModel>(builder: (context, provider, child) {
|
||||||
height: SizeConfig.height,
|
return Scaffold(
|
||||||
child: Stack(
|
body: SizedBox(
|
||||||
children: [
|
width: SizeConfig.width,
|
||||||
const ImageView(image: PathAssets.imgDashboardAccount),
|
height: SizeConfig.height,
|
||||||
Column(
|
child: Stack(
|
||||||
children: [
|
children: [
|
||||||
const SizedBox(
|
const ImageView(image: PathAssets.imgDashboardAccount),
|
||||||
height: 50,
|
Column(
|
||||||
),
|
children: [
|
||||||
Padding(
|
SizedBox(
|
||||||
padding: const EdgeInsets.symmetric(horizontal: 24),
|
height: SizeConfig.height * .1,
|
||||||
child: Row(
|
),
|
||||||
mainAxisAlignment: MainAxisAlignment.spaceBetween,
|
Padding(
|
||||||
children: [
|
padding: const EdgeInsets.symmetric(horizontal: 24),
|
||||||
const BackButtonView(),
|
child: Row(
|
||||||
TextTitle(title: widget.title, color: Colors.white),
|
mainAxisAlignment: MainAxisAlignment.spaceBetween,
|
||||||
SizedBox(
|
children: [
|
||||||
width: SizeConfig.width * 0.1,
|
const BackButtonView(),
|
||||||
)
|
TextTitle(title: widget.title, color: Colors.white),
|
||||||
],
|
SizedBox(
|
||||||
),
|
width: SizeConfig.width * 0.1,
|
||||||
),
|
)
|
||||||
const SizedBox(
|
],
|
||||||
height: 24,
|
),
|
||||||
),
|
),
|
||||||
Container(
|
const SizedBox(
|
||||||
padding: const EdgeInsets.all(24),
|
height: 24,
|
||||||
decoration: BoxDecoration(
|
),
|
||||||
borderRadius: BorderRadius.circular(16),
|
Expanded(
|
||||||
color: Colors.white
|
child: Container(
|
||||||
),
|
padding: const EdgeInsets.all(24),
|
||||||
child: Column(
|
decoration: BoxDecoration(
|
||||||
children: [
|
borderRadius: BorderRadius.circular(16),
|
||||||
filters(),
|
color: Colors.white),
|
||||||
ListView(
|
child: SingleChildScrollView(
|
||||||
shrinkWrap: true,
|
scrollDirection: Axis.vertical,
|
||||||
children: listProduct.asMap().entries.map((e) {
|
child: Column(
|
||||||
return GestureDetector(
|
children: [
|
||||||
onTap: () {
|
filters(),
|
||||||
routePush(context, page: ProductView(widget.title));
|
ListView(
|
||||||
},
|
shrinkWrap: true,
|
||||||
child: Padding(
|
children: listProduct.asMap().entries.map((e) {
|
||||||
padding: EdgeInsets.only(top: e.key != 0 ? 24 : 0),
|
return GestureDetector(
|
||||||
child: cardProduct(e.value),
|
onTap: () {
|
||||||
),
|
provider.setSelectedProduct(e.value);
|
||||||
);
|
routePush(context,
|
||||||
}).toList(),
|
page: ProductView(selectedProduct: e.value));
|
||||||
)
|
},
|
||||||
],
|
child: Padding(
|
||||||
),
|
padding: EdgeInsets.only(
|
||||||
),
|
top: e.key != 0 ? 24 : 0),
|
||||||
|
child: cardProduct(e.value),
|
||||||
|
),
|
||||||
|
);
|
||||||
|
}).toList(),
|
||||||
|
)
|
||||||
|
],
|
||||||
|
),
|
||||||
|
),
|
||||||
|
),
|
||||||
|
),
|
||||||
|
],
|
||||||
|
)
|
||||||
],
|
],
|
||||||
)
|
),
|
||||||
],
|
),
|
||||||
),
|
);
|
||||||
),
|
}),
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -104,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',
|
||||||
|
() {}),
|
||||||
],
|
],
|
||||||
),
|
),
|
||||||
);
|
);
|
||||||
@@ -115,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,
|
||||||
@@ -131,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
|
|
||||||
),
|
|
||||||
)
|
)
|
||||||
],
|
],
|
||||||
),
|
),
|
||||||
@@ -152,17 +194,18 @@ 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,
|
||||||
),
|
),
|
||||||
Expanded(
|
Expanded(
|
||||||
child: Text(
|
child: Text(
|
||||||
product.name,
|
product.name ?? '',
|
||||||
style: const TextStyle(
|
style: const TextStyle(
|
||||||
fontWeight: FontWeight.bold,
|
fontWeight: FontWeight.bold, fontSize: 18),
|
||||||
fontSize: 18
|
|
||||||
),
|
|
||||||
),
|
),
|
||||||
)
|
)
|
||||||
],
|
],
|
||||||
@@ -176,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),
|
||||||
),
|
|
||||||
),
|
),
|
||||||
],
|
],
|
||||||
)
|
)
|
||||||
@@ -213,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),
|
||||||
),
|
|
||||||
),
|
),
|
||||||
],
|
],
|
||||||
)
|
)
|
||||||
@@ -232,5 +296,4 @@ class _InvestTypeViewState extends State<InvestTypeView> {
|
|||||||
),
|
),
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
@@ -1,22 +0,0 @@
|
|||||||
import 'package:cims_apps/application/component/custom_app_bar/custom_app_bar.dart';
|
|
||||||
import 'package:cims_apps/application/component/goal_investing_view.dart';
|
|
||||||
import 'package:flutter/material.dart';
|
|
||||||
|
|
||||||
class PlanView extends StatelessWidget {
|
|
||||||
const PlanView({super.key});
|
|
||||||
|
|
||||||
@override
|
|
||||||
Widget build(BuildContext context) {
|
|
||||||
return Scaffold(
|
|
||||||
appBar: CustomAppBar(height: 70, title: 'Investment Plan'),
|
|
||||||
body: SingleChildScrollView(
|
|
||||||
padding: EdgeInsets.all(24),
|
|
||||||
child: Column(
|
|
||||||
children: [
|
|
||||||
GoalInvestingView()
|
|
||||||
],
|
|
||||||
),
|
|
||||||
),
|
|
||||||
);
|
|
||||||
}
|
|
||||||
}
|
|
@@ -0,0 +1,132 @@
|
|||||||
|
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/input_investment_view.dart';
|
||||||
|
import 'package:cims_apps/application/component/risk_profile.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/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:flutter/material.dart';
|
||||||
|
import 'package:provider/provider.dart';
|
||||||
|
|
||||||
|
class PlanView extends StatefulWidget {
|
||||||
|
const PlanView({super.key});
|
||||||
|
|
||||||
|
@override
|
||||||
|
State<PlanView> createState() => _PlanViewState();
|
||||||
|
}
|
||||||
|
|
||||||
|
class _PlanViewState extends State<PlanView> {
|
||||||
|
TextEditingController inputController = TextEditingController();
|
||||||
|
|
||||||
|
@override
|
||||||
|
void initState() {
|
||||||
|
// TODO: implement initState
|
||||||
|
inputController.text = 'Rp 0';
|
||||||
|
super.initState();
|
||||||
|
}
|
||||||
|
|
||||||
|
@override
|
||||||
|
void dispose() {
|
||||||
|
// TODO: implement dispose
|
||||||
|
super.dispose();
|
||||||
|
inputController.dispose();
|
||||||
|
}
|
||||||
|
|
||||||
|
@override
|
||||||
|
Widget build(BuildContext context) {
|
||||||
|
|
||||||
|
return ChangeNotifierProvider(
|
||||||
|
create: (context) => PlanViewModel(),
|
||||||
|
child: Scaffold(
|
||||||
|
appBar: CustomAppBar(
|
||||||
|
height: SizeConfig.height * 0.08,
|
||||||
|
title: 'Investment Plan',
|
||||||
|
leading: const SizedBox(),
|
||||||
|
),
|
||||||
|
body: SingleChildScrollView(
|
||||||
|
padding: const EdgeInsets.all(24),
|
||||||
|
child: Column(
|
||||||
|
crossAxisAlignment: CrossAxisAlignment.start,
|
||||||
|
children: [
|
||||||
|
const RiskProfile(
|
||||||
|
totalScore: 26,
|
||||||
|
rowSuitableProduct: true
|
||||||
|
),
|
||||||
|
const SizedBox(
|
||||||
|
height: 32,
|
||||||
|
),
|
||||||
|
const Text('Your Goal in Investing',
|
||||||
|
style: TextStyle(
|
||||||
|
fontWeight: FontWeight.w700,
|
||||||
|
color: ColorPalette.slate800,
|
||||||
|
fontSize: 18
|
||||||
|
),
|
||||||
|
),
|
||||||
|
const SizedBox(
|
||||||
|
height: 24,
|
||||||
|
),
|
||||||
|
GoalInvestingView(
|
||||||
|
onListSelected: (p0) {
|
||||||
|
showModalBottomSheet(
|
||||||
|
context: context,
|
||||||
|
isScrollControlled: true,
|
||||||
|
builder: (context) {
|
||||||
|
return modalInvest(context, p0);
|
||||||
|
},
|
||||||
|
);
|
||||||
|
},
|
||||||
|
)
|
||||||
|
],
|
||||||
|
),
|
||||||
|
),
|
||||||
|
),
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
Widget modalInvest(context, String text) {
|
||||||
|
return Container(
|
||||||
|
decoration: BoxDecoration(
|
||||||
|
color: Colors.white,
|
||||||
|
borderRadius: BorderRadius.circular(16)
|
||||||
|
),
|
||||||
|
child: Column(
|
||||||
|
mainAxisSize: MainAxisSize.min,
|
||||||
|
children: [
|
||||||
|
Padding(
|
||||||
|
padding: const EdgeInsets.symmetric(horizontal: 24, vertical: 18),
|
||||||
|
child: Row(
|
||||||
|
mainAxisAlignment: MainAxisAlignment.spaceBetween,
|
||||||
|
children: [
|
||||||
|
const Text("It's time to invest",
|
||||||
|
style: TextStyle(
|
||||||
|
fontSize: 16,
|
||||||
|
fontWeight: FontWeight.w600
|
||||||
|
),
|
||||||
|
),
|
||||||
|
GestureDetector(
|
||||||
|
onTap: () {
|
||||||
|
Navigator.pop(context);
|
||||||
|
},
|
||||||
|
child: const Icon(Icons.close_rounded)
|
||||||
|
)
|
||||||
|
],
|
||||||
|
),
|
||||||
|
),
|
||||||
|
const Divider(color: ColorPalette.slate200, height: 1),
|
||||||
|
InputInvestmentView(
|
||||||
|
currentPlan: text,
|
||||||
|
changePlan: () {
|
||||||
|
Navigator.pop(context);
|
||||||
|
},
|
||||||
|
nextMove: (value) {
|
||||||
|
Navigator.pop(context);
|
||||||
|
int formatIntParse = int.parse(value.replaceAll('Rp ', '').replaceAll('.', ''));
|
||||||
|
showModalBottomSheet(context: context, builder: (context) => OptionsStartingInvest(totalInvest: formatIntParse));
|
||||||
|
},
|
||||||
|
),
|
||||||
|
],
|
||||||
|
),
|
||||||
|
);
|
||||||
|
}
|
||||||
|
}
|
@@ -0,0 +1,123 @@
|
|||||||
|
import 'package:cims_apps/application/assets/path_assets.dart';
|
||||||
|
import 'package:cims_apps/application/theme/color_palette.dart';
|
||||||
|
import 'package:cims_apps/features/dashboard/dashboard_account/view/plan/view/step_invest_plan/result_options_product.dart';
|
||||||
|
import 'package:flutter/material.dart';
|
||||||
|
|
||||||
|
class OptionsStartingInvest extends StatelessWidget {
|
||||||
|
final int totalInvest;
|
||||||
|
const OptionsStartingInvest({super.key, required this.totalInvest});
|
||||||
|
|
||||||
|
@override
|
||||||
|
Widget build(BuildContext context) {
|
||||||
|
List<dynamic> listOptions = [
|
||||||
|
{
|
||||||
|
"title": "Results From Your Risk Profile",
|
||||||
|
"subtitle": "Start Investing from recommended products that suit you",
|
||||||
|
"iconImg": PathAssets.iconThumb,
|
||||||
|
"value": "risk profile"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"title": "Create Portfolio",
|
||||||
|
"subtitle": "Choose a portfolio according to your investment goals",
|
||||||
|
"iconImg": PathAssets.iconPortofolio,
|
||||||
|
"value": "investment goals"
|
||||||
|
}
|
||||||
|
];
|
||||||
|
|
||||||
|
return Container(
|
||||||
|
decoration: BoxDecoration(
|
||||||
|
color: Colors.white,
|
||||||
|
borderRadius: BorderRadius.circular(16)
|
||||||
|
),
|
||||||
|
child: Column(
|
||||||
|
crossAxisAlignment: CrossAxisAlignment.start,
|
||||||
|
mainAxisSize: MainAxisSize.min,
|
||||||
|
children: [
|
||||||
|
Padding(
|
||||||
|
padding: const EdgeInsets.symmetric(horizontal: 24, vertical: 16),
|
||||||
|
child: Row(
|
||||||
|
mainAxisAlignment: MainAxisAlignment.spaceBetween,
|
||||||
|
children: [
|
||||||
|
Text('Your options for starting to invest',
|
||||||
|
style: TextStyle(
|
||||||
|
fontSize: 18,
|
||||||
|
fontWeight: FontWeight.w600
|
||||||
|
),
|
||||||
|
),
|
||||||
|
GestureDetector(
|
||||||
|
onTap: () {
|
||||||
|
Navigator.pop(context);
|
||||||
|
},
|
||||||
|
child: Icon(Icons.close_rounded),
|
||||||
|
)
|
||||||
|
],
|
||||||
|
),
|
||||||
|
),
|
||||||
|
SizedBox(height: 8),
|
||||||
|
...listOptions.asMap().entries.map((e) {
|
||||||
|
return GestureDetector(
|
||||||
|
onTap: () {
|
||||||
|
Navigator.pop(context);
|
||||||
|
showModalBottomSheet(
|
||||||
|
context: context,
|
||||||
|
isScrollControlled: true,
|
||||||
|
builder: (context) => ResultOptionsProduct(totalInvest: totalInvest));
|
||||||
|
},
|
||||||
|
child: Container(
|
||||||
|
margin: const EdgeInsets.only(left: 24, right: 24, bottom: 12),
|
||||||
|
padding: EdgeInsets.all(16),
|
||||||
|
decoration: BoxDecoration(
|
||||||
|
borderRadius: BorderRadius.circular(14),
|
||||||
|
border: Border.all(color: ColorPalette.slate200),
|
||||||
|
),
|
||||||
|
child: Row(
|
||||||
|
children: [
|
||||||
|
Expanded(
|
||||||
|
child: Row(
|
||||||
|
crossAxisAlignment: CrossAxisAlignment.start,
|
||||||
|
children: [
|
||||||
|
Container(
|
||||||
|
padding: EdgeInsets.all(8),
|
||||||
|
alignment: Alignment.center,
|
||||||
|
decoration: BoxDecoration(
|
||||||
|
color: ColorPalette.blue200.withOpacity(0.5),
|
||||||
|
borderRadius: BorderRadius.circular(8)
|
||||||
|
),
|
||||||
|
child: Image.asset(e.value['iconImg'], width: 22),
|
||||||
|
),
|
||||||
|
SizedBox(width: 16),
|
||||||
|
Expanded(
|
||||||
|
child: Column(
|
||||||
|
crossAxisAlignment: CrossAxisAlignment.start,
|
||||||
|
children: [
|
||||||
|
Text(e.value['title'],
|
||||||
|
style: TextStyle(
|
||||||
|
fontWeight: FontWeight.w600,
|
||||||
|
color: ColorPalette.slate800,
|
||||||
|
fontSize: 16
|
||||||
|
),
|
||||||
|
),
|
||||||
|
SizedBox(height: 4),
|
||||||
|
Text(e.value['subtitle'],
|
||||||
|
style: TextStyle(
|
||||||
|
color: ColorPalette.slate400
|
||||||
|
),
|
||||||
|
)
|
||||||
|
],
|
||||||
|
),
|
||||||
|
)
|
||||||
|
],
|
||||||
|
),
|
||||||
|
),
|
||||||
|
Icon(Icons.keyboard_arrow_right_rounded, color: ColorPalette.slate400,)
|
||||||
|
],
|
||||||
|
),
|
||||||
|
),
|
||||||
|
);
|
||||||
|
}),
|
||||||
|
SizedBox(height: 16,)
|
||||||
|
],
|
||||||
|
),
|
||||||
|
);
|
||||||
|
}
|
||||||
|
}
|
@@ -0,0 +1,193 @@
|
|||||||
|
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/subscribe/total_payment_view.dart';
|
||||||
|
import 'package:cims_apps/application/theme/color_palette.dart';
|
||||||
|
import 'package:cims_apps/core/route/route.dart';
|
||||||
|
import 'package:cims_apps/core/utils/size_config.dart';
|
||||||
|
import 'package:cims_apps/features/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:flutter/material.dart';
|
||||||
|
import 'package:provider/provider.dart';
|
||||||
|
|
||||||
|
class ResultOptionsProduct extends StatelessWidget {
|
||||||
|
final int totalInvest;
|
||||||
|
const ResultOptionsProduct({super.key, required this.totalInvest});
|
||||||
|
|
||||||
|
@override
|
||||||
|
Widget build(BuildContext context) {
|
||||||
|
List<Product> listProduct = [
|
||||||
|
Product(name: 'Gemilang Dana Kas Maxima', type: 'Money Market', totalPercent: 0.7),
|
||||||
|
Product(name: 'Gemilang Dana Likuid', type: 'Bonds', totalPercent: 0.2),
|
||||||
|
Product(name: 'Gemilang Kas 2 Kelas A', type: 'Shares', totalPercent: 0.1)
|
||||||
|
];
|
||||||
|
|
||||||
|
return ChangeNotifierProvider(
|
||||||
|
create: (context) => PlanViewModel(),
|
||||||
|
child: Consumer<PlanViewModel>(
|
||||||
|
builder: (context, provider, child) {
|
||||||
|
return Container(
|
||||||
|
decoration: BoxDecoration(
|
||||||
|
color: Colors.white,
|
||||||
|
borderRadius: BorderRadius.circular(16)
|
||||||
|
),
|
||||||
|
padding: const EdgeInsets.all(24),
|
||||||
|
child: Column(
|
||||||
|
mainAxisSize: MainAxisSize.min,
|
||||||
|
children: [
|
||||||
|
Row(
|
||||||
|
mainAxisAlignment: MainAxisAlignment.spaceBetween,
|
||||||
|
children: [
|
||||||
|
GestureDetector(
|
||||||
|
onTap: () {
|
||||||
|
Navigator.pop(context);
|
||||||
|
showModalBottomSheet(
|
||||||
|
context: context,
|
||||||
|
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(
|
||||||
|
children: listProduct.asMap().entries.map((e) {
|
||||||
|
return Container(
|
||||||
|
margin: const EdgeInsets.only(bottom: 16),
|
||||||
|
padding: const EdgeInsets.all(16),
|
||||||
|
decoration: BoxDecoration(
|
||||||
|
color: Colors.white,
|
||||||
|
border: Border.all(color: ColorPalette.slate200),
|
||||||
|
borderRadius: BorderRadius.circular(12),
|
||||||
|
boxShadow: const [
|
||||||
|
BoxShadow(
|
||||||
|
color: Color(0XFF1E293B0A)
|
||||||
|
)
|
||||||
|
]
|
||||||
|
),
|
||||||
|
child: Column(
|
||||||
|
children: [
|
||||||
|
Row(
|
||||||
|
children: [
|
||||||
|
const ImageView(image: PathAssets.iconGoogle, width: 30,),
|
||||||
|
const SizedBox(
|
||||||
|
width: 12,
|
||||||
|
),
|
||||||
|
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
|
||||||
|
),
|
||||||
|
),
|
||||||
|
)
|
||||||
|
],
|
||||||
|
),
|
||||||
|
),
|
||||||
|
Text('${(e.value.totalPercent! * 100).toInt()} %',
|
||||||
|
style: const TextStyle(
|
||||||
|
fontWeight: FontWeight.w700,
|
||||||
|
fontSize: 16,
|
||||||
|
color: ColorPalette.slate800
|
||||||
|
),
|
||||||
|
)
|
||||||
|
],
|
||||||
|
),
|
||||||
|
const Padding(
|
||||||
|
padding: EdgeInsets.symmetric(vertical: 16),
|
||||||
|
child: Divider(height: 1, color: ColorPalette.slate200),
|
||||||
|
),
|
||||||
|
GestureDetector(
|
||||||
|
onTap: () {
|
||||||
|
routePush(context, page: ProductView(selectedProduct: e.value, seeMore: true));
|
||||||
|
},
|
||||||
|
child: const Text('See More',
|
||||||
|
style: TextStyle(
|
||||||
|
color: ColorPalette.slate500,
|
||||||
|
fontWeight: FontWeight.w600,
|
||||||
|
),
|
||||||
|
),
|
||||||
|
)
|
||||||
|
],
|
||||||
|
),
|
||||||
|
);
|
||||||
|
}).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,
|
||||||
|
)
|
||||||
|
],
|
||||||
|
),
|
||||||
|
);
|
||||||
|
}
|
||||||
|
),
|
||||||
|
);
|
||||||
|
}
|
||||||
|
}
|
@@ -0,0 +1,12 @@
|
|||||||
|
import 'package:cims_apps/features/dashboard/dashboard_account/view/product/view_model/product_view_model.dart';
|
||||||
|
import 'package:flutter/material.dart';
|
||||||
|
|
||||||
|
class PlanViewModel extends ChangeNotifier {
|
||||||
|
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();
|
||||||
|
}
|
||||||
|
}
|
@@ -9,9 +9,13 @@ 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/utils/number_formatter.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/product/product_chart_view.dart';
|
import 'package:cims_apps/features/dashboard/dashboard_account/view/product/view/product_chart_view.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: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';
|
||||||
|
|
||||||
class Time {
|
class Time {
|
||||||
int value;
|
int value;
|
||||||
@@ -21,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();
|
||||||
@@ -75,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);
|
||||||
@@ -97,59 +104,109 @@ class _ProductViewState extends State<ProductView> {
|
|||||||
|
|
||||||
@override
|
@override
|
||||||
Widget build(BuildContext context) {
|
Widget build(BuildContext context) {
|
||||||
return Scaffold(
|
return ChangeNotifierProvider(
|
||||||
body: SizedBox(
|
create: (context) => ProductViewModel(),
|
||||||
child: Stack(
|
child: Scaffold(
|
||||||
children: [
|
body: NotificationListener<ScrollNotification>(
|
||||||
const ImageView(image: PathAssets.imgDashboardAccount),
|
onNotification: (notification) {
|
||||||
Column(
|
setState(() {
|
||||||
children: [
|
currentScroll = notification.metrics.pixels;
|
||||||
const SizedBox(
|
});
|
||||||
height: 50,
|
return false;
|
||||||
|
},
|
||||||
|
child: CustomScrollView(
|
||||||
|
slivers: [
|
||||||
|
SliverAppBar(
|
||||||
|
toolbarHeight: 70,
|
||||||
|
expandedHeight: 170,
|
||||||
|
leadingWidth: 0,
|
||||||
|
floating: false,
|
||||||
|
automaticallyImplyLeading: false,
|
||||||
|
title: AnimatedCrossFade(
|
||||||
|
firstChild: Text(
|
||||||
|
widget.selectedProduct.name ?? '',
|
||||||
|
maxLines: 2,
|
||||||
|
overflow: TextOverflow.ellipsis,
|
||||||
|
style: TextStyle(
|
||||||
|
color: Colors.white,
|
||||||
|
fontWeight: FontWeight.w700,
|
||||||
|
fontSize: 18
|
||||||
|
),
|
||||||
|
),
|
||||||
|
secondChild: Padding(
|
||||||
|
padding: const EdgeInsets.only(left: 8),
|
||||||
|
child: BackButtonView(),
|
||||||
|
),
|
||||||
|
crossFadeState: currentScroll >= 85 ? CrossFadeState.showFirst : CrossFadeState.showSecond,
|
||||||
|
duration: Duration(milliseconds: 200)
|
||||||
),
|
),
|
||||||
const Padding(
|
centerTitle: false,
|
||||||
padding: EdgeInsets.symmetric(horizontal: 24),
|
snap: false,
|
||||||
child: Row(
|
pinned: true,
|
||||||
mainAxisAlignment: MainAxisAlignment.spaceBetween,
|
backgroundColor: Color(0xFF1745C8).withOpacity(currentScroll >= 95 ? 1 : currentScroll / 95),
|
||||||
|
surfaceTintColor: ColorPalette.primary,
|
||||||
|
actions: [
|
||||||
|
Wrap(
|
||||||
|
spacing: 12,
|
||||||
children: [
|
children: [
|
||||||
BackButtonView(),
|
Icon(Icons.search_rounded, color: ColorPalette.blue200, size: 32),
|
||||||
Wrap(
|
Icon(Icons.file_download_outlined, color: ColorPalette.blue200, size: 32),
|
||||||
spacing: 12,
|
Icon(Icons.star_outline_rounded, color: ColorPalette.blue200, size: 32)
|
||||||
|
],
|
||||||
|
),
|
||||||
|
SizedBox(width: 24,)
|
||||||
|
],
|
||||||
|
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: [
|
children: [
|
||||||
Icon(Icons.search_rounded, color: ColorPalette.blue200, size: 32),
|
headContainer(),
|
||||||
Icon(Icons.file_download_outlined, color: ColorPalette.blue200, size: 32),
|
const SizedBox(
|
||||||
Icon(Icons.star_outline_rounded, color: ColorPalette.blue200, size: 32)
|
height: 24,
|
||||||
|
),
|
||||||
|
Container(
|
||||||
|
height: 12,
|
||||||
|
decoration: BoxDecoration(
|
||||||
|
color: Colors.white,
|
||||||
|
borderRadius: BorderRadius.only(
|
||||||
|
topLeft: Radius.circular(12),
|
||||||
|
topRight: Radius.circular(12)
|
||||||
|
)
|
||||||
|
),
|
||||||
|
)
|
||||||
],
|
],
|
||||||
)
|
)
|
||||||
],
|
],
|
||||||
),
|
),
|
||||||
),
|
),
|
||||||
const SizedBox(
|
),
|
||||||
height: 24,
|
SliverToBoxAdapter(
|
||||||
),
|
child: contentContainer(),
|
||||||
headContainer(),
|
)
|
||||||
const SizedBox(
|
],
|
||||||
height: 24,
|
),
|
||||||
),
|
|
||||||
Expanded(
|
|
||||||
child: contentContainer()
|
|
||||||
)
|
|
||||||
],
|
|
||||||
)
|
|
||||||
],
|
|
||||||
),
|
|
||||||
),
|
|
||||||
bottomNavigationBar: Container(
|
|
||||||
height: SizeConfig.height * .1,
|
|
||||||
padding: const EdgeInsets.symmetric(horizontal: 24),
|
|
||||||
child: ButtonView(
|
|
||||||
name: 'Buy',
|
|
||||||
onPressed: () {
|
|
||||||
|
|
||||||
},
|
|
||||||
height: SizeConfig.height * 0.06,
|
|
||||||
marginVertical: 16,
|
|
||||||
),
|
),
|
||||||
|
bottomNavigationBar: !widget.seeMore ?
|
||||||
|
Container(
|
||||||
|
height: SizeConfig.height * .1,
|
||||||
|
padding: const EdgeInsets.symmetric(horizontal: 24),
|
||||||
|
child: ButtonView(
|
||||||
|
name: 'Subscribe',
|
||||||
|
onPressed: () {
|
||||||
|
showModalBottomSheet(
|
||||||
|
context: context,
|
||||||
|
isScrollControlled: true,
|
||||||
|
builder: (context) => SelectGoalInvesting(),
|
||||||
|
);
|
||||||
|
},
|
||||||
|
height: SizeConfig.height * 0.06,
|
||||||
|
marginVertical: 16,
|
||||||
|
),
|
||||||
|
) : SizedBox(),
|
||||||
),
|
),
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
@@ -167,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(
|
||||||
@@ -180,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
|
||||||
),
|
),
|
||||||
),
|
),
|
||||||
@@ -207,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,
|
||||||
@@ -581,18 +642,10 @@ class _ProductViewState extends State<ProductView> {
|
|||||||
},
|
},
|
||||||
selectedMachineType
|
selectedMachineType
|
||||||
),
|
),
|
||||||
const Padding(
|
SizedBox(height: 16),
|
||||||
padding: EdgeInsets.only(top: 16, bottom: 8),
|
|
||||||
child: Text(
|
|
||||||
"Today's Investment Estimated Value",
|
|
||||||
style: TextStyle(
|
|
||||||
fontWeight: FontWeight.w600,
|
|
||||||
color: ColorPalette.slate800
|
|
||||||
),
|
|
||||||
),
|
|
||||||
),
|
|
||||||
TextFormView(
|
TextFormView(
|
||||||
name: '',
|
name: "Today's Investment Estimated Value",
|
||||||
|
nameSize: 14,
|
||||||
ctrl: machineController,
|
ctrl: machineController,
|
||||||
keyboardType: TextInputType.number,
|
keyboardType: TextInputType.number,
|
||||||
contentPadding: EdgeInsets.all(12),
|
contentPadding: EdgeInsets.all(12),
|
@@ -0,0 +1,282 @@
|
|||||||
|
import 'dart:ffi';
|
||||||
|
|
||||||
|
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/modal_redirect_app.dart';
|
||||||
|
import 'package:cims_apps/application/component/success_view.dart';
|
||||||
|
import 'package:cims_apps/application/theme/color_palette.dart';
|
||||||
|
import 'package:cims_apps/core/route/route.dart';
|
||||||
|
import 'package:cims_apps/core/utils/number_formatter.dart';
|
||||||
|
import 'package:cims_apps/core/utils/size_config.dart';
|
||||||
|
import 'package:cims_apps/features/bottom_navigation_view.dart';
|
||||||
|
import 'package:flutter/material.dart';
|
||||||
|
import 'package:provider/provider.dart';
|
||||||
|
|
||||||
|
class Payment {
|
||||||
|
String name;
|
||||||
|
int fee;
|
||||||
|
double? discount;
|
||||||
|
|
||||||
|
Payment({required this.name, required this.fee, this.discount = 1});
|
||||||
|
}
|
||||||
|
|
||||||
|
class PaymentMethodView extends StatefulWidget {
|
||||||
|
final int totalInvest;
|
||||||
|
const PaymentMethodView({super.key, required this.totalInvest });
|
||||||
|
|
||||||
|
@override
|
||||||
|
State<PaymentMethodView> createState() => _PaymentMethodViewState();
|
||||||
|
}
|
||||||
|
|
||||||
|
class _PaymentMethodViewState extends State<PaymentMethodView> {
|
||||||
|
int selectedPayment = 0;
|
||||||
|
Payment currentPayment = Payment(name: 'Wallet Pay', fee: 2500);
|
||||||
|
List<Payment> listInstantPayment = [
|
||||||
|
Payment(name: 'Wallet Pay', fee: 2500),
|
||||||
|
Payment(name: 'Link Start', fee: 2500),
|
||||||
|
Payment(name: 'Shopping Pay', fee: 2500, discount: 0.5),
|
||||||
|
Payment(name: 'Fund', fee: 2500, discount: 0.2)
|
||||||
|
];
|
||||||
|
|
||||||
|
List<Payment> listTransferBank = [
|
||||||
|
Payment(name: 'BCA', fee: 2500),
|
||||||
|
Payment(name: 'Bank Republik Indonesia', fee: 2500)
|
||||||
|
];
|
||||||
|
|
||||||
|
@override
|
||||||
|
Widget build(BuildContext context) {
|
||||||
|
|
||||||
|
return Scaffold(
|
||||||
|
appBar: const CustomAppBar(
|
||||||
|
height: 70,
|
||||||
|
title: 'Payment Method'
|
||||||
|
),
|
||||||
|
body: SingleChildScrollView(
|
||||||
|
padding: const EdgeInsets.symmetric(horizontal: 24, vertical: 8),
|
||||||
|
child: Column(
|
||||||
|
children: [
|
||||||
|
segmentTitle(Icons.bolt_rounded, 'Instant Payment'),
|
||||||
|
Wrap(
|
||||||
|
runSpacing: 16,
|
||||||
|
children: listInstantPayment.asMap().entries.map((e) {
|
||||||
|
return cardPayment(e.value, e.key);
|
||||||
|
}).toList(),
|
||||||
|
),
|
||||||
|
const SizedBox(height: 8),
|
||||||
|
segmentTitle(Icons.account_balance_outlined, 'Transfer Bank'),
|
||||||
|
Wrap(
|
||||||
|
runSpacing: 16,
|
||||||
|
children: listTransferBank.asMap().entries.map((e) {
|
||||||
|
return cardPayment(e.value, e.key + (listInstantPayment.length));
|
||||||
|
}).toList(),
|
||||||
|
),
|
||||||
|
SizedBox(height: 16,)
|
||||||
|
],
|
||||||
|
),
|
||||||
|
),
|
||||||
|
bottomNavigationBar: Container(
|
||||||
|
padding: const EdgeInsets.all(24),
|
||||||
|
child: segmentBottom(currentPayment)
|
||||||
|
),
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
Widget segmentTitle(IconData? icon, String title) {
|
||||||
|
return Padding(
|
||||||
|
padding: const EdgeInsets.symmetric(vertical: 16),
|
||||||
|
child: Row(
|
||||||
|
children: [
|
||||||
|
Icon(icon, color: ColorPalette.primary),
|
||||||
|
const SizedBox(width: 8),
|
||||||
|
Text(title,
|
||||||
|
style: const TextStyle(
|
||||||
|
color: ColorPalette.slate800,
|
||||||
|
fontWeight: FontWeight.w600,
|
||||||
|
fontSize: 16
|
||||||
|
),
|
||||||
|
)
|
||||||
|
],
|
||||||
|
),
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
Widget cardPayment(Payment value, int index) {
|
||||||
|
return GestureDetector(
|
||||||
|
onTap: () {
|
||||||
|
setState(() {
|
||||||
|
selectedPayment = index;
|
||||||
|
currentPayment = value;
|
||||||
|
});
|
||||||
|
},
|
||||||
|
child: AnimatedContainer(
|
||||||
|
duration: const Duration(milliseconds: 200),
|
||||||
|
padding: const EdgeInsets.all(16),
|
||||||
|
decoration: BoxDecoration(
|
||||||
|
borderRadius: BorderRadius.circular(14),
|
||||||
|
border: Border.all(color: selectedPayment == index ? ColorPalette.primary : ColorPalette.slate200)
|
||||||
|
),
|
||||||
|
child: Column(
|
||||||
|
children: [
|
||||||
|
Row(
|
||||||
|
mainAxisAlignment: MainAxisAlignment.spaceBetween,
|
||||||
|
children: [
|
||||||
|
Row(
|
||||||
|
children: [
|
||||||
|
Column(
|
||||||
|
crossAxisAlignment: CrossAxisAlignment.start,
|
||||||
|
children: [
|
||||||
|
Text(value.name,
|
||||||
|
style: const TextStyle(
|
||||||
|
fontSize: 16
|
||||||
|
),
|
||||||
|
),
|
||||||
|
RichText(
|
||||||
|
text: TextSpan(
|
||||||
|
text: 'Payment fee ',
|
||||||
|
style: const TextStyle(
|
||||||
|
fontFamily: 'Manrope',
|
||||||
|
color: ColorPalette.slate400,
|
||||||
|
),
|
||||||
|
children: [
|
||||||
|
TextSpan(
|
||||||
|
text: '${NumberFormatter.numberCurrency(value.fee, 'Rp ', 'id_ID', decimalDigits: 0)} ',
|
||||||
|
style: TextStyle(
|
||||||
|
decoration: value.discount != 1 ? TextDecoration.lineThrough : TextDecoration.none,
|
||||||
|
fontFamily: 'Manrope',
|
||||||
|
color: ColorPalette.slate400,
|
||||||
|
),
|
||||||
|
),
|
||||||
|
if(value.discount != 1)...[
|
||||||
|
TextSpan(
|
||||||
|
text: value.discount == 0 ? 'Free' : NumberFormatter.numberCurrency(value.fee * value.discount!, 'Rp ', 'id_ID', decimalDigits: 0),
|
||||||
|
style: const TextStyle(
|
||||||
|
fontFamily: 'Manrope',
|
||||||
|
color: ColorPalette.primary,
|
||||||
|
),
|
||||||
|
)
|
||||||
|
]
|
||||||
|
]
|
||||||
|
)
|
||||||
|
)
|
||||||
|
],
|
||||||
|
)
|
||||||
|
],
|
||||||
|
),
|
||||||
|
AnimatedContainer(
|
||||||
|
duration: const Duration(milliseconds: 200),
|
||||||
|
width: 16,
|
||||||
|
height: 16,
|
||||||
|
alignment: Alignment.center,
|
||||||
|
decoration: BoxDecoration(
|
||||||
|
shape: BoxShape.circle,
|
||||||
|
color: selectedPayment == index ? ColorPalette.primary : Colors.white,
|
||||||
|
border: Border.all(color: selectedPayment == index ? ColorPalette.primary : ColorPalette.slate200, width: 1.5)
|
||||||
|
),
|
||||||
|
child: const Icon(Icons.done_rounded, color: Colors.white, size: 12),
|
||||||
|
)
|
||||||
|
],
|
||||||
|
)
|
||||||
|
],
|
||||||
|
),
|
||||||
|
),
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
Widget segmentBottom(Payment currentPayment) {
|
||||||
|
return Column(
|
||||||
|
mainAxisSize: MainAxisSize.min,
|
||||||
|
children: [
|
||||||
|
rowTotal('Total Invest', widget.totalInvest),
|
||||||
|
rowTotal('Payment Fee', (currentPayment.fee * currentPayment.discount!).toInt()),
|
||||||
|
Row(
|
||||||
|
children: [
|
||||||
|
Expanded(child: Divider(color: ColorPalette.slate200, height: 1,)),
|
||||||
|
Icon(Icons.add, size: 10,)
|
||||||
|
],
|
||||||
|
),
|
||||||
|
rowTotal('Total Payment', widget.totalInvest + (currentPayment.fee * currentPayment.discount!).toInt()),
|
||||||
|
SizedBox(height: 24),
|
||||||
|
ButtonView(
|
||||||
|
name: 'Buy',
|
||||||
|
textSize: 18,
|
||||||
|
marginVertical: 0,
|
||||||
|
width: SizeConfig.width,
|
||||||
|
heightWrapContent: true,
|
||||||
|
contentPadding: EdgeInsets.symmetric(vertical: 16),
|
||||||
|
onPressed: () {
|
||||||
|
List<String> redirect = ['Shopping Pay'];
|
||||||
|
if(redirect.contains(currentPayment.name)){
|
||||||
|
showModalBottomSheet(
|
||||||
|
context: context,
|
||||||
|
builder: (context) {
|
||||||
|
return ModalRedirectApp(value: currentPayment.name);
|
||||||
|
},
|
||||||
|
);
|
||||||
|
}
|
||||||
|
routePush(context, page: SuccessView(
|
||||||
|
img: PathAssets.imgPaymentSuccess,
|
||||||
|
textTitle: 'Payment Success!',
|
||||||
|
subtitle: RichText(
|
||||||
|
text: TextSpan(
|
||||||
|
text: 'Payment With ',
|
||||||
|
style: TextStyle(
|
||||||
|
fontFamily: 'Manrope',
|
||||||
|
fontWeight: FontWeight.w600,
|
||||||
|
fontSize: 16,
|
||||||
|
color: ColorPalette.slate500
|
||||||
|
),
|
||||||
|
children: [
|
||||||
|
TextSpan(
|
||||||
|
text: currentPayment.name,
|
||||||
|
style: TextStyle(
|
||||||
|
fontFamily: 'Manrope',
|
||||||
|
fontWeight: FontWeight.w700,
|
||||||
|
fontSize: 16,
|
||||||
|
color: ColorPalette.slate800
|
||||||
|
)
|
||||||
|
),
|
||||||
|
TextSpan(
|
||||||
|
text: ' successful',
|
||||||
|
style: TextStyle(
|
||||||
|
fontFamily: 'Manrope',
|
||||||
|
fontWeight: FontWeight.w600,
|
||||||
|
fontSize: 16,
|
||||||
|
color: ColorPalette.slate500
|
||||||
|
)
|
||||||
|
)
|
||||||
|
]
|
||||||
|
)
|
||||||
|
),
|
||||||
|
nextRoute: () {
|
||||||
|
routePush(context, page: BottomNavigationView(), routeType: RouteType.pushRemove);
|
||||||
|
},
|
||||||
|
));
|
||||||
|
},
|
||||||
|
)
|
||||||
|
],
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
Widget rowTotal(String title, int value) {
|
||||||
|
return Row(
|
||||||
|
mainAxisAlignment: MainAxisAlignment.spaceBetween,
|
||||||
|
children: [
|
||||||
|
Text(title,
|
||||||
|
style: const TextStyle(
|
||||||
|
fontWeight: FontWeight.w600,
|
||||||
|
color: ColorPalette.slate500,
|
||||||
|
fontSize: 16
|
||||||
|
),
|
||||||
|
),
|
||||||
|
Text(NumberFormatter.numberCurrency(value, 'Rp', 'id_ID', decimalDigits: 0),
|
||||||
|
style: const TextStyle(
|
||||||
|
fontWeight: FontWeight.w700,
|
||||||
|
color: ColorPalette.slate800,
|
||||||
|
fontSize: 16
|
||||||
|
),
|
||||||
|
)
|
||||||
|
],
|
||||||
|
);
|
||||||
|
}
|
||||||
|
}
|
@@ -0,0 +1,110 @@
|
|||||||
|
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/total_payment_view.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:flutter/material.dart';
|
||||||
|
import 'package:provider/provider.dart';
|
||||||
|
|
||||||
|
class SelectGoalInvesting extends StatelessWidget {
|
||||||
|
const SelectGoalInvesting({super.key});
|
||||||
|
|
||||||
|
@override
|
||||||
|
Widget build(BuildContext context) {
|
||||||
|
|
||||||
|
return ChangeNotifierProvider(
|
||||||
|
create: (context) => ProductViewModel(),
|
||||||
|
child: Consumer<ProductViewModel>(
|
||||||
|
builder: (context, provider, child) {
|
||||||
|
return Container(
|
||||||
|
decoration: BoxDecoration(
|
||||||
|
borderRadius: BorderRadius.circular(16)
|
||||||
|
),
|
||||||
|
padding: EdgeInsets.all(24),
|
||||||
|
child: Column(
|
||||||
|
mainAxisSize: MainAxisSize.min,
|
||||||
|
children: [
|
||||||
|
Row(
|
||||||
|
mainAxisAlignment: MainAxisAlignment.spaceBetween,
|
||||||
|
children: [
|
||||||
|
Text('Your Goal in Investing',
|
||||||
|
style: TextStyle(
|
||||||
|
fontWeight: FontWeight.w700,
|
||||||
|
color: ColorPalette.slate800,
|
||||||
|
fontSize: 18
|
||||||
|
),
|
||||||
|
),
|
||||||
|
GestureDetector(
|
||||||
|
onTap: () {
|
||||||
|
Navigator.pop(context);
|
||||||
|
},
|
||||||
|
child: Icon(Icons.close_rounded, color: ColorPalette.slate400)
|
||||||
|
)
|
||||||
|
],
|
||||||
|
),
|
||||||
|
SizedBox(height: 32),
|
||||||
|
GoalInvestingView(
|
||||||
|
onListSelected: (p0) {
|
||||||
|
Navigator.pop(context);
|
||||||
|
showModalBottomSheet(
|
||||||
|
context: context,
|
||||||
|
isScrollControlled: true,
|
||||||
|
builder: (context) {
|
||||||
|
return ChangeNotifierProvider(
|
||||||
|
create: (context) => ProductViewModel(),
|
||||||
|
child: Consumer<ProductViewModel>(
|
||||||
|
builder: (context, provider, child) {
|
||||||
|
return Padding(
|
||||||
|
padding: EdgeInsets.symmetric(vertical: 16),
|
||||||
|
child: InputInvestmentView(
|
||||||
|
currentPlan: p0,
|
||||||
|
changePlan: () {
|
||||||
|
Navigator.pop(context);
|
||||||
|
showModalBottomSheet(
|
||||||
|
context: context,
|
||||||
|
isScrollControlled: true,
|
||||||
|
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,
|
||||||
|
);
|
||||||
|
}
|
||||||
|
),
|
||||||
|
)
|
||||||
|
);
|
||||||
|
},
|
||||||
|
),
|
||||||
|
);
|
||||||
|
}
|
||||||
|
),
|
||||||
|
);
|
||||||
|
},
|
||||||
|
);
|
||||||
|
},
|
||||||
|
)
|
||||||
|
],
|
||||||
|
),
|
||||||
|
);
|
||||||
|
}
|
||||||
|
),
|
||||||
|
);
|
||||||
|
}
|
||||||
|
}
|
@@ -0,0 +1,33 @@
|
|||||||
|
|
||||||
|
import 'package:flutter/material.dart';
|
||||||
|
|
||||||
|
class Product {
|
||||||
|
String? name, type;
|
||||||
|
double? yield;
|
||||||
|
double? priceUnit, funds, totalPercent;
|
||||||
|
|
||||||
|
Product({this.name, this.type, this.yield, this.priceUnit, this.funds, this.totalPercent = 1});
|
||||||
|
}
|
||||||
|
|
||||||
|
class ProductViewModel extends ChangeNotifier {
|
||||||
|
static Product selectedProduct = Product();
|
||||||
|
Product get getSelectedProduct => selectedProduct;
|
||||||
|
|
||||||
|
double totalInvestment = 0;
|
||||||
|
bool isAgree = false;
|
||||||
|
|
||||||
|
void setSelectedProduct(Product product) {
|
||||||
|
selectedProduct = product;
|
||||||
|
notifyListeners();
|
||||||
|
}
|
||||||
|
|
||||||
|
void setTotalInvestment(double value) {
|
||||||
|
totalInvestment = value;
|
||||||
|
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;
|
||||||
|
}
|
||||||
|
}
|