Compare commits
14 Commits
fdca27233b
...
c4c0479341
Author | SHA1 | Date | |
---|---|---|---|
c4c0479341 | |||
e510aaefd7 | |||
dfb947dce5 | |||
9761dc369c | |||
9e2304990c | |||
8b1b3e950f | |||
aa987fe320 | |||
ad6195061d | |||
b5a382ce96 | |||
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-cart.png
Normal file
After Width: | Height: | Size: 1.8 KiB |
BIN
assets/icons/icon-gadget.png
Normal file
After Width: | Height: | Size: 1.4 KiB |
BIN
assets/icons/icon-market.png
Normal file
After Width: | Height: | Size: 1.4 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-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-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,15 @@ class PathAssets {
|
|||
static const String iconChecklistOutlined =
|
||||
'assets/icons/icon-ceklis-outline.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';
|
||||
|
||||
/// IMAGE
|
||||
static const String imgSplashLogo = 'assets/images/splash-logo.png';
|
||||
|
@ -73,6 +82,8 @@ class PathAssets {
|
|||
static const String imgGuideBank = 'assets/images/img-guide-bank.png';
|
||||
static const String imgGuide1 = 'assets/images/img-guide1.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 imgFinish = 'assets/images/img-finish.png';
|
||||
}
|
||||
|
|
|
@ -9,7 +9,7 @@ class ButtonView extends StatelessWidget {
|
|||
final double? height, width, widthSuffix, widthPrefix, marginVertical;
|
||||
final EdgeInsetsGeometry? contentPadding;
|
||||
final bool isSecondaryColor, isOutlined, heightWrapContent, disabled;
|
||||
final Color? backgroundColor, textColor, borderColor;
|
||||
final Color? backgroundColor, textColor, borderColor, disabledBgColor;
|
||||
final MainAxisAlignment? mainAxisAlignmentContent;
|
||||
// final _widthBtn = SizeConfig.screenWidth / 1.5;
|
||||
final _widthBtn = SizeConfig.width * .9;
|
||||
|
@ -34,6 +34,7 @@ class ButtonView extends StatelessWidget {
|
|||
this.backgroundColor,
|
||||
this.borderColor,
|
||||
this.textColor,
|
||||
this.disabledBgColor,
|
||||
this.textWeight = FontWeight.bold,
|
||||
this.textSize,
|
||||
this.textAlign = TextAlign.center,
|
||||
|
@ -65,7 +66,7 @@ class ButtonView extends StatelessWidget {
|
|||
height: heightWrapContent ? null : height ?? _heightBtn,
|
||||
child: ElevatedButton(
|
||||
style: ElevatedButton.styleFrom(
|
||||
disabledBackgroundColor: isOutlined ? Colors.white : color.surface,
|
||||
disabledBackgroundColor: disabledBgColor ?? (isOutlined ? Colors.white : color.surface),
|
||||
padding: contentPadding,
|
||||
backgroundColor: backgroundColor ??
|
||||
(isOutlined
|
||||
|
|
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),
|
||||
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(
|
||||
mainAxisAlignment: MainAxisAlignment.spaceEvenly,
|
||||
crossAxisAlignment: CrossAxisAlignment.center,
|
||||
|
@ -54,7 +66,7 @@ class NumericPad extends StatelessWidget {
|
|||
Widget dividerGradient(bool isHorizontal, AlignmentGeometry gradientFrom, AlignmentGeometry gradientTo, {bool fullColor = false}) {
|
||||
return Container(
|
||||
width: isHorizontal ? SizeConfig.width : 1,
|
||||
height: isHorizontal ? 1 : SizeConfig.height * 0.11,
|
||||
height: isHorizontal ? 1 : SizeConfig.height * 0.097,
|
||||
decoration: BoxDecoration(
|
||||
gradient: LinearGradient(
|
||||
colors: [
|
||||
|
@ -100,9 +112,14 @@ class NumericPad extends StatelessWidget {
|
|||
|
||||
Widget removeWidget() {
|
||||
return Expanded(
|
||||
child: Icon(
|
||||
Icons.highlight_remove,
|
||||
size: 28,
|
||||
child: GestureDetector(
|
||||
onTap: () {
|
||||
onNumberSelected('');
|
||||
},
|
||||
child: Icon(
|
||||
Icons.highlight_remove,
|
||||
size: 28,
|
||||
),
|
||||
)
|
||||
);
|
||||
}
|
||||
|
|
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(),
|
||||
)
|
||||
],
|
||||
);
|
||||
}
|
||||
}
|
|
@ -1,5 +1,7 @@
|
|||
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/core/route/route.dart';
|
||||
import 'package:cims_apps/core/utils/size_config.dart';
|
||||
import 'package:flutter/material.dart';
|
||||
|
||||
|
@ -11,7 +13,8 @@ class GoalInvest {
|
|||
}
|
||||
|
||||
class GoalInvestingView extends StatelessWidget {
|
||||
const GoalInvestingView({super.key});
|
||||
final void Function(String) onListSelected;
|
||||
const GoalInvestingView({super.key, required this.onListSelected});
|
||||
|
||||
@override
|
||||
Widget build(BuildContext context) {
|
||||
|
@ -19,7 +22,7 @@ class GoalInvestingView extends StatelessWidget {
|
|||
GoalInvest(PathAssets.iconToga, 'Education'),
|
||||
GoalInvest(PathAssets.iconCake, 'Marriage'),
|
||||
GoalInvest(PathAssets.iconHouse, 'Old age days'),
|
||||
GoalInvest(PathAssets.iconCreatePlan, 'Create Plan'),
|
||||
GoalInvest(PathAssets.iconCreatePlan, 'Other Plan'),
|
||||
];
|
||||
|
||||
return Column(
|
||||
|
@ -28,6 +31,20 @@ class GoalInvestingView extends StatelessWidget {
|
|||
return Padding(
|
||||
padding: EdgeInsets.only(top: e.key != 0 ? 16 : 0),
|
||||
child: ListTile(
|
||||
onTap: () {
|
||||
if(e.value.title == 'Other Plan'){
|
||||
routePush(
|
||||
context,
|
||||
page: OtherPlanView(
|
||||
selectedPlan: (value) {
|
||||
onListSelected(e.value.title);
|
||||
},
|
||||
)
|
||||
);
|
||||
}else{
|
||||
onListSelected(e.value.title);
|
||||
}
|
||||
},
|
||||
shape: RoundedRectangleBorder(
|
||||
side: BorderSide(color: ColorPalette.slate200),
|
||||
borderRadius: BorderRadius.circular(14)
|
||||
|
@ -47,10 +64,11 @@ class GoalInvestingView extends StatelessWidget {
|
|||
title: Text(e.value.title,
|
||||
style: TextStyle(
|
||||
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()
|
143
lib/application/component/subscribe/input_investment_view.dart
Normal file
|
@ -0,0 +1,143 @@
|
|||
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 selectedPlan;
|
||||
final void Function(String value) nextMove;
|
||||
const InputInvestmentView({super.key, required this.selectedPlan, required this.nextMove});
|
||||
|
||||
@override
|
||||
State<InputInvestmentView> createState() => _InputInvestmentViewState();
|
||||
}
|
||||
|
||||
class _InputInvestmentViewState extends State<InputInvestmentView> {
|
||||
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 Container(
|
||||
decoration: BoxDecoration(
|
||||
color: Colors.white,
|
||||
borderRadius: BorderRadius.circular(16)
|
||||
),
|
||||
child: Column(
|
||||
mainAxisSize: MainAxisSize.min,
|
||||
children: [
|
||||
SizedBox(height: 16),
|
||||
Padding(
|
||||
padding: EdgeInsets.symmetric(horizontal: 24, vertical: 12),
|
||||
child: Column(
|
||||
crossAxisAlignment: CrossAxisAlignment.start,
|
||||
children: [
|
||||
Row(
|
||||
mainAxisAlignment: MainAxisAlignment.spaceBetween,
|
||||
children: [
|
||||
Text(widget.selectedPlan,
|
||||
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: () {
|
||||
widget.nextMove(inputController.text);
|
||||
},
|
||||
width: SizeConfig.width,
|
||||
heightWrapContent: true,
|
||||
contentPadding: EdgeInsets.symmetric(vertical: 16),
|
||||
marginVertical: 0,
|
||||
)
|
||||
],
|
||||
),
|
||||
),
|
||||
],
|
||||
),
|
||||
);;
|
||||
}
|
||||
}
|
182
lib/application/component/subscribe/other_plan_view.dart
Normal file
|
@ -0,0 +1,182 @@
|
|||
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);
|
||||
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,
|
||||
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);
|
||||
},
|
||||
child: Icon(Icons.close_rounded),
|
||||
)
|
||||
],
|
||||
),
|
||||
TextFormView(
|
||||
name: 'Objective Name',
|
||||
ctrl: createController,
|
||||
),
|
||||
SizedBox(height: 24),
|
||||
ButtonView(
|
||||
name: 'Select',
|
||||
marginVertical: 0,
|
||||
disabled: !(createController.text != ''),
|
||||
onPressed: () {
|
||||
Navigator.of(context)..pop()..pop();
|
||||
widget.selectedPlan(selectedPlan.name);
|
||||
},
|
||||
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/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 StatefulWidget {
|
||||
final int totalInvest;
|
||||
final List<Product> listProduct;
|
||||
const TotalPaymentView({
|
||||
super.key,
|
||||
required this.listProduct,
|
||||
required this.totalInvest,
|
||||
});
|
||||
|
||||
@override
|
||||
State<TotalPaymentView> createState() => _TotalPaymentViewState();
|
||||
}
|
||||
|
||||
class _TotalPaymentViewState extends State<TotalPaymentView> {
|
||||
bool isAgreement = false;
|
||||
|
||||
@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))
|
||||
],
|
||||
),
|
||||
),
|
||||
...widget.listProduct.asMap().entries.map((e) {
|
||||
return Container(
|
||||
padding: const EdgeInsets.only(
|
||||
left: 16, right: 24, bottom: 16, top: 16),
|
||||
decoration: BoxDecoration(
|
||||
border: Border(
|
||||
left: BorderSide(
|
||||
width: 8,
|
||||
color:
|
||||
ColorPalette.investTypeColor[e.value.type]!))),
|
||||
child: Row(
|
||||
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(
|
||||
widget.totalInvest * e.value.totalPercent!,
|
||||
'Rp ',
|
||||
'id_ID'),
|
||||
textAlign: TextAlign.end,
|
||||
style: const TextStyle(
|
||||
fontWeight: FontWeight.w700,
|
||||
fontSize: 18,
|
||||
color: ColorPalette.slate800),
|
||||
))
|
||||
],
|
||||
),
|
||||
);
|
||||
}).toList(),
|
||||
const SizedBox(height: 16),
|
||||
const Padding(
|
||||
padding: EdgeInsets.symmetric(horizontal: 24),
|
||||
child: Row(
|
||||
mainAxisAlignment: MainAxisAlignment.spaceBetween,
|
||||
children: [
|
||||
Text(
|
||||
'Purchase Commission',
|
||||
style: TextStyle(
|
||||
color: ColorPalette.slate400,
|
||||
fontWeight: FontWeight.w600,
|
||||
fontSize: 16),
|
||||
),
|
||||
Text(
|
||||
'Free',
|
||||
style: TextStyle(
|
||||
color: ColorPalette.primary,
|
||||
fontSize: 18,
|
||||
fontWeight: FontWeight.w700),
|
||||
)
|
||||
],
|
||||
),
|
||||
),
|
||||
const SizedBox(
|
||||
height: 16,
|
||||
),
|
||||
Container(
|
||||
color: ColorPalette.slate200.withOpacity(0.5),
|
||||
padding: const EdgeInsets.symmetric(horizontal: 24, vertical: 16),
|
||||
child: Row(
|
||||
mainAxisAlignment: MainAxisAlignment.spaceBetween,
|
||||
children: [
|
||||
const Text(
|
||||
'Total',
|
||||
style: TextStyle(
|
||||
color: ColorPalette.slate400,
|
||||
fontWeight: FontWeight.w600,
|
||||
fontSize: 16),
|
||||
),
|
||||
Text(
|
||||
NumberFormatter.numberCurrency(
|
||||
widget.totalInvest, 'Rp ', 'id_ID'),
|
||||
textAlign: TextAlign.end,
|
||||
style: const TextStyle(
|
||||
fontWeight: FontWeight.w700,
|
||||
fontSize: 18,
|
||||
color: ColorPalette.slate800),
|
||||
)
|
||||
],
|
||||
),
|
||||
),
|
||||
buttonAgreement(),
|
||||
Container(
|
||||
padding: const EdgeInsets.symmetric(horizontal: 24, vertical: 16),
|
||||
child: Row(
|
||||
mainAxisAlignment: MainAxisAlignment.spaceBetween,
|
||||
children: [
|
||||
const Text(
|
||||
'Total Payment',
|
||||
style: TextStyle(
|
||||
color: ColorPalette.slate400,
|
||||
fontWeight: FontWeight.w600,
|
||||
fontSize: 16),
|
||||
),
|
||||
Text(
|
||||
NumberFormatter.numberCurrency(
|
||||
widget.totalInvest, 'Rp ', 'id_ID'),
|
||||
textAlign: TextAlign.end,
|
||||
style: const TextStyle(
|
||||
fontWeight: FontWeight.w700,
|
||||
fontSize: 18,
|
||||
color: ColorPalette.slate800),
|
||||
)
|
||||
],
|
||||
),
|
||||
),
|
||||
ButtonView(
|
||||
disabled: !isAgreement,
|
||||
name: 'Subscribe Now',
|
||||
onPressed: () {
|
||||
routePush(context,
|
||||
page: PaymentMethodView(
|
||||
totalInvest: widget.totalInvest,
|
||||
));
|
||||
},
|
||||
disabledBgColor: ColorPalette.slate200.withOpacity(0.5),
|
||||
textColor: isAgreement ? Colors.white : ColorPalette.slate400,
|
||||
textWeight: FontWeight.w700,
|
||||
textSize: 20,
|
||||
backgroundColor: ColorPalette.primary,
|
||||
)
|
||||
],
|
||||
),
|
||||
),
|
||||
);
|
||||
}
|
||||
|
||||
Widget buttonAgreement() {
|
||||
bool isAgree = isAgreement;
|
||||
return Padding(
|
||||
padding: const EdgeInsets.symmetric(horizontal: 24, vertical: 16),
|
||||
child: Row(
|
||||
crossAxisAlignment: CrossAxisAlignment.start,
|
||||
children: [
|
||||
GestureDetector(
|
||||
onTap: () {
|
||||
setState(() {
|
||||
isAgreement = !isAgreement;
|
||||
});
|
||||
},
|
||||
child: AnimatedContainer(
|
||||
margin: const EdgeInsets.only(top: 4),
|
||||
duration: const Duration(milliseconds: 200),
|
||||
height: 16,
|
||||
width: 16,
|
||||
padding: const EdgeInsets.all(1),
|
||||
alignment: Alignment.center,
|
||||
decoration: BoxDecoration(
|
||||
shape: BoxShape.circle,
|
||||
border: Border.all(
|
||||
color: isAgree
|
||||
? ColorPalette.primary
|
||||
: ColorPalette.slate200)),
|
||||
child: AnimatedContainer(
|
||||
duration: const Duration(milliseconds: 200),
|
||||
child: Container(
|
||||
decoration: BoxDecoration(
|
||||
color:
|
||||
isAgree ? ColorPalette.primary : ColorPalette.white,
|
||||
shape: BoxShape.circle),
|
||||
),
|
||||
),
|
||||
),
|
||||
),
|
||||
const SizedBox(
|
||||
width: 12,
|
||||
),
|
||||
Expanded(
|
||||
child: Column(
|
||||
crossAxisAlignment: CrossAxisAlignment.start,
|
||||
children: [
|
||||
const Text(
|
||||
'I agree to buy the mutual fund on this page and have read and agreed to all the contents of the Prospectus and summary information and understand the risks of my investment decision.',
|
||||
style: TextStyle(
|
||||
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),
|
||||
),
|
||||
),
|
||||
);
|
||||
}
|
||||
}
|
|
@ -5,6 +5,7 @@ import 'package:remove_emoji_input_formatter/remove_emoji_input_formatter.dart';
|
|||
|
||||
class TextFormView extends StatelessWidget {
|
||||
final String name;
|
||||
final double nameSize;
|
||||
final String? helperText;
|
||||
final String? initialValue;
|
||||
final VoidCallback? onTap;
|
||||
|
@ -40,6 +41,7 @@ class TextFormView extends StatelessWidget {
|
|||
TextFormView(
|
||||
{Key? key,
|
||||
required this.name,
|
||||
this.nameSize = 16,
|
||||
this.helperText,
|
||||
this.onTap,
|
||||
this.fontColorDisabled,
|
||||
|
@ -97,17 +99,17 @@ class TextFormView extends StatelessWidget {
|
|||
children: [
|
||||
Text(
|
||||
name,
|
||||
style: const TextStyle(
|
||||
fontSize: 16,
|
||||
style: TextStyle(
|
||||
fontSize: nameSize,
|
||||
fontWeight: FontWeight.w600,
|
||||
color: ColorPalette.slate800,
|
||||
),
|
||||
),
|
||||
suffixLable ??
|
||||
const Text(
|
||||
Text(
|
||||
"",
|
||||
style: TextStyle(
|
||||
fontSize: 16,
|
||||
fontSize: nameSize,
|
||||
color: Colors.red,
|
||||
),
|
||||
),
|
||||
|
@ -139,7 +141,7 @@ class TextFormView extends StatelessWidget {
|
|||
style: TextStyle(
|
||||
fontWeight: FontWeight.w500,
|
||||
fontSize: 14,
|
||||
color: fontColorDisabled ?? ColorPalette.slate500,
|
||||
color: fontColorDisabled ?? ColorPalette.slate800,
|
||||
),
|
||||
readOnly: readOnly,
|
||||
validator: validator,
|
||||
|
@ -161,7 +163,7 @@ class TextFormView extends StatelessWidget {
|
|||
hintStyle: hintTextStyle ??
|
||||
const TextStyle(
|
||||
fontSize: 14,
|
||||
color: ColorPalette.greyFont,
|
||||
color: ColorPalette.slate400,
|
||||
fontWeight: FontWeight.normal,
|
||||
),
|
||||
isDense: true,
|
||||
|
|
|
@ -75,6 +75,7 @@ class ColorPalette {
|
|||
static const Color backgroundBlueLight = Color(0xFFEBF3FD);
|
||||
static const Color blue50 = Color(0xFFEFF6FF);
|
||||
static const Color blue200 = Color(0xFFBFDBFE);
|
||||
static const Color blue900 = Color(0xFF1E3A8A);
|
||||
static const Color slate50 = Color(0xFFF8FAFC);
|
||||
static const Color slate200 = Color(0xFFE2E8F0);
|
||||
static const Color slate300 = Color(0xFFCBD5E1);
|
||||
|
|
|
@ -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/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/route/route.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/phone_number_view.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:flutter/material.dart';
|
||||
import 'package:flutter/services.dart';
|
||||
import 'package:provider/provider.dart';
|
||||
|
||||
class LoginView extends StatefulWidget {
|
||||
|
@ -90,7 +83,11 @@ class _LoginViewState extends State<LoginView> {
|
|||
currentPage++;
|
||||
pageController.jumpToPage(1);
|
||||
} 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 {
|
||||
final void Function() nextStep;
|
||||
final TextEditingController controller;
|
||||
const PasswordView({super.key, required this.nextStep, required this.controller});
|
||||
const PasswordView(
|
||||
{super.key, required this.nextStep, required this.controller});
|
||||
|
||||
@override
|
||||
Widget build(BuildContext context) {
|
||||
return Consumer<LoginViewModel>(
|
||||
builder: (context, provider, child) {
|
||||
return Container(
|
||||
width: SizeConfig.width,
|
||||
height: SizeConfig.height,
|
||||
padding: const EdgeInsets.all(24),
|
||||
child: Column(
|
||||
crossAxisAlignment: CrossAxisAlignment.start,
|
||||
children: [
|
||||
const TextTitle(title: 'Enter your password', fontSize: 24),
|
||||
SizedBox(
|
||||
height: 24,
|
||||
),
|
||||
TextFormView(
|
||||
name: 'Password',
|
||||
ctrl: controller,
|
||||
obscureText: !provider.showPassword,
|
||||
contentPadding: EdgeInsets.all(12),
|
||||
suffixIcon: GestureDetector(
|
||||
onTap: () {
|
||||
provider.changeShowPassword();
|
||||
return Consumer<LoginViewModel>(builder: (context, provider, child) {
|
||||
return Container(
|
||||
width: SizeConfig.width,
|
||||
height: SizeConfig.height,
|
||||
padding: const EdgeInsets.all(24),
|
||||
child: Form(
|
||||
key: provider.formKey,
|
||||
child: SingleChildScrollView(
|
||||
child: Column(
|
||||
crossAxisAlignment: CrossAxisAlignment.start,
|
||||
children: [
|
||||
const TextTitle(title: 'Enter your password', fontSize: 24),
|
||||
SizedBox(
|
||||
height: 24,
|
||||
),
|
||||
TextFormView(
|
||||
name: 'Password',
|
||||
ctrl: controller,
|
||||
obscureText: !provider.showPassword,
|
||||
contentPadding: EdgeInsets.all(12),
|
||||
validator: (value) {
|
||||
if (value!.isEmpty) {
|
||||
return 'Password must filled';
|
||||
} else if (value.length < 8) {
|
||||
return 'Minimum password 8 Character';
|
||||
} else {
|
||||
return null;
|
||||
}
|
||||
},
|
||||
child: Icon(
|
||||
provider.showPassword
|
||||
? Icons.visibility_outlined
|
||||
: Icons.visibility_off_outlined,
|
||||
color: ColorPalette.greyDarker,
|
||||
suffixIcon: GestureDetector(
|
||||
onTap: () {
|
||||
provider.changeShowPassword();
|
||||
},
|
||||
child: Icon(
|
||||
provider.showPassword
|
||||
? Icons.visibility_outlined
|
||||
: Icons.visibility_off_outlined,
|
||||
color: ColorPalette.greyDarker,
|
||||
),
|
||||
),
|
||||
),
|
||||
),
|
||||
TextButton(
|
||||
style: TextButton.styleFrom(
|
||||
padding: EdgeInsets.all(0)
|
||||
TextButton(
|
||||
style: TextButton.styleFrom(padding: EdgeInsets.all(0)),
|
||||
onPressed: () {},
|
||||
child: Text(
|
||||
'Forget the password?',
|
||||
style: TextStyle(
|
||||
color: ColorPalette.primary,
|
||||
),
|
||||
)),
|
||||
SizedBox(
|
||||
height: 16,
|
||||
),
|
||||
onPressed: () {
|
||||
|
||||
},
|
||||
child: Text(
|
||||
'Forget the password?',
|
||||
style: TextStyle(
|
||||
color: ColorPalette.primary,
|
||||
),
|
||||
ButtonView(
|
||||
name: 'Confirm',
|
||||
heightWrapContent: true,
|
||||
width: SizeConfig.width,
|
||||
textSize: 18,
|
||||
marginVertical: 0,
|
||||
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/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/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/route/route.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:flutter/material.dart';
|
||||
import 'package:flutter/services.dart';
|
||||
import 'package:provider/provider.dart';
|
||||
|
||||
class PhoneNumberView extends StatelessWidget {
|
||||
final void Function() nextStep;
|
||||
final TextEditingController controller;
|
||||
const PhoneNumberView({super.key, required this.nextStep, required this.controller});
|
||||
const PhoneNumberView(
|
||||
{super.key, required this.nextStep, required this.controller});
|
||||
|
||||
@override
|
||||
Widget build(BuildContext context) {
|
||||
return Container(
|
||||
width: SizeConfig.width,
|
||||
height: SizeConfig.height,
|
||||
padding: const EdgeInsets.all(24),
|
||||
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,
|
||||
return ChangeNotifierProvider(
|
||||
create: (context) => LoginViewModel(),
|
||||
builder: (context, child) {
|
||||
return Container(
|
||||
width: SizeConfig.width,
|
||||
marginVertical: 0,
|
||||
contentPadding: EdgeInsets.symmetric(horizontal: 16, vertical: 12),
|
||||
onPressed: 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)
|
||||
height: SizeConfig.height,
|
||||
padding: const EdgeInsets.all(24),
|
||||
child:
|
||||
Consumer<LoginViewModel>(builder: (context, provider, child) {
|
||||
return Form(
|
||||
key: provider.formKey,
|
||||
child: SingleChildScrollView(
|
||||
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,
|
||||
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 {
|
||||
bool showPassword = false;
|
||||
var formKey = GlobalKey<FormState>();
|
||||
|
||||
void changeShowPassword() {
|
||||
showPassword = !showPassword;
|
||||
notifyListeners();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -45,7 +45,7 @@ class RegistrationPasswordView extends StatelessWidget {
|
|||
validator: (value) {
|
||||
if (value!.isEmpty) {
|
||||
return 'Password must filled';
|
||||
} else if (value.length <= 8) {
|
||||
} else if (value.length < 8) {
|
||||
return 'Minimum password 8 Character';
|
||||
} else {
|
||||
return null;
|
||||
|
|
|
@ -29,52 +29,57 @@ class SubmitBankAccount extends StatelessWidget {
|
|||
return SizedBox(
|
||||
child: Consumer<SubmissionDataViewModel>(
|
||||
builder: (context, provider, child) {
|
||||
return Column(
|
||||
crossAxisAlignment: CrossAxisAlignment.start,
|
||||
children: [
|
||||
const TextCaption(title: 'Input your bank account data'),
|
||||
SelectFormView(
|
||||
name: 'Bank Name',
|
||||
hintText: 'Select Bank',
|
||||
listItem: provider.listBank,
|
||||
ctrl: provider.ctrlBankName,
|
||||
onSelect: (value) {},
|
||||
),
|
||||
TextFormView(
|
||||
name: 'Account Number',
|
||||
hintText: 'Input Account Number',
|
||||
trailingTitleWidget: SizedBox(
|
||||
width: 24,
|
||||
child: GestureDetector(
|
||||
onTap: () {
|
||||
routePush(context, page: const GuideScreen());
|
||||
},
|
||||
child: const ImageView(image: PathAssets.iconQuestion),
|
||||
return SingleChildScrollView(
|
||||
child: Column(
|
||||
crossAxisAlignment: CrossAxisAlignment.start,
|
||||
children: [
|
||||
const TextCaption(title: 'Input your bank account data'),
|
||||
SelectFormView(
|
||||
name: 'Bank Name',
|
||||
hintText: 'Select Bank',
|
||||
listItem: provider.listBank,
|
||||
ctrl: provider.ctrlBankName,
|
||||
onSelect: (value) {},
|
||||
),
|
||||
TextFormView(
|
||||
name: 'Account Number',
|
||||
hintText: 'Input Account Number',
|
||||
keyboardType: TextInputType.number,
|
||||
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',
|
||||
),
|
||||
const Text(
|
||||
"Make sure the account you use is in your name, not someone else's",
|
||||
style: TextStyle(
|
||||
color: ColorPalette.slate400,
|
||||
TextFormView(
|
||||
name: 'Account Owner Name',
|
||||
hintText: 'Input Account Name',
|
||||
),
|
||||
),
|
||||
SizedBox(height: SizeConfig.height * .08),
|
||||
ButtonView(
|
||||
name: 'Next',
|
||||
onPressed: () {
|
||||
provider.next(context).then((value) {
|
||||
if (value) {
|
||||
routePush(context, page: const ConfirmBankAccount());
|
||||
}
|
||||
});
|
||||
},
|
||||
)
|
||||
],
|
||||
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());
|
||||
}
|
||||
});
|
||||
},
|
||||
)
|
||||
],
|
||||
),
|
||||
);
|
||||
}),
|
||||
);
|
||||
|
|
|
@ -30,7 +30,7 @@ class SubmitDataIdCard extends StatelessWidget {
|
|||
color: Colors.white,
|
||||
borderRadius:
|
||||
BorderRadius.vertical(top: Radius.circular(18))),
|
||||
height: SizeConfig.height * .32,
|
||||
height: SizeConfig.height * .35,
|
||||
padding: const EdgeInsets.all(16.0),
|
||||
child: Column(
|
||||
mainAxisAlignment: MainAxisAlignment.spaceBetween,
|
||||
|
@ -173,11 +173,15 @@ class SubmitDataIdCard extends StatelessWidget {
|
|||
children: [
|
||||
const TextCaption(
|
||||
title: 'Check your ID card data for accuracy'),
|
||||
TextFormView(name: 'NIK'),
|
||||
TextFormView(
|
||||
name: 'NIK',
|
||||
keyboardType: TextInputType.number,
|
||||
),
|
||||
TextFormView(name: 'Full Name'),
|
||||
DatePickerView(
|
||||
name: 'Birth Date',
|
||||
ctrl: provider.ctrlBirthDate,
|
||||
maxDate: DateTime.now(),
|
||||
isMultipleSelection: false,
|
||||
enabled: true),
|
||||
photoDocument(provider),
|
||||
|
|
|
@ -1,7 +1,9 @@
|
|||
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/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/profile/view/profile_view.dart';
|
||||
import 'package:cims_apps/features/transaction/view/transaction_view.dart';
|
||||
import 'package:flutter/material.dart';
|
||||
|
||||
class BottomNavigationView extends StatefulWidget {
|
||||
|
@ -16,13 +18,12 @@ class _BottomNavigationViewState extends State<BottomNavigationView> {
|
|||
|
||||
@override
|
||||
Widget build(BuildContext context) {
|
||||
///TODO: masukan pagenya dilistWidget ini
|
||||
List<Widget> listWidget = [
|
||||
List<Widget> listWidget = const [
|
||||
HomeView(),
|
||||
PlanView(),
|
||||
Container(),
|
||||
TransactionView(),
|
||||
PortofolioView(),
|
||||
Container(),
|
||||
ProfileView(),
|
||||
];
|
||||
|
||||
List<BottomNavigationBarItem> listNavigation = const [
|
||||
|
|
|
@ -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/utils/size_config.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:flutter/material.dart';
|
||||
|
||||
|
@ -50,14 +49,22 @@ class _HomeViewState extends State<HomeView> {
|
|||
InvestType('Sharia', PathAssets.iconPortofolioSharia)
|
||||
];
|
||||
|
||||
StepVerification listStepVerification = StepVerification(0, [
|
||||
'Registration', 'Verification', 'Complete'
|
||||
]);
|
||||
StepVerification listStepVerification =
|
||||
StepVerification(0, ['Registration', 'Verification', 'Complete']);
|
||||
|
||||
List<Article> listArticle = [
|
||||
Article('Education', '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),
|
||||
Article(
|
||||
'Education',
|
||||
'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
|
||||
|
@ -85,22 +92,17 @@ class _HomeViewState extends State<HomeView> {
|
|||
style: TextStyle(
|
||||
color: Colors.white,
|
||||
fontSize: 20,
|
||||
fontWeight: FontWeight.w700
|
||||
),
|
||||
fontWeight: FontWeight.w700),
|
||||
),
|
||||
ElevatedButton(
|
||||
onPressed: () {
|
||||
|
||||
},
|
||||
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)
|
||||
)
|
||||
shape: const CircleBorder()),
|
||||
child: const Icon(Icons.notifications_outlined))
|
||||
],
|
||||
),
|
||||
),
|
||||
|
@ -148,7 +150,8 @@ class _HomeViewState extends State<HomeView> {
|
|||
children: [
|
||||
Row(
|
||||
children: [
|
||||
const Text('Portofolio Value', style: TextStyle(color: Colors.white)),
|
||||
const Text('Portofolio Value',
|
||||
style: TextStyle(color: Colors.white)),
|
||||
const SizedBox(
|
||||
width: 12,
|
||||
),
|
||||
|
@ -158,8 +161,11 @@ class _HomeViewState extends State<HomeView> {
|
|||
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(
|
||||
|
@ -170,24 +176,28 @@ class _HomeViewState extends State<HomeView> {
|
|||
AnimatedCrossFade(
|
||||
duration: const Duration(milliseconds: 300),
|
||||
alignment: Alignment.center,
|
||||
crossFadeState: seePortofolioValue ? CrossFadeState.showSecond : CrossFadeState.showFirst,
|
||||
crossFadeState: seePortofolioValue
|
||||
? CrossFadeState.showSecond
|
||||
: CrossFadeState.showFirst,
|
||||
firstChild: RichText(
|
||||
text: const TextSpan(
|
||||
text: 'Rp ',
|
||||
style: TextStyle(fontSize: 32, color: Color(0xff93C5FD), fontFamily: 'Manrope',),
|
||||
style: TextStyle(
|
||||
fontSize: 32,
|
||||
color: Color(0xff93C5FD),
|
||||
fontFamily: 'Manrope',
|
||||
),
|
||||
children: [
|
||||
TextSpan(
|
||||
text: '22.500.000',
|
||||
style: TextStyle(
|
||||
fontSize: 32,
|
||||
fontWeight: FontWeight.bold,
|
||||
color: Colors.white,
|
||||
fontFamily: 'Manrope',
|
||||
),
|
||||
)
|
||||
]
|
||||
)
|
||||
),
|
||||
TextSpan(
|
||||
text: '22.500.000',
|
||||
style: TextStyle(
|
||||
fontSize: 32,
|
||||
fontWeight: FontWeight.bold,
|
||||
color: Colors.white,
|
||||
fontFamily: 'Manrope',
|
||||
),
|
||||
)
|
||||
])),
|
||||
secondChild: Padding(
|
||||
padding: const EdgeInsets.symmetric(vertical: 16),
|
||||
child: Wrap(
|
||||
|
@ -197,7 +207,8 @@ class _HomeViewState extends State<HomeView> {
|
|||
Container(
|
||||
width: 12,
|
||||
height: 12,
|
||||
decoration: const BoxDecoration(color: Colors.white, shape: BoxShape.circle),
|
||||
decoration: const BoxDecoration(
|
||||
color: Colors.white, shape: BoxShape.circle),
|
||||
),
|
||||
],
|
||||
),
|
||||
|
@ -219,23 +230,25 @@ class _HomeViewState extends State<HomeView> {
|
|||
BoxShadow(
|
||||
spreadRadius: 2,
|
||||
blurRadius: 4,
|
||||
color: const Color(0xff1E293B).withOpacity(0.04)
|
||||
)
|
||||
]
|
||||
),
|
||||
color: const Color(0xff1E293B).withOpacity(0.04))
|
||||
]),
|
||||
child: Wrap(
|
||||
spacing: 10,
|
||||
children: listPortofolioType.asMap().entries.map((e) {
|
||||
return GestureDetector(
|
||||
return GestureDetector(
|
||||
onTap: () {
|
||||
routePush(context, page: InvestTypeView(e.value.name));
|
||||
routePush(context, page: InvestTypeView(title: e.value.name));
|
||||
},
|
||||
child: Container(
|
||||
color: Colors.white,
|
||||
width: SizeConfig.width * .18,
|
||||
child: Column(
|
||||
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(
|
||||
height: 8,
|
||||
),
|
||||
|
@ -244,9 +257,7 @@ class _HomeViewState extends State<HomeView> {
|
|||
overflow: TextOverflow.ellipsis,
|
||||
textAlign: TextAlign.center,
|
||||
style: const TextStyle(
|
||||
fontSize: 12,
|
||||
fontWeight: FontWeight.w600
|
||||
),
|
||||
fontSize: 12, fontWeight: FontWeight.w600),
|
||||
)
|
||||
],
|
||||
),
|
||||
|
@ -271,21 +282,22 @@ class _HomeViewState extends State<HomeView> {
|
|||
const SizedBox(
|
||||
height: 24,
|
||||
),
|
||||
if(listStepVerification.currentStep == 1)...[
|
||||
if (listStepVerification.currentStep == 1) ...[
|
||||
Row(
|
||||
mainAxisAlignment: MainAxisAlignment.spaceBetween,
|
||||
children: [
|
||||
const Row(
|
||||
children: [
|
||||
Icon(Icons.verified, size: 18,),
|
||||
Icon(
|
||||
Icons.verified,
|
||||
size: 18,
|
||||
),
|
||||
SizedBox(
|
||||
width: 12,
|
||||
),
|
||||
Text(
|
||||
'Verified by PT Gemilang',
|
||||
style: TextStyle(
|
||||
color: ColorPalette.slate500
|
||||
),
|
||||
style: TextStyle(color: ColorPalette.slate500),
|
||||
)
|
||||
],
|
||||
),
|
||||
|
@ -294,9 +306,9 @@ class _HomeViewState extends State<HomeView> {
|
|||
height: 16,
|
||||
decoration: BoxDecoration(
|
||||
color: Colors.white,
|
||||
border: Border.all(color: const Color(0xffCBD5E1), width: 1.5),
|
||||
shape: BoxShape.circle
|
||||
),
|
||||
border: Border.all(
|
||||
color: const Color(0xffCBD5E1), width: 1.5),
|
||||
shape: BoxShape.circle),
|
||||
)
|
||||
],
|
||||
),
|
||||
|
@ -309,15 +321,16 @@ class _HomeViewState extends State<HomeView> {
|
|||
const Row(
|
||||
crossAxisAlignment: CrossAxisAlignment.end,
|
||||
children: [
|
||||
Icon(Icons.verified, size: 18,),
|
||||
Icon(
|
||||
Icons.verified,
|
||||
size: 18,
|
||||
),
|
||||
SizedBox(
|
||||
width: 12,
|
||||
),
|
||||
Text(
|
||||
'Verified by KSEI',
|
||||
style: TextStyle(
|
||||
color: ColorPalette.slate500
|
||||
),
|
||||
style: TextStyle(color: ColorPalette.slate500),
|
||||
)
|
||||
],
|
||||
),
|
||||
|
@ -326,9 +339,9 @@ class _HomeViewState extends State<HomeView> {
|
|||
height: 16,
|
||||
decoration: BoxDecoration(
|
||||
color: Colors.white,
|
||||
border: Border.all(color: const Color(0xffCBD5E1), width: 1.5),
|
||||
shape: BoxShape.circle
|
||||
),
|
||||
border: Border.all(
|
||||
color: const Color(0xffCBD5E1), width: 1.5),
|
||||
shape: BoxShape.circle),
|
||||
)
|
||||
],
|
||||
),
|
||||
|
@ -339,15 +352,12 @@ class _HomeViewState extends State<HomeView> {
|
|||
padding: const EdgeInsets.all(12),
|
||||
decoration: BoxDecoration(
|
||||
color: ColorPalette.blue50,
|
||||
borderRadius: BorderRadius.circular(12)
|
||||
),
|
||||
borderRadius: BorderRadius.circular(12)),
|
||||
child: const Column(
|
||||
children: [
|
||||
Text(
|
||||
'Your registration is currently being verified by PT Gemilang',
|
||||
style: TextStyle(
|
||||
color: ColorPalette.slate500
|
||||
),
|
||||
style: TextStyle(color: ColorPalette.slate500),
|
||||
),
|
||||
SizedBox(
|
||||
height: 16,
|
||||
|
@ -355,37 +365,32 @@ class _HomeViewState extends State<HomeView> {
|
|||
Row(
|
||||
mainAxisAlignment: MainAxisAlignment.spaceBetween,
|
||||
children: [
|
||||
Text('Estimated:',
|
||||
style: TextStyle(
|
||||
color: ColorPalette.slate500
|
||||
),
|
||||
Text(
|
||||
'Estimated:',
|
||||
style: TextStyle(color: ColorPalette.slate500),
|
||||
),
|
||||
Text(
|
||||
'January 30 2024',
|
||||
style: TextStyle(
|
||||
fontWeight: FontWeight.w600,
|
||||
color: Color(0xff1E293B)
|
||||
),
|
||||
color: Color(0xff1E293B)),
|
||||
)
|
||||
],
|
||||
)
|
||||
],
|
||||
),
|
||||
)
|
||||
]else if(listStepVerification.currentStep == 0)...[
|
||||
] else if (listStepVerification.currentStep == 0) ...[
|
||||
Container(
|
||||
padding: const EdgeInsets.all(12),
|
||||
decoration: BoxDecoration(
|
||||
color: ColorPalette.blue50,
|
||||
borderRadius: BorderRadius.circular(12)
|
||||
),
|
||||
borderRadius: BorderRadius.circular(12)),
|
||||
child: Column(
|
||||
children: [
|
||||
Text(
|
||||
"Let's start registering your data to start mutual fund investment at PT Gemilang Indonesia",
|
||||
style: TextStyle(
|
||||
color: ColorPalette.slate500
|
||||
),
|
||||
style: TextStyle(color: ColorPalette.slate500),
|
||||
),
|
||||
SizedBox(
|
||||
height: 16,
|
||||
|
@ -416,11 +421,15 @@ class _HomeViewState extends State<HomeView> {
|
|||
return Row(
|
||||
crossAxisAlignment: CrossAxisAlignment.start,
|
||||
children: [
|
||||
if(e.key != 0)
|
||||
if (e.key != 0)
|
||||
SizedBox(
|
||||
width: 30,
|
||||
height: 30,
|
||||
child: Divider(color: listStepVerification.currentStep >= e.key ? const Color(0xff2563EB) : const Color(0xffCBD5E1),),
|
||||
child: Divider(
|
||||
color: listStepVerification.currentStep >= e.key
|
||||
? const Color(0xff2563EB)
|
||||
: const Color(0xffCBD5E1),
|
||||
),
|
||||
),
|
||||
Column(
|
||||
children: [
|
||||
|
@ -429,18 +438,31 @@ class _HomeViewState extends State<HomeView> {
|
|||
height: 30,
|
||||
decoration: BoxDecoration(
|
||||
shape: BoxShape.circle,
|
||||
color: listStepVerification.currentStep <= e.key ? Colors.white : const Color(0xff2563EB),
|
||||
color: listStepVerification.currentStep <= e.key
|
||||
? Colors.white
|
||||
: const Color(0xff2563EB),
|
||||
border: Border.all(
|
||||
color: listStepVerification.currentStep < e.key ? const Color(0xffCBD5E1) : const Color(0xff2563EB),
|
||||
width: 2
|
||||
)
|
||||
),
|
||||
child: listStepVerification.currentStep <= e.key ? const SizedBox() : const Icon(Icons.done_rounded, color: Colors.white,),
|
||||
color: listStepVerification.currentStep < e.key
|
||||
? const Color(0xffCBD5E1)
|
||||
: const Color(0xff2563EB),
|
||||
width: 2)),
|
||||
child: listStepVerification.currentStep <= e.key
|
||||
? const SizedBox()
|
||||
: const Icon(
|
||||
Icons.done_rounded,
|
||||
color: Colors.white,
|
||||
),
|
||||
),
|
||||
const SizedBox(
|
||||
height: 8,
|
||||
),
|
||||
Text(e.value, style: TextStyle(color: listStepVerification.currentStep == e.key ? const Color(0xff2563EB) : Colors.black),)
|
||||
Text(
|
||||
e.value,
|
||||
style: TextStyle(
|
||||
color: listStepVerification.currentStep == e.key
|
||||
? const Color(0xff2563EB)
|
||||
: Colors.black),
|
||||
)
|
||||
],
|
||||
),
|
||||
],
|
||||
|
@ -455,15 +477,22 @@ class _HomeViewState extends State<HomeView> {
|
|||
child: Column(
|
||||
crossAxisAlignment: CrossAxisAlignment.start,
|
||||
children: [
|
||||
const TextTitle(title: 'Info and Special Promo', color: ColorPalette.slate800,),
|
||||
const TextTitle(
|
||||
title: 'Info and Special Promo',
|
||||
color: ColorPalette.slate800,
|
||||
),
|
||||
const SizedBox(
|
||||
height: 16,
|
||||
),
|
||||
CarouselSlider(
|
||||
items: [1,2,3].map((e) {
|
||||
items: [1, 2, 3].map((e) {
|
||||
return Padding(
|
||||
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(),
|
||||
options: CarouselOptions(
|
||||
|
@ -493,14 +522,13 @@ class _HomeViewState extends State<HomeView> {
|
|||
children: [
|
||||
const TextTitle(title: 'Article', color: ColorPalette.slate800),
|
||||
GestureDetector(
|
||||
onTap: () {
|
||||
|
||||
},
|
||||
child: const Text('See More',
|
||||
onTap: () {},
|
||||
child: const Text(
|
||||
'See More',
|
||||
style: TextStyle(
|
||||
color: ColorPalette.primary,
|
||||
fontWeight: FontWeight.bold
|
||||
),),
|
||||
color: ColorPalette.primary,
|
||||
fontWeight: FontWeight.bold),
|
||||
),
|
||||
)
|
||||
],
|
||||
),
|
||||
|
@ -511,10 +539,12 @@ class _HomeViewState extends State<HomeView> {
|
|||
...listArticle.asMap().entries.map((e) {
|
||||
return Column(
|
||||
children: [
|
||||
if(e.key != 0)...[
|
||||
if (e.key != 0) ...[
|
||||
const Padding(
|
||||
padding: EdgeInsets.symmetric(vertical: 12),
|
||||
child: Divider(color: ColorPalette.slate200,),
|
||||
child: Divider(
|
||||
color: ColorPalette.slate200,
|
||||
),
|
||||
)
|
||||
],
|
||||
cardArticle(e.value),
|
||||
|
@ -531,39 +561,43 @@ class _HomeViewState extends State<HomeView> {
|
|||
padding: const EdgeInsets.symmetric(horizontal: 24),
|
||||
child: Row(
|
||||
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(
|
||||
width: 16,
|
||||
),
|
||||
Expanded(
|
||||
child: Column(
|
||||
crossAxisAlignment: CrossAxisAlignment.start,
|
||||
children: [
|
||||
Text(article.title,
|
||||
style: const TextStyle(
|
||||
fontWeight: FontWeight.bold,
|
||||
),
|
||||
child: Column(
|
||||
crossAxisAlignment: CrossAxisAlignment.start,
|
||||
children: [
|
||||
Text(
|
||||
article.title,
|
||||
style: const TextStyle(
|
||||
fontWeight: FontWeight.bold,
|
||||
),
|
||||
const SizedBox(
|
||||
height: 8,
|
||||
),
|
||||
Container(
|
||||
padding: const EdgeInsets.symmetric(vertical: 4, horizontal: 12),
|
||||
decoration: BoxDecoration(
|
||||
),
|
||||
const SizedBox(
|
||||
height: 8,
|
||||
),
|
||||
Container(
|
||||
padding:
|
||||
const EdgeInsets.symmetric(vertical: 4, horizontal: 12),
|
||||
decoration: BoxDecoration(
|
||||
borderRadius: BorderRadius.circular(30),
|
||||
color: ColorPalette.green100
|
||||
),
|
||||
child: Text(
|
||||
article.type,
|
||||
style: TextStyle(
|
||||
color: ColorPalette.green100),
|
||||
child: Text(
|
||||
article.type,
|
||||
style: TextStyle(
|
||||
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/utils/number_formatter.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';
|
||||
|
||||
class Product {
|
||||
String name;
|
||||
double yield;
|
||||
double priceUnit;
|
||||
double funds;
|
||||
|
||||
Product(this.name, this.yield, this.priceUnit, this.funds);
|
||||
}
|
||||
import 'package:provider/provider.dart';
|
||||
|
||||
class InvestTypeView extends StatefulWidget {
|
||||
final String title;
|
||||
const InvestTypeView(this.title, {super.key});
|
||||
const InvestTypeView({super.key, required this.title});
|
||||
|
||||
@override
|
||||
State<InvestTypeView> createState() => _InvestTypeViewState();
|
||||
}
|
||||
|
||||
class _InvestTypeViewState extends State<InvestTypeView> {
|
||||
|
||||
List<Product> listProduct = [
|
||||
Product('Gemilang Dana Kas Maxima', 8.17, 2600.79, 6300000),
|
||||
Product('Gemilang Dana Likuid', 6.42, 1600.79, 2340000),
|
||||
Product('Gemilang Income Fund', 8.17, 2600.79, 6300000)
|
||||
Product(
|
||||
name: 'Gemilang Dana Kas Maxima',
|
||||
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
|
||||
Widget build(BuildContext context) {
|
||||
return Scaffold(
|
||||
body: SizedBox(
|
||||
width: SizeConfig.width,
|
||||
height: SizeConfig.height,
|
||||
child: Stack(
|
||||
children: [
|
||||
const ImageView(image: PathAssets.imgDashboardAccount),
|
||||
Column(
|
||||
return ChangeNotifierProvider<ProductViewModel>(
|
||||
create: (context) => ProductViewModel(),
|
||||
child: Consumer<ProductViewModel>(builder: (context, provider, child) {
|
||||
return Scaffold(
|
||||
body: SizedBox(
|
||||
width: SizeConfig.width,
|
||||
height: SizeConfig.height,
|
||||
child: Stack(
|
||||
children: [
|
||||
const SizedBox(
|
||||
height: 50,
|
||||
),
|
||||
Padding(
|
||||
padding: const EdgeInsets.symmetric(horizontal: 24),
|
||||
child: Row(
|
||||
mainAxisAlignment: MainAxisAlignment.spaceBetween,
|
||||
children: [
|
||||
const BackButtonView(),
|
||||
TextTitle(title: widget.title, color: Colors.white),
|
||||
SizedBox(
|
||||
width: SizeConfig.width * 0.1,
|
||||
)
|
||||
],
|
||||
),
|
||||
),
|
||||
const SizedBox(
|
||||
height: 24,
|
||||
),
|
||||
Container(
|
||||
padding: const EdgeInsets.all(24),
|
||||
decoration: BoxDecoration(
|
||||
borderRadius: BorderRadius.circular(16),
|
||||
color: Colors.white
|
||||
),
|
||||
child: Column(
|
||||
children: [
|
||||
filters(),
|
||||
ListView(
|
||||
shrinkWrap: true,
|
||||
children: listProduct.asMap().entries.map((e) {
|
||||
return GestureDetector(
|
||||
onTap: () {
|
||||
routePush(context, page: ProductView(widget.title));
|
||||
},
|
||||
child: Padding(
|
||||
padding: EdgeInsets.only(top: e.key != 0 ? 24 : 0),
|
||||
child: cardProduct(e.value),
|
||||
),
|
||||
);
|
||||
}).toList(),
|
||||
)
|
||||
],
|
||||
),
|
||||
),
|
||||
const ImageView(image: PathAssets.imgDashboardAccount),
|
||||
Column(
|
||||
children: [
|
||||
SizedBox(
|
||||
height: SizeConfig.height * .1,
|
||||
),
|
||||
Padding(
|
||||
padding: const EdgeInsets.symmetric(horizontal: 24),
|
||||
child: Row(
|
||||
mainAxisAlignment: MainAxisAlignment.spaceBetween,
|
||||
children: [
|
||||
const BackButtonView(),
|
||||
TextTitle(title: widget.title, color: Colors.white),
|
||||
SizedBox(
|
||||
width: SizeConfig.width * 0.1,
|
||||
)
|
||||
],
|
||||
),
|
||||
),
|
||||
const SizedBox(
|
||||
height: 24,
|
||||
),
|
||||
Expanded(
|
||||
child: Container(
|
||||
padding: const EdgeInsets.all(24),
|
||||
decoration: BoxDecoration(
|
||||
borderRadius: BorderRadius.circular(16),
|
||||
color: Colors.white),
|
||||
child: SingleChildScrollView(
|
||||
scrollDirection: Axis.vertical,
|
||||
child: Column(
|
||||
children: [
|
||||
filters(),
|
||||
ListView(
|
||||
shrinkWrap: true,
|
||||
children: listProduct.asMap().entries.map((e) {
|
||||
return GestureDetector(
|
||||
onTap: () {
|
||||
provider.setSelectedProduct(e.value);
|
||||
routePush(context,
|
||||
page: ProductView(widget.title));
|
||||
},
|
||||
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(
|
||||
mainAxisAlignment: MainAxisAlignment.spaceBetween,
|
||||
children: [
|
||||
segmentFilter(const Icon(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', () { }),
|
||||
segmentFilter(
|
||||
const Icon(
|
||||
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) {
|
||||
return GestureDetector(
|
||||
onTap: onTap,
|
||||
child: Container(
|
||||
child: Container(
|
||||
padding: const EdgeInsets.symmetric(vertical: 8, horizontal: 16),
|
||||
decoration: BoxDecoration(
|
||||
border: Border.all(color: ColorPalette.slate200),
|
||||
borderRadius: BorderRadius.circular(56)
|
||||
),
|
||||
borderRadius: BorderRadius.circular(56)),
|
||||
child: Row(
|
||||
children: [
|
||||
leading,
|
||||
|
@ -131,9 +175,7 @@ class _InvestTypeViewState extends State<InvestTypeView> {
|
|||
text,
|
||||
overflow: TextOverflow.ellipsis,
|
||||
style: const TextStyle(
|
||||
color: ColorPalette.slate500,
|
||||
fontWeight: FontWeight.w700
|
||||
),
|
||||
color: ColorPalette.slate500, fontWeight: FontWeight.w700),
|
||||
)
|
||||
],
|
||||
),
|
||||
|
@ -152,17 +194,18 @@ class _InvestTypeViewState extends State<InvestTypeView> {
|
|||
children: [
|
||||
Row(
|
||||
children: [
|
||||
ImageView(image: PathAssets.imgProduct, width: SizeConfig.width * .12,),
|
||||
ImageView(
|
||||
image: PathAssets.imgProduct,
|
||||
width: SizeConfig.width * .12,
|
||||
),
|
||||
const SizedBox(
|
||||
width: 8,
|
||||
),
|
||||
Expanded(
|
||||
child: Text(
|
||||
product.name,
|
||||
product.name ?? '',
|
||||
style: const TextStyle(
|
||||
fontWeight: FontWeight.bold,
|
||||
fontSize: 18
|
||||
),
|
||||
fontWeight: FontWeight.bold, fontSize: 18),
|
||||
),
|
||||
)
|
||||
],
|
||||
|
@ -176,36 +219,53 @@ class _InvestTypeViewState extends State<InvestTypeView> {
|
|||
children: [
|
||||
Column(
|
||||
children: [
|
||||
const Text('Yield', style: TextStyle(color: ColorPalette.slate400, fontWeight: FontWeight.w600),),
|
||||
const Text(
|
||||
'Yield',
|
||||
style: TextStyle(
|
||||
color: ColorPalette.slate400,
|
||||
fontWeight: FontWeight.w600),
|
||||
),
|
||||
Row(
|
||||
children: [
|
||||
Text(
|
||||
'${product.yield.toString()}%',
|
||||
style: const TextStyle(
|
||||
color: ColorPalette.green400,
|
||||
fontWeight: FontWeight.w600
|
||||
),
|
||||
color: ColorPalette.green400,
|
||||
fontWeight: FontWeight.w600),
|
||||
),
|
||||
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(
|
||||
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(
|
||||
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(
|
||||
width: 2,
|
||||
),
|
||||
Text(
|
||||
NumberFormatter.numberCurrency(product.priceUnit, 'Rp', 'id_ID'),
|
||||
style: const TextStyle(
|
||||
fontWeight: FontWeight.w600
|
||||
),
|
||||
NumberFormatter.numberCurrency(
|
||||
product.priceUnit, 'Rp', 'id_ID'),
|
||||
style: const TextStyle(fontWeight: FontWeight.w600),
|
||||
),
|
||||
],
|
||||
)
|
||||
|
@ -213,14 +273,18 @@ class _InvestTypeViewState extends State<InvestTypeView> {
|
|||
),
|
||||
Column(
|
||||
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(
|
||||
children: [
|
||||
Text(
|
||||
NumberFormatter.compactCurrency(product.funds, 'Rp ', 'id_ID'),
|
||||
style: const TextStyle(
|
||||
fontWeight: FontWeight.w600
|
||||
),
|
||||
NumberFormatter.compactCurrency(
|
||||
product.funds, 'Rp ', 'id_ID'),
|
||||
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,126 @@
|
|||
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/subscribe/goal_investing_view.dart';
|
||||
import 'package:cims_apps/application/component/subscribe/input_investment_view.dart';
|
||||
import 'package:cims_apps/application/component/numeric_pad/numeric_pad.dart';
|
||||
import 'package:cims_apps/application/component/risk_profile.dart';
|
||||
import 'package:cims_apps/application/component/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 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 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),
|
||||
InputInvestmentView(
|
||||
selectedPlan: text,
|
||||
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,153 @@
|
|||
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/utils/size_config.dart';
|
||||
import 'package:cims_apps/features/dashboard/dashboard_account/view/product/view_model/product_view_model.dart';
|
||||
import 'package:flutter/material.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 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
|
||||
),
|
||||
),
|
||||
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: () {
|
||||
},
|
||||
child: const Text('See More',
|
||||
style: TextStyle(
|
||||
color: ColorPalette.slate500,
|
||||
fontWeight: FontWeight.w600,
|
||||
),
|
||||
),
|
||||
)
|
||||
],
|
||||
),
|
||||
);
|
||||
}).toList(),
|
||||
),
|
||||
),
|
||||
const SizedBox(
|
||||
height: 16,
|
||||
),
|
||||
ButtonView(
|
||||
name: 'Next',
|
||||
onPressed: () {
|
||||
showModalBottomSheet(
|
||||
context: context,
|
||||
isScrollControlled: true,
|
||||
builder: (context) =>
|
||||
TotalPaymentView(
|
||||
listProduct: listProduct,
|
||||
totalInvest: totalInvest,
|
||||
)
|
||||
);
|
||||
},
|
||||
width: SizeConfig.width,
|
||||
heightWrapContent: true,
|
||||
contentPadding: const EdgeInsets.symmetric(vertical: 16),
|
||||
marginVertical: 0,
|
||||
)
|
||||
],
|
||||
),
|
||||
);
|
||||
}
|
||||
}
|
|
@ -0,0 +1,6 @@
|
|||
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 = [];
|
||||
}
|
|
@ -1,5 +1,3 @@
|
|||
import 'dart:math';
|
||||
|
||||
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';
|
||||
|
@ -70,7 +68,7 @@ class _PortofolioViewState extends State<PortofolioView> {
|
|||
),
|
||||
const Center(
|
||||
child: Text(
|
||||
'Portofolio',
|
||||
'Portfolio',
|
||||
style: TextStyle(
|
||||
fontSize: 20,
|
||||
fontWeight: FontWeight.w700,
|
||||
|
@ -125,20 +123,22 @@ class _PortofolioViewState extends State<PortofolioView> {
|
|||
),
|
||||
Column(
|
||||
children: [
|
||||
const Text('Total Mutual Fund',
|
||||
const Text(
|
||||
'Total Mutual Fund',
|
||||
style: TextStyle(
|
||||
fontWeight: FontWeight.w600,
|
||||
fontSize: 18,
|
||||
color: ColorPalette.slate400
|
||||
),
|
||||
fontWeight: FontWeight.w600,
|
||||
fontSize: 18,
|
||||
color: ColorPalette.slate400),
|
||||
),
|
||||
Text(listInvestmentType.map((e) => e.mutualFunds).reduce((value, element) => value + element).toString(),
|
||||
style: const TextStyle(
|
||||
fontSize: 44,
|
||||
fontWeight: FontWeight.w700
|
||||
)
|
||||
)
|
||||
,
|
||||
Text(
|
||||
listInvestmentType
|
||||
.map((e) => e.mutualFunds)
|
||||
.reduce(
|
||||
(value, element) => value + element)
|
||||
.toString(),
|
||||
style: const TextStyle(
|
||||
fontSize: 44,
|
||||
fontWeight: FontWeight.w700)),
|
||||
],
|
||||
)
|
||||
]),
|
||||
|
@ -168,7 +168,7 @@ class _PortofolioViewState extends State<PortofolioView> {
|
|||
children: [
|
||||
Row(
|
||||
children: [
|
||||
const Text('Portofolio Value',
|
||||
const Text('Portfolio Value',
|
||||
style: TextStyle(color: Colors.white)),
|
||||
const SizedBox(
|
||||
width: 8,
|
||||
|
@ -179,8 +179,11 @@ class _PortofolioViewState extends State<PortofolioView> {
|
|||
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(
|
||||
|
@ -197,7 +200,10 @@ class _PortofolioViewState extends State<PortofolioView> {
|
|||
firstChild: RichText(
|
||||
text: const TextSpan(
|
||||
text: 'Rp ',
|
||||
style: TextStyle(fontSize: 32, color: Color(0xff93C5FD), fontFamily: 'Manrope'),
|
||||
style: TextStyle(
|
||||
fontSize: 32,
|
||||
color: Color(0xff93C5FD),
|
||||
fontFamily: 'Manrope'),
|
||||
children: [
|
||||
TextSpan(
|
||||
text: '22.500.000',
|
||||
|
@ -205,8 +211,7 @@ class _PortofolioViewState extends State<PortofolioView> {
|
|||
fontSize: 32,
|
||||
fontFamily: 'Manrope',
|
||||
fontWeight: FontWeight.bold,
|
||||
color: Colors.white
|
||||
),
|
||||
color: Colors.white),
|
||||
)
|
||||
])),
|
||||
secondChild: Padding(
|
||||
|
@ -276,8 +281,8 @@ class _PortofolioViewState extends State<PortofolioView> {
|
|||
width: 58,
|
||||
alignment: Alignment.center,
|
||||
decoration: BoxDecoration(
|
||||
shape: BoxShape.circle,
|
||||
color: bgContentColor[e.key],
|
||||
shape: BoxShape.circle,
|
||||
color: bgContentColor[e.key],
|
||||
),
|
||||
child: Text(
|
||||
'${e.value.value}%',
|
||||
|
|
|
@ -9,9 +9,12 @@ 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/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:group_button/group_button.dart';
|
||||
import 'package:provider/provider.dart';
|
||||
|
||||
class Time {
|
||||
int value;
|
||||
|
@ -97,58 +100,65 @@ class _ProductViewState extends State<ProductView> {
|
|||
|
||||
@override
|
||||
Widget build(BuildContext context) {
|
||||
return Scaffold(
|
||||
body: SizedBox(
|
||||
child: Stack(
|
||||
children: [
|
||||
const ImageView(image: PathAssets.imgDashboardAccount),
|
||||
Column(
|
||||
children: [
|
||||
const SizedBox(
|
||||
height: 50,
|
||||
),
|
||||
const Padding(
|
||||
padding: EdgeInsets.symmetric(horizontal: 24),
|
||||
child: Row(
|
||||
mainAxisAlignment: MainAxisAlignment.spaceBetween,
|
||||
children: [
|
||||
BackButtonView(),
|
||||
Wrap(
|
||||
spacing: 12,
|
||||
children: [
|
||||
Icon(Icons.search_rounded, color: ColorPalette.blue200, size: 32),
|
||||
Icon(Icons.file_download_outlined, color: ColorPalette.blue200, size: 32),
|
||||
Icon(Icons.star_outline_rounded, color: ColorPalette.blue200, size: 32)
|
||||
],
|
||||
)
|
||||
],
|
||||
return ChangeNotifierProvider(
|
||||
create: (context) => ProductViewModel(),
|
||||
child: Scaffold(
|
||||
body: SizedBox(
|
||||
child: Stack(
|
||||
children: [
|
||||
const ImageView(image: PathAssets.imgDashboardAccount),
|
||||
Column(
|
||||
children: [
|
||||
const SizedBox(
|
||||
height: 50,
|
||||
),
|
||||
),
|
||||
const SizedBox(
|
||||
height: 24,
|
||||
),
|
||||
headContainer(),
|
||||
const SizedBox(
|
||||
height: 24,
|
||||
),
|
||||
Expanded(
|
||||
child: contentContainer()
|
||||
)
|
||||
],
|
||||
)
|
||||
],
|
||||
const Padding(
|
||||
padding: EdgeInsets.symmetric(horizontal: 24),
|
||||
child: Row(
|
||||
mainAxisAlignment: MainAxisAlignment.spaceBetween,
|
||||
children: [
|
||||
BackButtonView(),
|
||||
Wrap(
|
||||
spacing: 12,
|
||||
children: [
|
||||
Icon(Icons.search_rounded, color: ColorPalette.blue200, size: 32),
|
||||
Icon(Icons.file_download_outlined, color: ColorPalette.blue200, size: 32),
|
||||
Icon(Icons.star_outline_rounded, color: ColorPalette.blue200, size: 32)
|
||||
],
|
||||
)
|
||||
],
|
||||
),
|
||||
),
|
||||
const SizedBox(
|
||||
height: 24,
|
||||
),
|
||||
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: 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,
|
||||
),
|
||||
),
|
||||
),
|
||||
);
|
||||
|
@ -581,18 +591,10 @@ class _ProductViewState extends State<ProductView> {
|
|||
},
|
||||
selectedMachineType
|
||||
),
|
||||
const Padding(
|
||||
padding: EdgeInsets.only(top: 16, bottom: 8),
|
||||
child: Text(
|
||||
"Today's Investment Estimated Value",
|
||||
style: TextStyle(
|
||||
fontWeight: FontWeight.w600,
|
||||
color: ColorPalette.slate800
|
||||
),
|
||||
),
|
||||
),
|
||||
SizedBox(height: 16),
|
||||
TextFormView(
|
||||
name: '',
|
||||
name: "Today's Investment Estimated Value",
|
||||
nameSize: 14,
|
||||
ctrl: machineController,
|
||||
keyboardType: TextInputType.number,
|
||||
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,83 @@
|
|||
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/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 MultiProvider(
|
||||
providers: [
|
||||
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 InputInvestmentView(
|
||||
selectedPlan: p0,
|
||||
nextMove: (value) {
|
||||
Navigator.pop(context);
|
||||
int formatIntParse = int.parse(value.replaceAll('Rp ', '').replaceAll(',', ''));
|
||||
showModalBottomSheet(
|
||||
context: context,
|
||||
isScrollControlled: true,
|
||||
builder: (context) =>
|
||||
TotalPaymentView(
|
||||
listProduct: [
|
||||
provider.getSelectedProduct
|
||||
],
|
||||
totalInvest: formatIntParse,
|
||||
)
|
||||
);
|
||||
},
|
||||
);
|
||||
},
|
||||
);
|
||||
},
|
||||
)
|
||||
],
|
||||
),
|
||||
);
|
||||
}
|
||||
),
|
||||
);
|
||||
}
|
||||
}
|
|
@ -0,0 +1,27 @@
|
|||
|
||||
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;
|
||||
|
||||
void setSelectedProduct(Product product) {
|
||||
selectedProduct = product;
|
||||
notifyListeners();
|
||||
}
|
||||
|
||||
void setTotalInvestment(double value) {
|
||||
totalInvestment = value;
|
||||
notifyListeners();
|
||||
}
|
||||
}
|
|
@ -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/utils/size_config.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/dashboard/dashboard_public/viewmodel/dashboard_public_viewmodel.dart';
|
||||
import 'package:flutter/material.dart';
|
||||
import 'package:provider/provider.dart';
|
||||
|
||||
class DashboardPublicView extends StatelessWidget {
|
||||
static const routeName = '/DashboardPublicView';
|
||||
|
@ -37,88 +38,95 @@ class DashboardPublicView extends StatelessWidget {
|
|||
|
||||
@override
|
||||
Widget build(BuildContext context) {
|
||||
return Scaffold(
|
||||
body: SingleChildScrollView(
|
||||
padding: const EdgeInsets.only(
|
||||
top: 32.0,
|
||||
bottom: 8.0,
|
||||
left: 24.0,
|
||||
right: 24.0,
|
||||
),
|
||||
child: Column(
|
||||
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,
|
||||
return ChangeNotifierProvider(
|
||||
create: (context) => DashboardPublicViewModel(),
|
||||
builder: (context, child) {
|
||||
return Scaffold(
|
||||
body: SingleChildScrollView(
|
||||
padding: const EdgeInsets.only(
|
||||
top: 32.0,
|
||||
bottom: 8.0,
|
||||
left: 24.0,
|
||||
right: 24.0,
|
||||
),
|
||||
child: Consumer<DashboardPublicViewModel>(
|
||||
builder: (context, provider, child) {
|
||||
return Column(
|
||||
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,
|
||||
),
|
||||
),
|
||||
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);
|
||||
},
|
||||
),
|
||||
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;
|
||||
}
|
||||
}
|
14
lib/features/profile/view/profile_view.dart
Normal file
|
@ -0,0 +1,14 @@
|
|||
import 'package:cims_apps/application/component/custom_app_bar/custom_app_bar.dart';
|
||||
import 'package:cims_apps/core/utils/size_config.dart';
|
||||
import 'package:flutter/material.dart';
|
||||
|
||||
class ProfileView extends StatelessWidget {
|
||||
const ProfileView({Key? key}) : super(key: key);
|
||||
|
||||
@override
|
||||
Widget build(BuildContext context) {
|
||||
return Scaffold(
|
||||
appBar: CustomAppBar(height: SizeConfig.height * .1, title: 'Profile'),
|
||||
);
|
||||
}
|
||||
}
|
15
lib/features/transaction/view/transaction_view.dart
Normal file
|
@ -0,0 +1,15 @@
|
|||
import 'package:cims_apps/application/component/custom_app_bar/custom_app_bar.dart';
|
||||
import 'package:cims_apps/core/utils/size_config.dart';
|
||||
import 'package:flutter/material.dart';
|
||||
|
||||
class TransactionView extends StatelessWidget {
|
||||
const TransactionView({Key? key}) : super(key: key);
|
||||
|
||||
@override
|
||||
Widget build(BuildContext context) {
|
||||
return Scaffold(
|
||||
appBar:
|
||||
CustomAppBar(height: SizeConfig.height * .1, title: 'Transaction'),
|
||||
);
|
||||
}
|
||||
}
|
|
@ -76,6 +76,10 @@ class MyApp extends StatelessWidget {
|
|||
secondary: const Color(0xFFFECDA6),
|
||||
onBackground: const Color(0xFFA9A9A9),
|
||||
),
|
||||
bottomSheetTheme: BottomSheetThemeData(
|
||||
backgroundColor: Colors.white,
|
||||
surfaceTintColor: Colors.white
|
||||
)
|
||||
// useMaterial3: true,
|
||||
),
|
||||
initialRoute: initialRoute,
|
||||
|
|
48
pubspec.lock
|
@ -264,6 +264,54 @@ packages:
|
|||
description: flutter
|
||||
source: sdk
|
||||
version: "0.0.0"
|
||||
google_identity_services_web:
|
||||
dependency: transitive
|
||||
description:
|
||||
name: google_identity_services_web
|
||||
sha256: "0c56c2c5d60d6dfaf9725f5ad4699f04749fb196ee5a70487a46ef184837ccf6"
|
||||
url: "https://pub.dev"
|
||||
source: hosted
|
||||
version: "0.3.0+2"
|
||||
google_sign_in:
|
||||
dependency: "direct main"
|
||||
description:
|
||||
name: google_sign_in
|
||||
sha256: "0b8787cb9c1a68ad398e8010e8c8766bfa33556d2ab97c439fb4137756d7308f"
|
||||
url: "https://pub.dev"
|
||||
source: hosted
|
||||
version: "6.2.1"
|
||||
google_sign_in_android:
|
||||
dependency: transitive
|
||||
description:
|
||||
name: google_sign_in_android
|
||||
sha256: bfd42c81c30c6faba16e0f62968d5505a87504aaa672b3155ee931461abb0a49
|
||||
url: "https://pub.dev"
|
||||
source: hosted
|
||||
version: "6.1.21"
|
||||
google_sign_in_ios:
|
||||
dependency: transitive
|
||||
description:
|
||||
name: google_sign_in_ios
|
||||
sha256: f3336d9e44d4d28063ac90271f6db5caf99f0480cb07281330e7a432edb95226
|
||||
url: "https://pub.dev"
|
||||
source: hosted
|
||||
version: "5.7.3"
|
||||
google_sign_in_platform_interface:
|
||||
dependency: transitive
|
||||
description:
|
||||
name: google_sign_in_platform_interface
|
||||
sha256: "1f6e5787d7a120cc0359ddf315c92309069171306242e181c09472d1b00a2971"
|
||||
url: "https://pub.dev"
|
||||
source: hosted
|
||||
version: "2.4.5"
|
||||
google_sign_in_web:
|
||||
dependency: transitive
|
||||
description:
|
||||
name: google_sign_in_web
|
||||
sha256: a278ea2d01013faf341cbb093da880d0f2a552bbd1cb6ee90b5bebac9ba69d77
|
||||
url: "https://pub.dev"
|
||||
source: hosted
|
||||
version: "0.12.3+2"
|
||||
group_button:
|
||||
dependency: "direct main"
|
||||
description:
|
||||
|
|
|
@ -52,6 +52,7 @@ dependencies:
|
|||
dotted_border: ^2.1.0
|
||||
shared_preferences: ^2.2.2
|
||||
calendar_date_picker2: ^0.5.3
|
||||
google_sign_in: ^6.2.1
|
||||
|
||||
|
||||
|
||||
|
|