feat: plan view, wip plan view model
This commit is contained in:
parent
3c1f7e210a
commit
0762a8ab0c
BIN
assets/icons/icon-portofolio.png
Normal file
BIN
assets/icons/icon-portofolio.png
Normal file
Binary file not shown.
After Width: | Height: | Size: 1.5 KiB |
BIN
assets/icons/icon-thumb.png
Normal file
BIN
assets/icons/icon-thumb.png
Normal file
Binary file not shown.
After Width: | Height: | Size: 1.6 KiB |
|
@ -37,6 +37,8 @@ class PathAssets {
|
||||||
static const String iconHouse = 'assets/icons/icon-house.png';
|
static const String iconHouse = 'assets/icons/icon-house.png';
|
||||||
static const String iconToga = 'assets/icons/icon-toga.png';
|
static const String iconToga = 'assets/icons/icon-toga.png';
|
||||||
static const String iconCreatePlan = 'assets/icons/icon-create-plan.png';
|
static const String iconCreatePlan = 'assets/icons/icon-create-plan.png';
|
||||||
|
static const String iconThumb = 'assets/icons/icon-thumb.png';
|
||||||
|
static const String iconPortofolio = 'assets/icons/icon-portofolio.png';
|
||||||
|
|
||||||
/// IMAGE
|
/// IMAGE
|
||||||
static const String imgSplashLogo = 'assets/images/splash-logo.png';
|
static const String imgSplashLogo = 'assets/images/splash-logo.png';
|
||||||
|
|
|
@ -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
|
||||||
|
|
|
@ -11,7 +11,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) {
|
||||||
|
@ -28,6 +29,9 @@ 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: () {
|
||||||
|
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)
|
||||||
|
|
|
@ -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: [
|
||||||
|
@ -100,9 +112,14 @@ class NumericPad extends StatelessWidget {
|
||||||
|
|
||||||
Widget removeWidget() {
|
Widget removeWidget() {
|
||||||
return Expanded(
|
return Expanded(
|
||||||
child: Icon(
|
child: GestureDetector(
|
||||||
Icons.highlight_remove,
|
onTap: () {
|
||||||
size: 28,
|
onNumberSelected('');
|
||||||
|
},
|
||||||
|
child: Icon(
|
||||||
|
Icons.highlight_remove,
|
||||||
|
size: 28,
|
||||||
|
),
|
||||||
)
|
)
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
212
lib/application/component/risk_profile.dart
Normal file
212
lib/application/component/risk_profile.dart
Normal file
|
@ -0,0 +1,212 @@
|
||||||
|
import 'package:cims_apps/application/assets/path_assets.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: EdgeInsets.all(24),
|
||||||
|
child: Column(
|
||||||
|
crossAxisAlignment: CrossAxisAlignment.start,
|
||||||
|
children: [
|
||||||
|
Text(
|
||||||
|
riskProfile.type,
|
||||||
|
style: TextStyle(
|
||||||
|
fontWeight: FontWeight.bold,
|
||||||
|
fontSize: 24,
|
||||||
|
color: ColorPalette.white
|
||||||
|
),
|
||||||
|
),
|
||||||
|
SizedBox(height: 16,),
|
||||||
|
Text('Total Score :',
|
||||||
|
style: TextStyle(
|
||||||
|
fontWeight: FontWeight.bold,
|
||||||
|
fontSize: 16,
|
||||||
|
color: ColorPalette.white
|
||||||
|
),
|
||||||
|
),
|
||||||
|
Text('$totalScore',
|
||||||
|
style: TextStyle(
|
||||||
|
fontWeight: FontWeight.bold,
|
||||||
|
fontSize: 28,
|
||||||
|
color: ColorPalette.white
|
||||||
|
),
|
||||||
|
)
|
||||||
|
],
|
||||||
|
),
|
||||||
|
),
|
||||||
|
],
|
||||||
|
),
|
||||||
|
),
|
||||||
|
),
|
||||||
|
SizedBox(
|
||||||
|
height: 24,
|
||||||
|
),
|
||||||
|
Text(
|
||||||
|
riskProfile.desc,
|
||||||
|
style: TextStyle(
|
||||||
|
color: ColorPalette.slate500,
|
||||||
|
fontSize: 16
|
||||||
|
)
|
||||||
|
),
|
||||||
|
SizedBox(
|
||||||
|
height: 24,
|
||||||
|
),
|
||||||
|
Text(
|
||||||
|
'Suitable Product',
|
||||||
|
style: TextStyle(
|
||||||
|
color: ColorPalette.slate800,
|
||||||
|
fontWeight: FontWeight.bold,
|
||||||
|
fontSize: 18
|
||||||
|
),
|
||||||
|
),
|
||||||
|
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: EdgeInsets.all(16),
|
||||||
|
decoration: BoxDecoration(
|
||||||
|
border: Border.all(color: ColorPalette.slate200),
|
||||||
|
borderRadius: BorderRadius.circular(6)
|
||||||
|
),
|
||||||
|
child: Column(
|
||||||
|
crossAxisAlignment: CrossAxisAlignment.start,
|
||||||
|
children: [
|
||||||
|
Container(
|
||||||
|
padding: 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)
|
||||||
|
),
|
||||||
|
SizedBox(
|
||||||
|
height: 12,
|
||||||
|
),
|
||||||
|
Text(e.value['desc'],
|
||||||
|
style: TextStyle(
|
||||||
|
fontSize: 16,
|
||||||
|
fontWeight: FontWeight.bold,
|
||||||
|
color: ColorPalette.slate800
|
||||||
|
),
|
||||||
|
)
|
||||||
|
],
|
||||||
|
),
|
||||||
|
)
|
||||||
|
);
|
||||||
|
}).toList(),
|
||||||
|
)
|
||||||
|
: Wrap(
|
||||||
|
runSpacing: 16,
|
||||||
|
children: riskProfile.suitableProduct.map((e) {
|
||||||
|
return Container(
|
||||||
|
padding: EdgeInsets.all(16),
|
||||||
|
decoration: BoxDecoration(
|
||||||
|
borderRadius: BorderRadius.circular(6),
|
||||||
|
border: Border.all(color: ColorPalette.slate200),
|
||||||
|
),
|
||||||
|
child: Row(
|
||||||
|
children: [
|
||||||
|
Container(
|
||||||
|
padding: 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)
|
||||||
|
),
|
||||||
|
SizedBox(
|
||||||
|
width: 12,
|
||||||
|
),
|
||||||
|
Expanded(
|
||||||
|
child: Text(e['desc'],
|
||||||
|
style: TextStyle(
|
||||||
|
fontSize: 18,
|
||||||
|
fontWeight: FontWeight.bold,
|
||||||
|
color: ColorPalette.slate800
|
||||||
|
),
|
||||||
|
),
|
||||||
|
)
|
||||||
|
],
|
||||||
|
),
|
||||||
|
);
|
||||||
|
}).toList(),
|
||||||
|
)
|
||||||
|
],
|
||||||
|
);
|
||||||
|
}
|
||||||
|
}
|
|
@ -22,7 +22,7 @@ class RiskProfileView extends StatelessWidget {
|
||||||
title: Row(
|
title: Row(
|
||||||
mainAxisAlignment: MainAxisAlignment.spaceBetween,
|
mainAxisAlignment: MainAxisAlignment.spaceBetween,
|
||||||
children: [
|
children: [
|
||||||
BackButtonView(),
|
const BackButtonView(),
|
||||||
const Text('Risk Profile', textAlign: TextAlign.center),
|
const Text('Risk Profile', textAlign: TextAlign.center),
|
||||||
SizedBox(width: SizeConfig.width * 0.1)
|
SizedBox(width: SizeConfig.width * 0.1)
|
||||||
],
|
],
|
||||||
|
@ -33,11 +33,11 @@ class RiskProfileView extends StatelessWidget {
|
||||||
body: Container(
|
body: Container(
|
||||||
width: SizeConfig.width,
|
width: SizeConfig.width,
|
||||||
height: SizeConfig.height,
|
height: SizeConfig.height,
|
||||||
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(
|
||||||
|
@ -66,7 +66,7 @@ class RiskProfileView extends StatelessWidget {
|
||||||
),
|
),
|
||||||
Column(
|
Column(
|
||||||
children: [
|
children: [
|
||||||
Row(
|
const Row(
|
||||||
mainAxisAlignment: MainAxisAlignment.center,
|
mainAxisAlignment: MainAxisAlignment.center,
|
||||||
children: [
|
children: [
|
||||||
ImageView(
|
ImageView(
|
||||||
|
@ -86,13 +86,13 @@ class RiskProfileView extends StatelessWidget {
|
||||||
)
|
)
|
||||||
],
|
],
|
||||||
),
|
),
|
||||||
SizedBox(
|
const SizedBox(
|
||||||
height: 24,
|
height: 24,
|
||||||
),
|
),
|
||||||
ButtonView(
|
ButtonView(
|
||||||
name: "Let's Start",
|
name: "Let's Start",
|
||||||
onPressed: () {
|
onPressed: () {
|
||||||
routePush(context, page: QuestionView());
|
routePush(context, page: const QuestionView());
|
||||||
},
|
},
|
||||||
marginVertical: 0,
|
marginVertical: 0,
|
||||||
)
|
)
|
||||||
|
|
|
@ -1,8 +1,10 @@
|
||||||
import 'package:cims_apps/application/theme/color_palette.dart';
|
import 'package:cims_apps/application/theme/color_palette.dart';
|
||||||
import 'package:cims_apps/features/dashboard/dashboard_account/view/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/plan/view_model/plan_view_model.dart';
|
||||||
import 'package:cims_apps/features/dashboard/dashboard_account/view/portfolio/portfolio_view.dart';
|
import 'package:cims_apps/features/dashboard/dashboard_account/view/portfolio/portfolio_view.dart';
|
||||||
import 'package:flutter/material.dart';
|
import 'package:flutter/material.dart';
|
||||||
|
import 'package:provider/provider.dart';
|
||||||
|
|
||||||
class BottomNavigationView extends StatefulWidget {
|
class BottomNavigationView extends StatefulWidget {
|
||||||
const BottomNavigationView({Key? key}) : super(key: key);
|
const BottomNavigationView({Key? key}) : super(key: key);
|
||||||
|
@ -48,25 +50,28 @@ class _BottomNavigationViewState extends State<BottomNavigationView> {
|
||||||
),
|
),
|
||||||
];
|
];
|
||||||
|
|
||||||
return Scaffold(
|
return ChangeNotifierProvider(
|
||||||
body: listWidget[_selectedIndex],
|
create: (context) => PlanViewModel(),
|
||||||
bottomNavigationBar: Padding(
|
child: Scaffold(
|
||||||
padding: const EdgeInsets.symmetric(vertical: 12),
|
body: listWidget[_selectedIndex],
|
||||||
child: BottomNavigationBar(
|
bottomNavigationBar: Padding(
|
||||||
elevation: 0,
|
padding: const EdgeInsets.symmetric(vertical: 12),
|
||||||
onTap: (value) {
|
child: BottomNavigationBar(
|
||||||
setState(() {
|
elevation: 0,
|
||||||
_selectedIndex = value;
|
onTap: (value) {
|
||||||
});
|
setState(() {
|
||||||
},
|
_selectedIndex = value;
|
||||||
currentIndex: _selectedIndex,
|
});
|
||||||
items: listNavigation,
|
},
|
||||||
type: BottomNavigationBarType.fixed,
|
currentIndex: _selectedIndex,
|
||||||
showUnselectedLabels: true,
|
items: listNavigation,
|
||||||
selectedItemColor: ColorPalette.primary,
|
type: BottomNavigationBarType.fixed,
|
||||||
unselectedItemColor: Colors.black,
|
showUnselectedLabels: true,
|
||||||
selectedLabelStyle: const TextStyle(color: ColorPalette.primary),
|
selectedItemColor: ColorPalette.primary,
|
||||||
unselectedLabelStyle: const TextStyle(color: Colors.black),
|
unselectedItemColor: Colors.black,
|
||||||
|
selectedLabelStyle: const TextStyle(color: ColorPalette.primary),
|
||||||
|
unselectedLabelStyle: const TextStyle(color: Colors.black),
|
||||||
|
),
|
||||||
),
|
),
|
||||||
),
|
),
|
||||||
);
|
);
|
||||||
|
|
|
@ -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,206 @@
|
||||||
|
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/goal_investing_view.dart';
|
||||||
|
import 'package:cims_apps/application/component/numeric_pad/numeric_pad.dart';
|
||||||
|
import 'package:cims_apps/application/component/risk_profile.dart';
|
||||||
|
import 'package:cims_apps/application/component/text_form/text_form_view.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/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 dispose() {
|
||||||
|
// TODO: implement dispose
|
||||||
|
super.dispose();
|
||||||
|
inputController.dispose();
|
||||||
|
}
|
||||||
|
|
||||||
|
@override
|
||||||
|
Widget build(BuildContext context) {
|
||||||
|
|
||||||
|
return Scaffold(
|
||||||
|
appBar: CustomAppBar(height: 70, title: 'Investment Plan'),
|
||||||
|
body: SingleChildScrollView(
|
||||||
|
padding: EdgeInsets.all(24),
|
||||||
|
child: Column(
|
||||||
|
crossAxisAlignment: CrossAxisAlignment.start,
|
||||||
|
children: [
|
||||||
|
RiskProfile(
|
||||||
|
totalScore: 26,
|
||||||
|
rowSuitableProduct: true
|
||||||
|
),
|
||||||
|
SizedBox(
|
||||||
|
height: 32,
|
||||||
|
),
|
||||||
|
Text('Your Goal in Investing',
|
||||||
|
style: TextStyle(
|
||||||
|
fontWeight: FontWeight.w700,
|
||||||
|
color: ColorPalette.slate800,
|
||||||
|
fontSize: 18
|
||||||
|
),
|
||||||
|
),
|
||||||
|
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: [
|
||||||
|
Text("It's time to invest",
|
||||||
|
style: TextStyle(
|
||||||
|
fontSize: 16,
|
||||||
|
fontWeight: FontWeight.w600
|
||||||
|
),
|
||||||
|
),
|
||||||
|
GestureDetector(
|
||||||
|
onTap: () {
|
||||||
|
Navigator.pop(context);
|
||||||
|
},
|
||||||
|
child: Icon(Icons.close_rounded)
|
||||||
|
)
|
||||||
|
],
|
||||||
|
),
|
||||||
|
),
|
||||||
|
Divider(color: ColorPalette.slate200, height: 1),
|
||||||
|
Padding(
|
||||||
|
padding: EdgeInsets.symmetric(horizontal: 24, vertical: 12),
|
||||||
|
child: Column(
|
||||||
|
crossAxisAlignment: CrossAxisAlignment.start,
|
||||||
|
children: [
|
||||||
|
Row(
|
||||||
|
mainAxisAlignment: MainAxisAlignment.spaceBetween,
|
||||||
|
children: [
|
||||||
|
Text(text,
|
||||||
|
style: TextStyle(
|
||||||
|
fontSize: 20,
|
||||||
|
fontWeight: FontWeight.w700,
|
||||||
|
|
||||||
|
),
|
||||||
|
),
|
||||||
|
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: TextStyle(
|
||||||
|
fontSize: 28,
|
||||||
|
fontWeight: FontWeight.w600,
|
||||||
|
color: ColorPalette.slate800
|
||||||
|
),
|
||||||
|
keyboardType: TextInputType.number,
|
||||||
|
onChanged: (value) {
|
||||||
|
value = value.replaceAll('Rp ', '').replaceAll('.', '');
|
||||||
|
double parseValue = double.parse(value);
|
||||||
|
if(value.isNotEmpty){
|
||||||
|
inputController.text = NumberFormatter.numberCurrency(parseValue, 'Rp ', 'id_ID', decimalDigits: 0);
|
||||||
|
}else{
|
||||||
|
inputController.text = NumberFormatter.numberCurrency(0, 'Rp ', 'id_ID', decimalDigits: 0);
|
||||||
|
}
|
||||||
|
},
|
||||||
|
decoration: InputDecoration(
|
||||||
|
enabledBorder: UnderlineInputBorder(
|
||||||
|
borderSide: BorderSide(
|
||||||
|
color: ColorPalette.primary,
|
||||||
|
width: 2
|
||||||
|
),
|
||||||
|
)
|
||||||
|
),
|
||||||
|
),
|
||||||
|
SizedBox(height: 12),
|
||||||
|
Text('Minimum Budget Rp1,000,000',
|
||||||
|
style: TextStyle(
|
||||||
|
color: ColorPalette.slate400,
|
||||||
|
fontSize: 16,
|
||||||
|
fontWeight: FontWeight.w600
|
||||||
|
),
|
||||||
|
),
|
||||||
|
SizedBox(height: 16),
|
||||||
|
NumericPad(onNumberSelected: (p0) {
|
||||||
|
String checkIsZeroInput = inputController.text.replaceAll('Rp ', '').replaceAll(',', '');
|
||||||
|
String getNumeric = p0;
|
||||||
|
if(p0.isNotEmpty){
|
||||||
|
if(checkIsZeroInput != '0'){
|
||||||
|
getNumeric = checkIsZeroInput + getNumeric;
|
||||||
|
}
|
||||||
|
}else{
|
||||||
|
getNumeric = checkIsZeroInput.substring(0, checkIsZeroInput.length - 1);
|
||||||
|
}
|
||||||
|
String formatNumeric = NumberFormatter.numberCurrency(
|
||||||
|
double.parse(getNumeric), 'Rp ', 'id_ID', decimalDigits: 0).replaceAll('.', ',');
|
||||||
|
inputController.text = formatNumeric;
|
||||||
|
}),
|
||||||
|
SizedBox(height: 8),
|
||||||
|
ButtonView(
|
||||||
|
name: 'Next',
|
||||||
|
onPressed: () {
|
||||||
|
Navigator.pop(context);
|
||||||
|
int formatIntParse = int.parse(inputController.text.replaceAll('Rp ', '').replaceAll(',', ''));
|
||||||
|
showModalBottomSheet(context: context, builder: (context) => OptionsStartingInvest(totalInvest: formatIntParse));
|
||||||
|
},
|
||||||
|
width: SizeConfig.width,
|
||||||
|
heightWrapContent: true,
|
||||||
|
contentPadding: EdgeInsets.symmetric(vertical: 16),
|
||||||
|
marginVertical: 0,
|
||||||
|
)
|
||||||
|
],
|
||||||
|
),
|
||||||
|
),
|
||||||
|
],
|
||||||
|
),
|
||||||
|
);
|
||||||
|
}
|
||||||
|
}
|
|
@ -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,154 @@
|
||||||
|
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/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/result_total_product.dart';
|
||||||
|
import 'package:flutter/material.dart';
|
||||||
|
|
||||||
|
class Product {
|
||||||
|
String name, type;
|
||||||
|
double totalPercent;
|
||||||
|
|
||||||
|
Product(this.name, this.type, this.totalPercent);
|
||||||
|
}
|
||||||
|
class ResultOptionsProduct extends StatelessWidget {
|
||||||
|
final int totalInvest;
|
||||||
|
const ResultOptionsProduct({super.key, required this.totalInvest});
|
||||||
|
|
||||||
|
@override
|
||||||
|
Widget build(BuildContext context) {
|
||||||
|
List<Product> listProduct = [
|
||||||
|
Product('Gemilang Dana Kas Maxima', 'Money Market', 0.7),
|
||||||
|
Product('Gemilang Dana Likuid', 'Bonds', 0.2),
|
||||||
|
Product('Gemilang Kas 2 Kelas A', 'Shares', 0.1)
|
||||||
|
];
|
||||||
|
|
||||||
|
return Container(
|
||||||
|
decoration: BoxDecoration(
|
||||||
|
color: Colors.white,
|
||||||
|
borderRadius: BorderRadius.circular(16)
|
||||||
|
),
|
||||||
|
padding: const EdgeInsets.all(24),
|
||||||
|
child: Column(
|
||||||
|
mainAxisSize: MainAxisSize.min,
|
||||||
|
children: [
|
||||||
|
const Row(
|
||||||
|
mainAxisAlignment: MainAxisAlignment.spaceBetween,
|
||||||
|
children: [
|
||||||
|
Icon(Icons.arrow_back, color: ColorPalette.slate500),
|
||||||
|
Text('Results from your risk profile',
|
||||||
|
style: TextStyle(
|
||||||
|
fontWeight: FontWeight.w600,
|
||||||
|
fontSize: 18,
|
||||||
|
color: ColorPalette.slate800
|
||||||
|
),
|
||||||
|
),
|
||||||
|
const 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
|
||||||
|
),
|
||||||
|
),
|
||||||
|
)
|
||||||
|
],
|
||||||
|
),
|
||||||
|
),
|
||||||
|
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: () {
|
||||||
|
},
|
||||||
|
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) => ResultTotalProduct(listProduct: listProduct, totalInvest: totalInvest)
|
||||||
|
);
|
||||||
|
},
|
||||||
|
width: SizeConfig.width,
|
||||||
|
heightWrapContent: true,
|
||||||
|
contentPadding: const EdgeInsets.symmetric(vertical: 16),
|
||||||
|
marginVertical: 0,
|
||||||
|
)
|
||||||
|
],
|
||||||
|
),
|
||||||
|
);
|
||||||
|
}
|
||||||
|
}
|
|
@ -0,0 +1,221 @@
|
||||||
|
import 'package:cims_apps/application/component/button/button_view.dart';
|
||||||
|
import 'package:cims_apps/application/theme/color_palette.dart';
|
||||||
|
import 'package:cims_apps/core/utils/number_formatter.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 ResultTotalProduct extends StatelessWidget {
|
||||||
|
final int totalInvest;
|
||||||
|
final List<Product> listProduct;
|
||||||
|
const ResultTotalProduct({super.key, required this.listProduct, required this.totalInvest});
|
||||||
|
|
||||||
|
@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.all(24.0),
|
||||||
|
child: Row(
|
||||||
|
mainAxisAlignment: MainAxisAlignment.spaceBetween,
|
||||||
|
children: [
|
||||||
|
Text('Your Investment Today',
|
||||||
|
style: TextStyle(
|
||||||
|
color: ColorPalette.slate800,
|
||||||
|
fontWeight: FontWeight.w600,
|
||||||
|
fontSize: 16
|
||||||
|
),
|
||||||
|
),
|
||||||
|
GestureDetector(
|
||||||
|
onTap: () => Navigator.pop(context),
|
||||||
|
child: Icon(Icons.close_rounded)
|
||||||
|
)
|
||||||
|
],
|
||||||
|
),
|
||||||
|
),
|
||||||
|
...listProduct.asMap().entries.map((e) {
|
||||||
|
return Container(
|
||||||
|
padding: EdgeInsets.only(left: 16, right: 24, bottom: 16, top: 16),
|
||||||
|
decoration: BoxDecoration(
|
||||||
|
border: Border(
|
||||||
|
left: BorderSide(
|
||||||
|
color: ColorPalette.investTypeColor[e.value.type]!,
|
||||||
|
width: 8,
|
||||||
|
)
|
||||||
|
)
|
||||||
|
),
|
||||||
|
child: Row(
|
||||||
|
mainAxisAlignment: MainAxisAlignment.spaceBetween,
|
||||||
|
children: [
|
||||||
|
Expanded(
|
||||||
|
flex: 5,
|
||||||
|
child: Text(e.value.name,
|
||||||
|
style: 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: TextStyle(
|
||||||
|
fontWeight: FontWeight.w700,
|
||||||
|
fontSize: 18,
|
||||||
|
color: ColorPalette.slate800
|
||||||
|
),
|
||||||
|
)
|
||||||
|
)
|
||||||
|
],
|
||||||
|
),
|
||||||
|
);
|
||||||
|
}).toList(),
|
||||||
|
SizedBox(height: 16),
|
||||||
|
Padding(
|
||||||
|
padding: const 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
|
||||||
|
),
|
||||||
|
)
|
||||||
|
],
|
||||||
|
),
|
||||||
|
),
|
||||||
|
SizedBox(height: 16,),
|
||||||
|
Container(
|
||||||
|
color: ColorPalette.slate200.withOpacity(0.5),
|
||||||
|
padding: const EdgeInsets.symmetric(horizontal: 24, vertical: 16),
|
||||||
|
child: Row(
|
||||||
|
mainAxisAlignment: MainAxisAlignment.spaceBetween,
|
||||||
|
children: [
|
||||||
|
Text('Total',
|
||||||
|
style: TextStyle(
|
||||||
|
color: ColorPalette.slate400,
|
||||||
|
fontWeight: FontWeight.w600,
|
||||||
|
fontSize: 16
|
||||||
|
),
|
||||||
|
),
|
||||||
|
Text(NumberFormatter.numberCurrency(totalInvest, 'Rp ', 'id_ID'),
|
||||||
|
textAlign: TextAlign.end,
|
||||||
|
style: TextStyle(
|
||||||
|
fontWeight: FontWeight.w700,
|
||||||
|
fontSize: 18,
|
||||||
|
color: ColorPalette.slate800
|
||||||
|
),
|
||||||
|
)
|
||||||
|
],
|
||||||
|
),
|
||||||
|
),
|
||||||
|
buttonAgreement(),
|
||||||
|
Container(
|
||||||
|
padding: const EdgeInsets.symmetric(horizontal: 24, vertical: 16),
|
||||||
|
child: Row(
|
||||||
|
mainAxisAlignment: MainAxisAlignment.spaceBetween,
|
||||||
|
children: [
|
||||||
|
Text('Total Payment',
|
||||||
|
style: TextStyle(
|
||||||
|
color: ColorPalette.slate400,
|
||||||
|
fontWeight: FontWeight.w600,
|
||||||
|
fontSize: 16
|
||||||
|
),
|
||||||
|
),
|
||||||
|
Text(NumberFormatter.numberCurrency(totalInvest, 'Rp ', 'id_ID'),
|
||||||
|
textAlign: TextAlign.end,
|
||||||
|
style: TextStyle(
|
||||||
|
fontWeight: FontWeight.w700,
|
||||||
|
fontSize: 18,
|
||||||
|
color: ColorPalette.slate800
|
||||||
|
),
|
||||||
|
)
|
||||||
|
],
|
||||||
|
),
|
||||||
|
),
|
||||||
|
ButtonView(
|
||||||
|
disabled: true,
|
||||||
|
name: 'Subscribe Now',
|
||||||
|
onPressed: () {
|
||||||
|
|
||||||
|
},
|
||||||
|
disabledBgColor: ColorPalette.slate200.withOpacity(0.5),
|
||||||
|
textColor: 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: [
|
||||||
|
SizedBox(
|
||||||
|
height: 24,
|
||||||
|
width: 24,
|
||||||
|
child: Radio(
|
||||||
|
value: false,
|
||||||
|
groupValue: false,
|
||||||
|
onChanged: (value) {
|
||||||
|
|
||||||
|
},
|
||||||
|
activeColor: ColorPalette.primary,
|
||||||
|
),
|
||||||
|
),
|
||||||
|
SizedBox(width: 12,),
|
||||||
|
Expanded(
|
||||||
|
child: Column(
|
||||||
|
crossAxisAlignment: CrossAxisAlignment.start,
|
||||||
|
children: [
|
||||||
|
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: Text('Read More',
|
||||||
|
style: TextStyle(
|
||||||
|
fontSize: 16,
|
||||||
|
fontWeight: FontWeight.w600,
|
||||||
|
decoration: TextDecoration.underline,
|
||||||
|
color: ColorPalette.primary
|
||||||
|
),
|
||||||
|
)
|
||||||
|
)
|
||||||
|
],
|
||||||
|
)
|
||||||
|
)
|
||||||
|
],
|
||||||
|
),
|
||||||
|
);
|
||||||
|
}
|
||||||
|
}
|
|
@ -0,0 +1,11 @@
|
||||||
|
|
||||||
|
import 'package:flutter/material.dart';
|
||||||
|
|
||||||
|
class PlanViewModel extends ChangeNotifier {
|
||||||
|
bool isAgreement = false;
|
||||||
|
|
||||||
|
void setAgreement() {
|
||||||
|
isAgreement = !isAgreement;
|
||||||
|
notifyListeners();
|
||||||
|
}
|
||||||
|
}
|
Loading…
Reference in New Issue
Block a user