Compare commits
No commits in common. "0a347f5e6dbcc8697cf288d8d7de490f92594f7d" and "6e2516d9c8f5003fe6458761037fb39e50a87a11" have entirely different histories.
0a347f5e6d
...
6e2516d9c8
Before Width: | Height: | Size: 2.9 KiB |
Before Width: | Height: | Size: 3.3 KiB |
Before Width: | Height: | Size: 2.4 KiB |
Before Width: | Height: | Size: 3.9 KiB |
Before Width: | Height: | Size: 154 KiB |
Before Width: | Height: | Size: 636 KiB |
Before Width: | Height: | Size: 1.3 MiB |
Before Width: | Height: | Size: 4.5 KiB |
|
@ -10,10 +10,6 @@ class PathAssets {
|
||||||
static const String iconGoogle = 'assets/icons/icon-google.png';
|
static const String iconGoogle = 'assets/icons/icon-google.png';
|
||||||
static const String icon1 = 'assets/icons/icon-1.png';
|
static const String icon1 = 'assets/icons/icon-1.png';
|
||||||
static const String iconConnect = 'assets/icons/icon-connect.png';
|
static const String iconConnect = 'assets/icons/icon-connect.png';
|
||||||
static const String iconPortofolioBonds = 'assets/icons/icon-portofolio-bonds.png';
|
|
||||||
static const String iconPortofolioShares = 'assets/icons/icon-portofolio-shares.png';
|
|
||||||
static const String iconPortofolioSharia = 'assets/icons/icon-portofolio-sharia.png';
|
|
||||||
static const String iconPortofolioMoneyMarket = 'assets/icons/icon-portofolio-moneymarket.png';
|
|
||||||
static const String iconShield = 'assets/icons/icon-shield.png';
|
static const String iconShield = 'assets/icons/icon-shield.png';
|
||||||
static const String iconFlag = 'assets/icons/icon-flag.png';
|
static const String iconFlag = 'assets/icons/icon-flag.png';
|
||||||
|
|
||||||
|
@ -28,9 +24,5 @@ class PathAssets {
|
||||||
static const String imgKtpCropped = 'assets/images/img-ktp-cropped.png';
|
static const String imgKtpCropped = 'assets/images/img-ktp-cropped.png';
|
||||||
static const String imgKtpClear = 'assets/images/img-ktp-clear.png';
|
static const String imgKtpClear = 'assets/images/img-ktp-clear.png';
|
||||||
static const String imgKtpBlur = 'assets/images/img-ktp-blur.png';
|
static const String imgKtpBlur = 'assets/images/img-ktp-blur.png';
|
||||||
static const String imgDashboardAccount = 'assets/images/img-dashboard-account.png';
|
|
||||||
static const String imgCarousel = 'assets/images/img-carousel.png';
|
|
||||||
static const String imgArticles = 'assets/images/img-articles.png';
|
|
||||||
static const String imgProduct = 'assets/images/img-product.png';
|
|
||||||
static const String imgSuccessSignup = 'assets/images/img-success-signup.png';
|
static const String imgSuccessSignup = 'assets/images/img-success-signup.png';
|
||||||
}
|
}
|
||||||
|
|
|
@ -1,23 +0,0 @@
|
||||||
import 'package:cims_apps/core/utils/size_config.dart';
|
|
||||||
import 'package:flutter/material.dart';
|
|
||||||
|
|
||||||
class ButtonBack extends StatelessWidget {
|
|
||||||
const ButtonBack({super.key});
|
|
||||||
|
|
||||||
@override
|
|
||||||
Widget build(BuildContext context) {
|
|
||||||
return SizedBox(
|
|
||||||
width: SizeConfig.width * 0.1,
|
|
||||||
child: IconButton(
|
|
||||||
style: IconButton.styleFrom(
|
|
||||||
backgroundColor: Colors.white,
|
|
||||||
shape: const CircleBorder()
|
|
||||||
),
|
|
||||||
onPressed: () {
|
|
||||||
Navigator.pop(context);
|
|
||||||
},
|
|
||||||
icon: const Icon(Icons.arrow_back)
|
|
||||||
),
|
|
||||||
);
|
|
||||||
}
|
|
||||||
}
|
|
|
@ -9,14 +9,13 @@ class ButtonView extends StatelessWidget {
|
||||||
final double? height, width, widthSuffix, widthPrefix, marginVertical;
|
final double? height, width, widthSuffix, widthPrefix, marginVertical;
|
||||||
final EdgeInsetsGeometry? contentPadding;
|
final EdgeInsetsGeometry? contentPadding;
|
||||||
final bool isSecondaryColor, isOutlined, heightWrapContent, disabled;
|
final bool isSecondaryColor, isOutlined, heightWrapContent, disabled;
|
||||||
final Color? backgroundColor, textColor, borderColor;
|
final Color? backgroundColor, textColor;
|
||||||
final MainAxisAlignment? mainAxisAlignmentContent;
|
final MainAxisAlignment? mainAxisAlignmentContent;
|
||||||
// final _widthBtn = SizeConfig.screenWidth / 1.5;
|
// final _widthBtn = SizeConfig.screenWidth / 1.5;
|
||||||
final _widthBtn = SizeConfig.width * .9;
|
final _widthBtn = SizeConfig.width * .9;
|
||||||
// final _heightBtn = SizeConfig.screenHeight / 12;
|
// final _heightBtn = SizeConfig.screenHeight / 12;
|
||||||
final _heightBtn = SizeConfig.height * .07;
|
final _heightBtn = SizeConfig.height * .07;
|
||||||
final FontWeight textWeight;
|
final FontWeight textWeight;
|
||||||
final TextAlign textAlign;
|
|
||||||
final double? textSize, sizeBorderRadius;
|
final double? textSize, sizeBorderRadius;
|
||||||
final int? maxLines;
|
final int? maxLines;
|
||||||
|
|
||||||
|
@ -32,11 +31,9 @@ class ButtonView extends StatelessWidget {
|
||||||
this.width,
|
this.width,
|
||||||
this.contentPadding,
|
this.contentPadding,
|
||||||
this.backgroundColor,
|
this.backgroundColor,
|
||||||
this.borderColor,
|
|
||||||
this.textColor,
|
this.textColor,
|
||||||
this.textWeight = FontWeight.bold,
|
this.textWeight = FontWeight.bold,
|
||||||
this.textSize,
|
this.textSize,
|
||||||
this.textAlign = TextAlign.center,
|
|
||||||
this.mainAxisAlignmentContent,
|
this.mainAxisAlignmentContent,
|
||||||
this.disabled = false,
|
this.disabled = false,
|
||||||
this.heightWrapContent = false,
|
this.heightWrapContent = false,
|
||||||
|
@ -78,11 +75,11 @@ class ButtonView extends StatelessWidget {
|
||||||
borderRadius: BorderRadius.circular(sizeBorderRadius ?? 48),
|
borderRadius: BorderRadius.circular(sizeBorderRadius ?? 48),
|
||||||
side: isOutlined
|
side: isOutlined
|
||||||
? BorderSide(
|
? BorderSide(
|
||||||
color: borderColor ?? (disabled
|
color: disabled
|
||||||
? color.surface
|
|
||||||
: isSecondaryColor
|
|
||||||
? ColorPalette.greyBorder
|
? ColorPalette.greyBorder
|
||||||
: ColorPalette.primary),
|
: isSecondaryColor
|
||||||
|
? ColorPalette.greyBorder
|
||||||
|
: ColorPalette.primary,
|
||||||
)
|
)
|
||||||
: BorderSide.none,
|
: BorderSide.none,
|
||||||
),
|
),
|
||||||
|
@ -104,7 +101,7 @@ class ButtonView extends StatelessWidget {
|
||||||
Flexible(
|
Flexible(
|
||||||
child: Text(
|
child: Text(
|
||||||
name,
|
name,
|
||||||
textAlign: textAlign,
|
textAlign: TextAlign.center,
|
||||||
maxLines: maxLines,
|
maxLines: maxLines,
|
||||||
overflow: TextOverflow.ellipsis,
|
overflow: TextOverflow.ellipsis,
|
||||||
style: TextStyle(
|
style: TextStyle(
|
||||||
|
|
|
@ -1,26 +0,0 @@
|
||||||
import 'package:cims_apps/application/theme/color_palette.dart';
|
|
||||||
import 'package:flutter/cupertino.dart';
|
|
||||||
|
|
||||||
class TextTitle extends StatelessWidget {
|
|
||||||
final String title;
|
|
||||||
final Color? color;
|
|
||||||
final double? fontSize;
|
|
||||||
const TextTitle({
|
|
||||||
Key? key,
|
|
||||||
required this.title,
|
|
||||||
this.color,
|
|
||||||
this.fontSize,
|
|
||||||
}) : super(key: key);
|
|
||||||
|
|
||||||
@override
|
|
||||||
Widget build(BuildContext context) {
|
|
||||||
return Text(
|
|
||||||
title,
|
|
||||||
style: TextStyle(
|
|
||||||
fontSize: fontSize ?? 20,
|
|
||||||
fontWeight: FontWeight.w700,
|
|
||||||
color: color ?? ColorPalette.slate800,
|
|
||||||
),
|
|
||||||
);
|
|
||||||
}
|
|
||||||
}
|
|
|
@ -74,37 +74,5 @@ class ColorPalette {
|
||||||
static const Color background = Color(0xFFDADADA);
|
static const Color background = Color(0xFFDADADA);
|
||||||
static const Color backgroundBlueLight = Color(0xFFEBF3FD);
|
static const Color backgroundBlueLight = Color(0xFFEBF3FD);
|
||||||
static const Color slate500 = Color(0xFF64748B);
|
static const Color slate500 = Color(0xFF64748B);
|
||||||
static const Color blue50 = Color(0xFFEFF6FF);
|
|
||||||
static const Color blue200 = Color(0xFFBFDBFE);
|
|
||||||
static const Color slate50 = Color(0xFFF8FAFC);
|
|
||||||
static const Color slate200 = Color(0xFFE2E8F0);
|
|
||||||
static const Color slate300 = Color(0xFFCBD5E1);
|
|
||||||
static const Color slate400 = Color(0xFF94A3B8);
|
|
||||||
static const Color slate500 = Color(0xFF64748B);
|
|
||||||
static const Color slate800 = Color(0xFF1E293B);
|
static const Color slate800 = Color(0xFF1E293B);
|
||||||
static const Color purple100 = Color(0xFFEDE9FE);
|
|
||||||
static const Color purple500 = Color(0xFF8B5CF6);
|
|
||||||
static const Color orange50 = Color(0xFFFFF7ED);
|
|
||||||
static const Color orange100 = Color(0xFFFFEDD5);
|
|
||||||
static const Color orange500 = Color(0xFFF97316);
|
|
||||||
static const Color cyan100 = Color(0xFFCFFAFE);
|
|
||||||
static const Color cyan500 = Color(0xFF06B6D4);
|
|
||||||
static const Color green100 = Color(0xFFDCFCE7);
|
|
||||||
static const Color green400 = Color(0xFF4ADE80);
|
|
||||||
static const Color green500 = Color(0xFF16A34A);
|
|
||||||
|
|
||||||
|
|
||||||
static const Map<String, Color> investTypeColor = {
|
|
||||||
'Money Market': purple500,
|
|
||||||
'Shares': orange500,
|
|
||||||
'Sharia': green500,
|
|
||||||
'Bonds': cyan500
|
|
||||||
};
|
|
||||||
|
|
||||||
static const Map<String, Color> investTypeBgColor = {
|
|
||||||
'Money Market': purple100,
|
|
||||||
'Shares': orange100,
|
|
||||||
'Sharia': green100,
|
|
||||||
'Bonds': cyan100
|
|
||||||
};
|
|
||||||
}
|
}
|
||||||
|
|
|
@ -1,3 +0,0 @@
|
||||||
class DateFormatter {
|
|
||||||
|
|
||||||
}
|
|
|
@ -1,19 +0,0 @@
|
||||||
import 'package:intl/intl.dart';
|
|
||||||
|
|
||||||
class NumberFormatter {
|
|
||||||
NumberFormatter._();
|
|
||||||
|
|
||||||
static String numberCurrency(dynamic value, String symbol, String locale, {int? decimalDigits = 2}) {
|
|
||||||
NumberFormat numberFormat = NumberFormat.currency(locale: locale, symbol: symbol, decimalDigits: decimalDigits);
|
|
||||||
String formatValue = numberFormat.format(value);
|
|
||||||
|
|
||||||
return formatValue;
|
|
||||||
}
|
|
||||||
|
|
||||||
static compactCurrency(dynamic value, String symbol, String locale) {
|
|
||||||
NumberFormat numberFormat = NumberFormat.compactCurrency(locale: locale, symbol: symbol);
|
|
||||||
String formatValue = numberFormat.format(value);
|
|
||||||
|
|
||||||
return formatValue;
|
|
||||||
}
|
|
||||||
}
|
|
|
@ -1,6 +1,4 @@
|
||||||
import 'package:cims_apps/application/theme/color_palette.dart';
|
import 'package:cims_apps/application/theme/color_palette.dart';
|
||||||
import 'package:cims_apps/features/dashboard/dashboard_account/view/homepage/homepage_view.dart';
|
|
||||||
import 'package:cims_apps/features/dashboard/dashboard_account/view/portfolio/portfolio_view.dart';
|
|
||||||
import 'package:flutter/material.dart';
|
import 'package:flutter/material.dart';
|
||||||
|
|
||||||
class BottomNavigationView extends StatefulWidget {
|
class BottomNavigationView extends StatefulWidget {
|
||||||
|
@ -17,12 +15,15 @@ class _BottomNavigationViewState extends State<BottomNavigationView> {
|
||||||
Widget build(BuildContext context) {
|
Widget build(BuildContext context) {
|
||||||
///TODO: masukan pagenya dilistWidget ini
|
///TODO: masukan pagenya dilistWidget ini
|
||||||
List<Widget> listWidget = [
|
List<Widget> listWidget = [
|
||||||
HomeView(),
|
Container(
|
||||||
|
color: Colors.amberAccent,
|
||||||
|
),
|
||||||
Container(
|
Container(
|
||||||
color: Colors.redAccent,
|
color: Colors.redAccent,
|
||||||
),
|
),
|
||||||
Container(),
|
Container(),
|
||||||
PortofolioView(),
|
Container(),
|
||||||
|
Container(),
|
||||||
Container(),
|
Container(),
|
||||||
];
|
];
|
||||||
|
|
||||||
|
@ -59,7 +60,6 @@ class _BottomNavigationViewState extends State<BottomNavigationView> {
|
||||||
},
|
},
|
||||||
currentIndex: _selectedIndex,
|
currentIndex: _selectedIndex,
|
||||||
items: listNavigation,
|
items: listNavigation,
|
||||||
type: BottomNavigationBarType.fixed,
|
|
||||||
showUnselectedLabels: true,
|
showUnselectedLabels: true,
|
||||||
selectedItemColor: ColorPalette.primary,
|
selectedItemColor: ColorPalette.primary,
|
||||||
unselectedItemColor: Colors.black,
|
unselectedItemColor: Colors.black,
|
||||||
|
|
|
@ -1,529 +0,0 @@
|
||||||
import 'package:carousel_slider/carousel_slider.dart';
|
|
||||||
import 'package:cims_apps/application/assets/path_assets.dart';
|
|
||||||
import 'package:cims_apps/application/component/image/image_view.dart';
|
|
||||||
import 'package:cims_apps/application/component/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/dashboard/dashboard_account/view/invest_type/invest_type_view.dart';
|
|
||||||
import 'package:flutter/material.dart';
|
|
||||||
|
|
||||||
class InvestType {
|
|
||||||
String name;
|
|
||||||
String iconImage;
|
|
||||||
|
|
||||||
InvestType(this.name, this.iconImage);
|
|
||||||
}
|
|
||||||
|
|
||||||
class StepVerification {
|
|
||||||
int currentStep;
|
|
||||||
List<String> nameStep;
|
|
||||||
|
|
||||||
StepVerification(this.currentStep, this.nameStep);
|
|
||||||
}
|
|
||||||
|
|
||||||
class Article {
|
|
||||||
String image;
|
|
||||||
String title;
|
|
||||||
String type;
|
|
||||||
|
|
||||||
Article(this.type, this.title, this.image);
|
|
||||||
}
|
|
||||||
|
|
||||||
class HomeView extends StatefulWidget {
|
|
||||||
const HomeView({super.key});
|
|
||||||
|
|
||||||
@override
|
|
||||||
State<HomeView> createState() => _HomeViewState();
|
|
||||||
}
|
|
||||||
|
|
||||||
class _HomeViewState extends State<HomeView> {
|
|
||||||
bool seePortofolioValue = false;
|
|
||||||
|
|
||||||
List<InvestType> listPortofolioType = [
|
|
||||||
InvestType('Money Market', PathAssets.iconPortofolioMoneyMarket),
|
|
||||||
InvestType('Shares', PathAssets.iconPortofolioShares),
|
|
||||||
InvestType('Bonds', PathAssets.iconPortofolioBonds),
|
|
||||||
InvestType('Sharia', PathAssets.iconPortofolioSharia)
|
|
||||||
];
|
|
||||||
|
|
||||||
StepVerification listStepVerification = StepVerification(1, [
|
|
||||||
'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),
|
|
||||||
];
|
|
||||||
|
|
||||||
@override
|
|
||||||
Widget build(BuildContext context) {
|
|
||||||
return Scaffold(
|
|
||||||
backgroundColor: const Color(0xffF8FAFC),
|
|
||||||
body: SizedBox(
|
|
||||||
width: SizeConfig.width,
|
|
||||||
height: SizeConfig.height,
|
|
||||||
child: Stack(
|
|
||||||
children: [
|
|
||||||
const ImageView(image: PathAssets.imgDashboardAccount),
|
|
||||||
Column(
|
|
||||||
children: [
|
|
||||||
const SizedBox(
|
|
||||||
height: 50,
|
|
||||||
),
|
|
||||||
Padding(
|
|
||||||
padding: const EdgeInsets.only(left: 24, right: 16),
|
|
||||||
child: Row(
|
|
||||||
mainAxisAlignment: MainAxisAlignment.spaceBetween,
|
|
||||||
children: [
|
|
||||||
const Text(
|
|
||||||
'Home',
|
|
||||||
style: TextStyle(
|
|
||||||
color: Colors.white,
|
|
||||||
fontSize: 20,
|
|
||||||
fontWeight: FontWeight.w700
|
|
||||||
),
|
|
||||||
),
|
|
||||||
ElevatedButton(
|
|
||||||
onPressed: () {
|
|
||||||
|
|
||||||
},
|
|
||||||
style: ElevatedButton.styleFrom(
|
|
||||||
padding: const EdgeInsets.all(0),
|
|
||||||
backgroundColor: Colors.white,
|
|
||||||
foregroundColor: const Color(0xff2563EB),
|
|
||||||
elevation: 0,
|
|
||||||
shape: const CircleBorder()
|
|
||||||
),
|
|
||||||
child: const Icon(Icons.notifications_outlined)
|
|
||||||
)
|
|
||||||
],
|
|
||||||
),
|
|
||||||
),
|
|
||||||
const SizedBox(
|
|
||||||
height: 32,
|
|
||||||
),
|
|
||||||
Padding(
|
|
||||||
padding: const EdgeInsets.symmetric(horizontal: 24),
|
|
||||||
child: portofolioValue(),
|
|
||||||
),
|
|
||||||
const SizedBox(
|
|
||||||
height: 24,
|
|
||||||
),
|
|
||||||
cardInvestType(),
|
|
||||||
const SizedBox(
|
|
||||||
height: 32,
|
|
||||||
),
|
|
||||||
Expanded(
|
|
||||||
child: ListView(
|
|
||||||
padding: const EdgeInsets.all(0),
|
|
||||||
children: [
|
|
||||||
cardVerification(),
|
|
||||||
const SizedBox(
|
|
||||||
height: 24,
|
|
||||||
),
|
|
||||||
infoAndPromo(),
|
|
||||||
const SizedBox(
|
|
||||||
height: 24,
|
|
||||||
),
|
|
||||||
articles(),
|
|
||||||
],
|
|
||||||
),
|
|
||||||
),
|
|
||||||
],
|
|
||||||
)
|
|
||||||
],
|
|
||||||
),
|
|
||||||
),
|
|
||||||
);
|
|
||||||
}
|
|
||||||
|
|
||||||
Widget portofolioValue() {
|
|
||||||
return Column(
|
|
||||||
crossAxisAlignment: CrossAxisAlignment.start,
|
|
||||||
children: [
|
|
||||||
Row(
|
|
||||||
children: [
|
|
||||||
const Text('Portofolio Value', style: TextStyle(color: Colors.white)),
|
|
||||||
const SizedBox(
|
|
||||||
width: 12,
|
|
||||||
),
|
|
||||||
GestureDetector(
|
|
||||||
onTap: () {
|
|
||||||
setState(() {
|
|
||||||
seePortofolioValue = !seePortofolioValue;
|
|
||||||
});
|
|
||||||
},
|
|
||||||
child: const Icon(Icons.visibility_outlined, color: Color(0xff93C5FD))
|
|
||||||
)
|
|
||||||
],
|
|
||||||
),
|
|
||||||
const SizedBox(
|
|
||||||
height: 4,
|
|
||||||
),
|
|
||||||
Row(
|
|
||||||
children: [
|
|
||||||
AnimatedCrossFade(
|
|
||||||
duration: const Duration(milliseconds: 300),
|
|
||||||
alignment: Alignment.center,
|
|
||||||
crossFadeState: seePortofolioValue ? CrossFadeState.showSecond : CrossFadeState.showFirst,
|
|
||||||
firstChild: RichText(
|
|
||||||
text: const TextSpan(
|
|
||||||
text: 'Rp ',
|
|
||||||
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',
|
|
||||||
),
|
|
||||||
)
|
|
||||||
]
|
|
||||||
)
|
|
||||||
),
|
|
||||||
secondChild: Padding(
|
|
||||||
padding: const EdgeInsets.symmetric(vertical: 16),
|
|
||||||
child: Wrap(
|
|
||||||
spacing: 7,
|
|
||||||
children: [
|
|
||||||
for (int i = 0; i < 6; i++)
|
|
||||||
Container(
|
|
||||||
width: 12,
|
|
||||||
height: 12,
|
|
||||||
decoration: const BoxDecoration(color: Colors.white, shape: BoxShape.circle),
|
|
||||||
),
|
|
||||||
],
|
|
||||||
),
|
|
||||||
),
|
|
||||||
),
|
|
||||||
],
|
|
||||||
)
|
|
||||||
],
|
|
||||||
);
|
|
||||||
}
|
|
||||||
|
|
||||||
Widget cardInvestType() {
|
|
||||||
return Container(
|
|
||||||
padding: const EdgeInsets.all(16),
|
|
||||||
decoration: BoxDecoration(
|
|
||||||
color: Colors.white,
|
|
||||||
borderRadius: BorderRadius.circular(12),
|
|
||||||
boxShadow: [
|
|
||||||
BoxShadow(
|
|
||||||
spreadRadius: 2,
|
|
||||||
blurRadius: 4,
|
|
||||||
color: const Color(0xff1E293B).withOpacity(0.04)
|
|
||||||
)
|
|
||||||
]
|
|
||||||
),
|
|
||||||
child: Wrap(
|
|
||||||
spacing: 10,
|
|
||||||
children: listPortofolioType.asMap().entries.map((e) {
|
|
||||||
return GestureDetector(
|
|
||||||
onTap: () {
|
|
||||||
routePush(context, page: InvestTypeView(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,),
|
|
||||||
const SizedBox(
|
|
||||||
height: 8,
|
|
||||||
),
|
|
||||||
Text(
|
|
||||||
e.value.name,
|
|
||||||
overflow: TextOverflow.ellipsis,
|
|
||||||
textAlign: TextAlign.center,
|
|
||||||
style: const TextStyle(
|
|
||||||
fontSize: 12,
|
|
||||||
fontWeight: FontWeight.w600
|
|
||||||
),
|
|
||||||
)
|
|
||||||
],
|
|
||||||
),
|
|
||||||
),
|
|
||||||
);
|
|
||||||
}).toList(),
|
|
||||||
),
|
|
||||||
);
|
|
||||||
}
|
|
||||||
|
|
||||||
Widget cardVerification() {
|
|
||||||
return Container(
|
|
||||||
margin: const EdgeInsets.symmetric(horizontal: 24),
|
|
||||||
padding: const EdgeInsets.all(16),
|
|
||||||
decoration: BoxDecoration(
|
|
||||||
color: Colors.white,
|
|
||||||
borderRadius: BorderRadius.circular(12),
|
|
||||||
),
|
|
||||||
child: Column(
|
|
||||||
children: [
|
|
||||||
stepVerification(),
|
|
||||||
const SizedBox(
|
|
||||||
height: 24,
|
|
||||||
),
|
|
||||||
Row(
|
|
||||||
mainAxisAlignment: MainAxisAlignment.spaceBetween,
|
|
||||||
children: [
|
|
||||||
const Row(
|
|
||||||
children: [
|
|
||||||
Icon(Icons.verified, size: 18,),
|
|
||||||
SizedBox(
|
|
||||||
width: 12,
|
|
||||||
),
|
|
||||||
Text(
|
|
||||||
'Verified by PT Gemilang',
|
|
||||||
style: TextStyle(
|
|
||||||
color: ColorPalette.slate500
|
|
||||||
),
|
|
||||||
)
|
|
||||||
],
|
|
||||||
),
|
|
||||||
Container(
|
|
||||||
width: 16,
|
|
||||||
height: 16,
|
|
||||||
decoration: BoxDecoration(
|
|
||||||
color: Colors.white,
|
|
||||||
border: Border.all(color: const Color(0xffCBD5E1), width: 1.5),
|
|
||||||
shape: BoxShape.circle
|
|
||||||
),
|
|
||||||
)
|
|
||||||
],
|
|
||||||
),
|
|
||||||
const SizedBox(
|
|
||||||
height: 16,
|
|
||||||
),
|
|
||||||
Row(
|
|
||||||
mainAxisAlignment: MainAxisAlignment.spaceBetween,
|
|
||||||
children: [
|
|
||||||
const Row(
|
|
||||||
crossAxisAlignment: CrossAxisAlignment.end,
|
|
||||||
children: [
|
|
||||||
Icon(Icons.verified, size: 18,),
|
|
||||||
SizedBox(
|
|
||||||
width: 12,
|
|
||||||
),
|
|
||||||
Text(
|
|
||||||
'Verified by KSEI',
|
|
||||||
style: TextStyle(
|
|
||||||
color: ColorPalette.slate500
|
|
||||||
),
|
|
||||||
)
|
|
||||||
],
|
|
||||||
),
|
|
||||||
Container(
|
|
||||||
width: 16,
|
|
||||||
height: 16,
|
|
||||||
decoration: BoxDecoration(
|
|
||||||
color: Colors.white,
|
|
||||||
border: Border.all(color: const Color(0xffCBD5E1), width: 1.5),
|
|
||||||
shape: BoxShape.circle
|
|
||||||
),
|
|
||||||
)
|
|
||||||
],
|
|
||||||
),
|
|
||||||
const SizedBox(
|
|
||||||
height: 16,
|
|
||||||
),
|
|
||||||
Container(
|
|
||||||
padding: const EdgeInsets.all(12),
|
|
||||||
decoration: BoxDecoration(
|
|
||||||
color: ColorPalette.blue50,
|
|
||||||
borderRadius: BorderRadius.circular(12)
|
|
||||||
),
|
|
||||||
child: const Column(
|
|
||||||
children: [
|
|
||||||
Text(
|
|
||||||
'Your registration is currently being verified by PT Gemilang',
|
|
||||||
style: TextStyle(
|
|
||||||
color: ColorPalette.slate500
|
|
||||||
),
|
|
||||||
),
|
|
||||||
SizedBox(
|
|
||||||
height: 16,
|
|
||||||
),
|
|
||||||
Row(
|
|
||||||
mainAxisAlignment: MainAxisAlignment.spaceBetween,
|
|
||||||
children: [
|
|
||||||
Text('Estimated:',
|
|
||||||
style: TextStyle(
|
|
||||||
color: ColorPalette.slate500
|
|
||||||
),
|
|
||||||
),
|
|
||||||
Text(
|
|
||||||
'January 30 2024',
|
|
||||||
style: TextStyle(
|
|
||||||
fontWeight: FontWeight.w600,
|
|
||||||
color: Color(0xff1E293B)
|
|
||||||
),
|
|
||||||
)
|
|
||||||
],
|
|
||||||
)
|
|
||||||
],
|
|
||||||
),
|
|
||||||
)
|
|
||||||
],
|
|
||||||
),
|
|
||||||
);
|
|
||||||
}
|
|
||||||
|
|
||||||
Widget stepVerification() {
|
|
||||||
return Row(
|
|
||||||
mainAxisAlignment: MainAxisAlignment.spaceBetween,
|
|
||||||
children: listStepVerification.nameStep.asMap().entries.map((e) {
|
|
||||||
return Row(
|
|
||||||
crossAxisAlignment: CrossAxisAlignment.start,
|
|
||||||
children: [
|
|
||||||
if(e.key != 0)
|
|
||||||
SizedBox(
|
|
||||||
width: 30,
|
|
||||||
height: 30,
|
|
||||||
child: Divider(color: listStepVerification.currentStep >= e.key ? const Color(0xff2563EB) : const Color(0xffCBD5E1),),
|
|
||||||
),
|
|
||||||
Column(
|
|
||||||
children: [
|
|
||||||
Container(
|
|
||||||
width: 30,
|
|
||||||
height: 30,
|
|
||||||
decoration: BoxDecoration(
|
|
||||||
shape: BoxShape.circle,
|
|
||||||
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,),
|
|
||||||
),
|
|
||||||
const SizedBox(
|
|
||||||
height: 8,
|
|
||||||
),
|
|
||||||
Text(e.value, style: TextStyle(color: listStepVerification.currentStep == e.key ? const Color(0xff2563EB) : Colors.black),)
|
|
||||||
],
|
|
||||||
),
|
|
||||||
],
|
|
||||||
);
|
|
||||||
}).toList(),
|
|
||||||
);
|
|
||||||
}
|
|
||||||
|
|
||||||
Widget infoAndPromo() {
|
|
||||||
return Padding(
|
|
||||||
padding: const EdgeInsets.symmetric(horizontal: 24),
|
|
||||||
child: Column(
|
|
||||||
crossAxisAlignment: CrossAxisAlignment.start,
|
|
||||||
children: [
|
|
||||||
const TextTitle(title: 'Info and Special Promo', color: ColorPalette.slate800,),
|
|
||||||
const SizedBox(
|
|
||||||
height: 16,
|
|
||||||
),
|
|
||||||
CarouselSlider(
|
|
||||||
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,),
|
|
||||||
);
|
|
||||||
}).toList(),
|
|
||||||
options: CarouselOptions(
|
|
||||||
height: 150,
|
|
||||||
autoPlay: true,
|
|
||||||
pageSnapping: true,
|
|
||||||
viewportFraction: 0.9,
|
|
||||||
autoPlayInterval: const Duration(seconds: 5),
|
|
||||||
autoPlayCurve: Curves.fastOutSlowIn,
|
|
||||||
),
|
|
||||||
)
|
|
||||||
],
|
|
||||||
),
|
|
||||||
);
|
|
||||||
}
|
|
||||||
|
|
||||||
Widget articles() {
|
|
||||||
return Container(
|
|
||||||
color: Colors.white,
|
|
||||||
padding: const EdgeInsets.symmetric(vertical: 24),
|
|
||||||
child: Column(
|
|
||||||
children: [
|
|
||||||
Padding(
|
|
||||||
padding: const EdgeInsets.symmetric(horizontal: 24),
|
|
||||||
child: Row(
|
|
||||||
mainAxisAlignment: MainAxisAlignment.spaceBetween,
|
|
||||||
children: [
|
|
||||||
const TextTitle(title: 'Article', color: ColorPalette.slate800),
|
|
||||||
GestureDetector(
|
|
||||||
onTap: () {
|
|
||||||
|
|
||||||
},
|
|
||||||
child: const Text('See More',
|
|
||||||
style: TextStyle(
|
|
||||||
color: ColorPalette.primary,
|
|
||||||
fontWeight: FontWeight.bold
|
|
||||||
),),
|
|
||||||
)
|
|
||||||
],
|
|
||||||
),
|
|
||||||
),
|
|
||||||
const SizedBox(
|
|
||||||
height: 16,
|
|
||||||
),
|
|
||||||
...listArticle.asMap().entries.map((e) {
|
|
||||||
return Column(
|
|
||||||
children: [
|
|
||||||
if(e.key != 0)...[
|
|
||||||
const Padding(
|
|
||||||
padding: EdgeInsets.symmetric(vertical: 12),
|
|
||||||
child: Divider(color: ColorPalette.slate200,),
|
|
||||||
)
|
|
||||||
],
|
|
||||||
cardArticle(e.value),
|
|
||||||
],
|
|
||||||
);
|
|
||||||
})
|
|
||||||
],
|
|
||||||
),
|
|
||||||
);
|
|
||||||
}
|
|
||||||
|
|
||||||
Widget cardArticle(Article article) {
|
|
||||||
return Padding(
|
|
||||||
padding: const EdgeInsets.symmetric(horizontal: 24),
|
|
||||||
child: Row(
|
|
||||||
children: [
|
|
||||||
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,
|
|
||||||
),
|
|
||||||
),
|
|
||||||
const SizedBox(
|
|
||||||
height: 8,
|
|
||||||
),
|
|
||||||
Container(
|
|
||||||
padding: const EdgeInsets.symmetric(vertical: 4, horizontal: 12),
|
|
||||||
decoration: BoxDecoration(
|
|
||||||
borderRadius: BorderRadius.circular(30),
|
|
||||||
color: ColorPalette.colorSwitchButtonActive
|
|
||||||
),
|
|
||||||
child: Text(article.type),
|
|
||||||
),
|
|
||||||
],
|
|
||||||
)
|
|
||||||
)
|
|
||||||
],
|
|
||||||
),
|
|
||||||
);
|
|
||||||
}
|
|
||||||
}
|
|
|
@ -1,236 +0,0 @@
|
||||||
import 'package:cims_apps/application/assets/path_assets.dart';
|
|
||||||
import 'package:cims_apps/application/component/button/button_back.dart';
|
|
||||||
import 'package:cims_apps/application/component/image/image_view.dart';
|
|
||||||
import 'package:cims_apps/application/component/text_title/text_title.dart';
|
|
||||||
import 'package:cims_apps/application/theme/color_palette.dart';
|
|
||||||
import 'package:cims_apps/core/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:flutter/material.dart';
|
|
||||||
|
|
||||||
class Product {
|
|
||||||
String name;
|
|
||||||
double yield;
|
|
||||||
double priceUnit;
|
|
||||||
double funds;
|
|
||||||
|
|
||||||
Product(this.name, this.yield, this.priceUnit, this.funds);
|
|
||||||
}
|
|
||||||
|
|
||||||
class InvestTypeView extends StatefulWidget {
|
|
||||||
final String title;
|
|
||||||
const InvestTypeView(this.title, {super.key});
|
|
||||||
|
|
||||||
@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)
|
|
||||||
];
|
|
||||||
|
|
||||||
@override
|
|
||||||
Widget build(BuildContext context) {
|
|
||||||
return Scaffold(
|
|
||||||
body: SizedBox(
|
|
||||||
width: SizeConfig.width,
|
|
||||||
height: SizeConfig.height,
|
|
||||||
child: Stack(
|
|
||||||
children: [
|
|
||||||
const ImageView(image: PathAssets.imgDashboardAccount),
|
|
||||||
Column(
|
|
||||||
children: [
|
|
||||||
const SizedBox(
|
|
||||||
height: 50,
|
|
||||||
),
|
|
||||||
Padding(
|
|
||||||
padding: const EdgeInsets.symmetric(horizontal: 24),
|
|
||||||
child: Row(
|
|
||||||
mainAxisAlignment: MainAxisAlignment.spaceBetween,
|
|
||||||
children: [
|
|
||||||
const ButtonBack(),
|
|
||||||
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(),
|
|
||||||
)
|
|
||||||
],
|
|
||||||
),
|
|
||||||
),
|
|
||||||
],
|
|
||||||
)
|
|
||||||
],
|
|
||||||
),
|
|
||||||
),
|
|
||||||
);
|
|
||||||
}
|
|
||||||
|
|
||||||
Widget filters() {
|
|
||||||
return Padding(
|
|
||||||
padding: const EdgeInsets.symmetric(horizontal: 8),
|
|
||||||
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', () { }),
|
|
||||||
],
|
|
||||||
),
|
|
||||||
);
|
|
||||||
}
|
|
||||||
|
|
||||||
Widget segmentFilter(Widget leading, String text, void Function()? onTap) {
|
|
||||||
return GestureDetector(
|
|
||||||
onTap: onTap,
|
|
||||||
child: Container(
|
|
||||||
padding: const EdgeInsets.symmetric(vertical: 8, horizontal: 16),
|
|
||||||
decoration: BoxDecoration(
|
|
||||||
border: Border.all(color: ColorPalette.slate200),
|
|
||||||
borderRadius: BorderRadius.circular(56)
|
|
||||||
),
|
|
||||||
child: Row(
|
|
||||||
children: [
|
|
||||||
leading,
|
|
||||||
const SizedBox(
|
|
||||||
width: 4,
|
|
||||||
),
|
|
||||||
Text(
|
|
||||||
text,
|
|
||||||
overflow: TextOverflow.ellipsis,
|
|
||||||
style: const TextStyle(
|
|
||||||
color: ColorPalette.slate500,
|
|
||||||
fontWeight: FontWeight.w700
|
|
||||||
),
|
|
||||||
)
|
|
||||||
],
|
|
||||||
),
|
|
||||||
),
|
|
||||||
);
|
|
||||||
}
|
|
||||||
|
|
||||||
Widget cardProduct(Product product) {
|
|
||||||
return Container(
|
|
||||||
padding: const EdgeInsets.all(16),
|
|
||||||
decoration: BoxDecoration(
|
|
||||||
borderRadius: BorderRadius.circular(12),
|
|
||||||
border: Border.all(color: ColorPalette.slate200),
|
|
||||||
),
|
|
||||||
child: Column(
|
|
||||||
children: [
|
|
||||||
Row(
|
|
||||||
children: [
|
|
||||||
ImageView(image: PathAssets.imgProduct, width: SizeConfig.width * .12,),
|
|
||||||
const SizedBox(
|
|
||||||
width: 8,
|
|
||||||
),
|
|
||||||
Expanded(
|
|
||||||
child: Text(
|
|
||||||
product.name,
|
|
||||||
style: const TextStyle(
|
|
||||||
fontWeight: FontWeight.bold,
|
|
||||||
fontSize: 18
|
|
||||||
),
|
|
||||||
),
|
|
||||||
)
|
|
||||||
],
|
|
||||||
),
|
|
||||||
const Padding(
|
|
||||||
padding: EdgeInsets.symmetric(vertical: 12),
|
|
||||||
child: Divider(color: ColorPalette.slate200),
|
|
||||||
),
|
|
||||||
Row(
|
|
||||||
mainAxisAlignment: MainAxisAlignment.spaceBetween,
|
|
||||||
children: [
|
|
||||||
Column(
|
|
||||||
children: [
|
|
||||||
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
|
|
||||||
),
|
|
||||||
),
|
|
||||||
const Text('/'),
|
|
||||||
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),),
|
|
||||||
Row(
|
|
||||||
children: [
|
|
||||||
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
|
|
||||||
),
|
|
||||||
),
|
|
||||||
],
|
|
||||||
)
|
|
||||||
],
|
|
||||||
),
|
|
||||||
Column(
|
|
||||||
children: [
|
|
||||||
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
|
|
||||||
),
|
|
||||||
),
|
|
||||||
],
|
|
||||||
)
|
|
||||||
],
|
|
||||||
)
|
|
||||||
],
|
|
||||||
)
|
|
||||||
],
|
|
||||||
),
|
|
||||||
);
|
|
||||||
}
|
|
||||||
|
|
||||||
}
|
|
|
@ -1,347 +0,0 @@
|
||||||
import 'package:cims_apps/application/assets/path_assets.dart';
|
|
||||||
import 'package:cims_apps/application/component/image/image_view.dart';
|
|
||||||
import 'package:cims_apps/application/theme/color_palette.dart';
|
|
||||||
import 'package:cims_apps/core/utils/size_config.dart';
|
|
||||||
import 'package:fl_chart/fl_chart.dart';
|
|
||||||
import 'package:flutter/material.dart';
|
|
||||||
|
|
||||||
class CategoryPortofolio {
|
|
||||||
String name;
|
|
||||||
int value;
|
|
||||||
|
|
||||||
CategoryPortofolio(this.value, this.name);
|
|
||||||
}
|
|
||||||
|
|
||||||
class PortofolioView extends StatefulWidget {
|
|
||||||
const PortofolioView({super.key});
|
|
||||||
|
|
||||||
@override
|
|
||||||
State<PortofolioView> createState() => _PortofolioViewState();
|
|
||||||
}
|
|
||||||
|
|
||||||
class _PortofolioViewState extends State<PortofolioView> {
|
|
||||||
List<Color> contentColor = [
|
|
||||||
ColorPalette.purple500,
|
|
||||||
ColorPalette.orange500,
|
|
||||||
ColorPalette.cyan500,
|
|
||||||
ColorPalette.green500,
|
|
||||||
];
|
|
||||||
List<Color> bgContentColor = [
|
|
||||||
ColorPalette.purple100,
|
|
||||||
ColorPalette.orange100,
|
|
||||||
ColorPalette.cyan100,
|
|
||||||
ColorPalette.green100,
|
|
||||||
];
|
|
||||||
|
|
||||||
bool seePortofolioValue = false;
|
|
||||||
int touchedIndex = -1;
|
|
||||||
|
|
||||||
List<CategoryPortofolio> listCategoryPortofolio = [
|
|
||||||
CategoryPortofolio(20, 'Money Market'),
|
|
||||||
CategoryPortofolio(15, 'Shares'),
|
|
||||||
CategoryPortofolio(8, 'Bonds'),
|
|
||||||
CategoryPortofolio(50, 'Sharia'),
|
|
||||||
];
|
|
||||||
|
|
||||||
List<String> assetsImage = [
|
|
||||||
PathAssets.iconPortofolioMoneyMarket,
|
|
||||||
PathAssets.iconPortofolioShares,
|
|
||||||
PathAssets.iconPortofolioBonds,
|
|
||||||
PathAssets.iconPortofolioSharia,
|
|
||||||
];
|
|
||||||
|
|
||||||
@override
|
|
||||||
Widget build(BuildContext context) {
|
|
||||||
return Scaffold(
|
|
||||||
backgroundColor: Colors.white,
|
|
||||||
body: SizedBox(
|
|
||||||
width: SizeConfig.width,
|
|
||||||
height: SizeConfig.height,
|
|
||||||
child: Stack(
|
|
||||||
children: [
|
|
||||||
const ImageView(image: PathAssets.imgDashboardAccount),
|
|
||||||
Column(
|
|
||||||
children: [
|
|
||||||
const SizedBox(
|
|
||||||
height: 50,
|
|
||||||
),
|
|
||||||
const Center(
|
|
||||||
child: Text(
|
|
||||||
'Portofolio',
|
|
||||||
style: TextStyle(
|
|
||||||
fontSize: 20,
|
|
||||||
fontWeight: FontWeight.w700,
|
|
||||||
color: Colors.white),
|
|
||||||
),
|
|
||||||
),
|
|
||||||
const SizedBox(
|
|
||||||
height: 40,
|
|
||||||
),
|
|
||||||
Padding(
|
|
||||||
padding: const EdgeInsets.symmetric(horizontal: 24),
|
|
||||||
child: portofolioValue(),
|
|
||||||
),
|
|
||||||
Expanded(
|
|
||||||
child: Container(
|
|
||||||
margin: const EdgeInsets.only(top: 24),
|
|
||||||
decoration: const BoxDecoration(
|
|
||||||
color: Colors.white,
|
|
||||||
borderRadius: BorderRadius.only(
|
|
||||||
topLeft: Radius.circular(24),
|
|
||||||
topRight: Radius.circular(24)),
|
|
||||||
),
|
|
||||||
child: ListView(
|
|
||||||
padding: const EdgeInsets.symmetric(vertical: 0),
|
|
||||||
children: [
|
|
||||||
Stack(alignment: Alignment.center, children: [
|
|
||||||
AspectRatio(
|
|
||||||
aspectRatio: 1.3,
|
|
||||||
child: PieChart(PieChartData(
|
|
||||||
pieTouchData: PieTouchData(
|
|
||||||
touchCallback:
|
|
||||||
(FlTouchEvent event, pieTouchResponse) {
|
|
||||||
setState(() {
|
|
||||||
if (!event.isInterestedForInteractions ||
|
|
||||||
pieTouchResponse == null ||
|
|
||||||
pieTouchResponse.touchedSection ==
|
|
||||||
null) {
|
|
||||||
touchedIndex = -1;
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
touchedIndex = pieTouchResponse
|
|
||||||
.touchedSection!.touchedSectionIndex;
|
|
||||||
});
|
|
||||||
},
|
|
||||||
),
|
|
||||||
borderData: FlBorderData(
|
|
||||||
show: true,
|
|
||||||
),
|
|
||||||
sectionsSpace: 20,
|
|
||||||
centerSpaceRadius: 100,
|
|
||||||
sections: sectionsDataPortofolio())),
|
|
||||||
),
|
|
||||||
const Column(
|
|
||||||
children: [
|
|
||||||
Text('Total Mutual Fund'),
|
|
||||||
Text('10',
|
|
||||||
style: TextStyle(
|
|
||||||
fontSize: 44,
|
|
||||||
fontWeight: FontWeight.w700)),
|
|
||||||
],
|
|
||||||
)
|
|
||||||
]),
|
|
||||||
const SizedBox(
|
|
||||||
height: 12,
|
|
||||||
),
|
|
||||||
menuPortofolio(),
|
|
||||||
const SizedBox(
|
|
||||||
height: 24,
|
|
||||||
),
|
|
||||||
...listColumnPortofolio(),
|
|
||||||
const SizedBox(
|
|
||||||
height: 24,
|
|
||||||
)
|
|
||||||
],
|
|
||||||
),
|
|
||||||
),
|
|
||||||
)
|
|
||||||
],
|
|
||||||
)
|
|
||||||
],
|
|
||||||
),
|
|
||||||
),
|
|
||||||
);
|
|
||||||
}
|
|
||||||
|
|
||||||
Widget portofolioValue() {
|
|
||||||
return Column(
|
|
||||||
crossAxisAlignment: CrossAxisAlignment.start,
|
|
||||||
children: [
|
|
||||||
Row(
|
|
||||||
children: [
|
|
||||||
const Text('Portofolio Value',
|
|
||||||
style: TextStyle(color: Colors.white)),
|
|
||||||
const SizedBox(
|
|
||||||
width: 8,
|
|
||||||
),
|
|
||||||
GestureDetector(
|
|
||||||
onTap: () {
|
|
||||||
setState(() {
|
|
||||||
seePortofolioValue = !seePortofolioValue;
|
|
||||||
});
|
|
||||||
},
|
|
||||||
child: const Icon(Icons.visibility_outlined,
|
|
||||||
color: Color(0xff93C5FD)))
|
|
||||||
],
|
|
||||||
),
|
|
||||||
const SizedBox(
|
|
||||||
height: 4,
|
|
||||||
),
|
|
||||||
Row(
|
|
||||||
children: [
|
|
||||||
AnimatedCrossFade(
|
|
||||||
duration: const Duration(milliseconds: 300),
|
|
||||||
alignment: Alignment.center,
|
|
||||||
crossFadeState: seePortofolioValue
|
|
||||||
? CrossFadeState.showSecond
|
|
||||||
: CrossFadeState.showFirst,
|
|
||||||
firstChild: RichText(
|
|
||||||
text: const TextSpan(
|
|
||||||
text: 'Rp ',
|
|
||||||
style: TextStyle(fontSize: 32, color: Color(0xff93C5FD), fontFamily: 'Manrope'),
|
|
||||||
children: [
|
|
||||||
TextSpan(
|
|
||||||
text: '22.500.000',
|
|
||||||
style: TextStyle(
|
|
||||||
fontSize: 32,
|
|
||||||
fontFamily: 'Manrope',
|
|
||||||
fontWeight: FontWeight.bold,
|
|
||||||
color: Colors.white
|
|
||||||
),
|
|
||||||
)
|
|
||||||
])),
|
|
||||||
secondChild: Padding(
|
|
||||||
padding: const EdgeInsets.symmetric(vertical: 16),
|
|
||||||
child: Wrap(
|
|
||||||
spacing: 7,
|
|
||||||
children: [
|
|
||||||
for (int i = 0; i < 6; i++)
|
|
||||||
Container(
|
|
||||||
width: 12,
|
|
||||||
height: 12,
|
|
||||||
decoration: const BoxDecoration(
|
|
||||||
color: Colors.white, shape: BoxShape.circle),
|
|
||||||
),
|
|
||||||
],
|
|
||||||
),
|
|
||||||
),
|
|
||||||
),
|
|
||||||
],
|
|
||||||
)
|
|
||||||
],
|
|
||||||
);
|
|
||||||
}
|
|
||||||
|
|
||||||
List<PieChartSectionData> sectionsDataPortofolio() {
|
|
||||||
return listCategoryPortofolio.asMap().entries.map((e) {
|
|
||||||
final isTouched = e.key == touchedIndex;
|
|
||||||
final radius = isTouched ? 40.0 : 30.0;
|
|
||||||
return PieChartSectionData(
|
|
||||||
color: contentColor[e.key],
|
|
||||||
value: e.value.value.toDouble(),
|
|
||||||
title: e.value.name,
|
|
||||||
showTitle: isTouched,
|
|
||||||
radius: radius,
|
|
||||||
titleStyle: const TextStyle(
|
|
||||||
fontSize: 20,
|
|
||||||
fontWeight: FontWeight.bold,
|
|
||||||
),
|
|
||||||
);
|
|
||||||
}).toList();
|
|
||||||
}
|
|
||||||
|
|
||||||
Widget menuPortofolio() {
|
|
||||||
return Container(
|
|
||||||
margin: const EdgeInsets.symmetric(horizontal: 24),
|
|
||||||
padding: const EdgeInsets.all(12),
|
|
||||||
decoration: BoxDecoration(
|
|
||||||
color: Colors.white,
|
|
||||||
borderRadius: const BorderRadius.all(Radius.circular(12)),
|
|
||||||
boxShadow: [
|
|
||||||
BoxShadow(
|
|
||||||
spreadRadius: 2,
|
|
||||||
blurRadius: 8,
|
|
||||||
color: const Color(0xff1E293B).withOpacity(0.04))
|
|
||||||
]),
|
|
||||||
child: Wrap(
|
|
||||||
alignment: WrapAlignment.center,
|
|
||||||
spacing: 12,
|
|
||||||
children: listCategoryPortofolio.asMap().entries.map((e) {
|
|
||||||
return Container(
|
|
||||||
color: Colors.white,
|
|
||||||
width: SizeConfig.width * 0.18,
|
|
||||||
child: Column(
|
|
||||||
children: [
|
|
||||||
Container(
|
|
||||||
height: 58,
|
|
||||||
width: 58,
|
|
||||||
alignment: Alignment.center,
|
|
||||||
decoration: BoxDecoration(
|
|
||||||
shape: BoxShape.circle,
|
|
||||||
color: bgContentColor[e.key],
|
|
||||||
),
|
|
||||||
child: Text(
|
|
||||||
'${e.value.value}%',
|
|
||||||
style: TextStyle(
|
|
||||||
fontWeight: FontWeight.bold,
|
|
||||||
color: contentColor[e.key]),
|
|
||||||
),
|
|
||||||
),
|
|
||||||
const SizedBox(
|
|
||||||
height: 8,
|
|
||||||
),
|
|
||||||
Text(
|
|
||||||
e.value.name,
|
|
||||||
overflow: TextOverflow.ellipsis,
|
|
||||||
textAlign: TextAlign.center,
|
|
||||||
)
|
|
||||||
],
|
|
||||||
),
|
|
||||||
);
|
|
||||||
}).toList(),
|
|
||||||
),
|
|
||||||
);
|
|
||||||
}
|
|
||||||
|
|
||||||
List<Widget> listColumnPortofolio() {
|
|
||||||
return listCategoryPortofolio.asMap().entries.map((e) {
|
|
||||||
return Column(
|
|
||||||
children: [
|
|
||||||
if (e.key > 0) ...[
|
|
||||||
const Divider(
|
|
||||||
color: ColorPalette.slate200,
|
|
||||||
)
|
|
||||||
],
|
|
||||||
ListTile(
|
|
||||||
contentPadding:
|
|
||||||
const EdgeInsets.symmetric(vertical: 0, horizontal: 24),
|
|
||||||
leading: ImageView(
|
|
||||||
image: assetsImage[e.key],
|
|
||||||
width: SizeConfig.width * .15,
|
|
||||||
height: SizeConfig.height * .08,
|
|
||||||
borderRadius: 8,
|
|
||||||
),
|
|
||||||
title: Text(
|
|
||||||
e.value.name,
|
|
||||||
style: const TextStyle(fontWeight: FontWeight.w600),
|
|
||||||
),
|
|
||||||
subtitle: Text(
|
|
||||||
e.value.name,
|
|
||||||
style: const TextStyle(
|
|
||||||
fontWeight: FontWeight.w600, color: Color(0xff94A3B8)),
|
|
||||||
),
|
|
||||||
trailing: const Column(
|
|
||||||
crossAxisAlignment: CrossAxisAlignment.end,
|
|
||||||
children: [
|
|
||||||
Text(
|
|
||||||
'Rp 2.000.000',
|
|
||||||
style: TextStyle(
|
|
||||||
color: Colors.black,
|
|
||||||
fontSize: 16,
|
|
||||||
fontWeight: FontWeight.w700),
|
|
||||||
),
|
|
||||||
Text(
|
|
||||||
'+ Rp 200.000',
|
|
||||||
style: TextStyle(
|
|
||||||
fontSize: 14,
|
|
||||||
color: Color(0xff4ADE80),
|
|
||||||
fontWeight: FontWeight.w600),
|
|
||||||
)
|
|
||||||
],
|
|
||||||
),
|
|
||||||
),
|
|
||||||
],
|
|
||||||
);
|
|
||||||
}).toList();
|
|
||||||
}
|
|
||||||
}
|
|
|
@ -1,325 +0,0 @@
|
||||||
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:fl_chart/fl_chart.dart';
|
|
||||||
import 'package:flutter/material.dart';
|
|
||||||
import 'dart:math';
|
|
||||||
import 'package:intl/intl.dart';
|
|
||||||
|
|
||||||
class ProductChartView extends StatefulWidget {
|
|
||||||
final String tabType;
|
|
||||||
final String lastTime;
|
|
||||||
final List<double> dataChart;
|
|
||||||
|
|
||||||
const ProductChartView({
|
|
||||||
super.key,
|
|
||||||
required this.tabType,
|
|
||||||
required this.lastTime,
|
|
||||||
required this.dataChart,
|
|
||||||
});
|
|
||||||
|
|
||||||
@override
|
|
||||||
State<ProductChartView> createState() => _ProductChartViewState();
|
|
||||||
}
|
|
||||||
|
|
||||||
class _ProductChartViewState extends State<ProductChartView> {
|
|
||||||
bool isShowLabel = true;
|
|
||||||
DateTime dateTime = DateTime.now();
|
|
||||||
double currentPrice = 0;
|
|
||||||
int spotIndicator = 0;
|
|
||||||
List<int> showingTooltipOnSpots = [1, 3, 5];
|
|
||||||
List<FlSpot> spots = [];
|
|
||||||
|
|
||||||
double dataHighest = 0;
|
|
||||||
double dataLowest = 0;
|
|
||||||
|
|
||||||
int indexHighestValue = 0;
|
|
||||||
int indexLowestValue = 0;
|
|
||||||
|
|
||||||
@override
|
|
||||||
void initState() {
|
|
||||||
spots = widget.dataChart.asMap().entries.map((e) {
|
|
||||||
return FlSpot(double.parse(e.key.toString()), e.value);
|
|
||||||
}).toList();
|
|
||||||
dataHighest = widget.dataChart.reduce(max);
|
|
||||||
dataLowest = widget.dataChart.reduce(min);
|
|
||||||
currentPrice = dataHighest;
|
|
||||||
indexHighestValue = widget.dataChart.indexWhere((element) => element == dataHighest);
|
|
||||||
indexLowestValue = widget.dataChart.indexWhere((element) => element == dataLowest);
|
|
||||||
// TODO: implement initState
|
|
||||||
super.initState();
|
|
||||||
}
|
|
||||||
|
|
||||||
@override
|
|
||||||
void didUpdateWidget(covariant ProductChartView oldWidget) {
|
|
||||||
// TODO: implement didUpdateWidget
|
|
||||||
spots = widget.dataChart.asMap().entries.map((e) {
|
|
||||||
return FlSpot(double.parse(e.key.toString()), e.value);
|
|
||||||
}).toList();
|
|
||||||
dataHighest = widget.dataChart.reduce(max);
|
|
||||||
dataLowest = widget.dataChart.reduce(min);
|
|
||||||
currentPrice = dataHighest;
|
|
||||||
indexHighestValue = widget.dataChart.indexWhere((element) => element == dataHighest);
|
|
||||||
indexLowestValue = widget.dataChart.indexWhere((element) => element == dataLowest);
|
|
||||||
super.didUpdateWidget(oldWidget);
|
|
||||||
}
|
|
||||||
|
|
||||||
@override
|
|
||||||
Widget build(BuildContext context) {
|
|
||||||
|
|
||||||
return Column(
|
|
||||||
crossAxisAlignment: CrossAxisAlignment.start,
|
|
||||||
children: [
|
|
||||||
Padding(
|
|
||||||
padding: const EdgeInsets.symmetric(horizontal: 24),
|
|
||||||
child: Wrap(
|
|
||||||
spacing: 8,
|
|
||||||
children: [
|
|
||||||
Text(
|
|
||||||
widget.tabType,
|
|
||||||
style: TextStyle(
|
|
||||||
color: ColorPalette.slate400,
|
|
||||||
fontWeight: FontWeight.w700
|
|
||||||
),
|
|
||||||
),
|
|
||||||
Text(
|
|
||||||
DateFormat('dd MMM yyyy').format(dateTime),
|
|
||||||
style: TextStyle(
|
|
||||||
color: ColorPalette.slate300
|
|
||||||
),
|
|
||||||
),
|
|
||||||
],
|
|
||||||
),
|
|
||||||
),
|
|
||||||
Padding(
|
|
||||||
padding: const EdgeInsets.symmetric(horizontal: 24),
|
|
||||||
child: TextTitle(title: NumberFormatter.numberCurrency(currentPrice, 'Rp ', 'id_ID')),
|
|
||||||
),
|
|
||||||
Padding(
|
|
||||||
padding: const EdgeInsets.symmetric(horizontal: 24),
|
|
||||||
child: Wrap(
|
|
||||||
crossAxisAlignment: WrapCrossAlignment.center,
|
|
||||||
spacing: 8,
|
|
||||||
children: [
|
|
||||||
Icon(
|
|
||||||
Icons.trending_up_outlined,
|
|
||||||
size: 18,
|
|
||||||
color: ColorPalette.green500,
|
|
||||||
),
|
|
||||||
Text(
|
|
||||||
'Rp20,30 (+3,88%)',
|
|
||||||
style: TextStyle(
|
|
||||||
color: ColorPalette.green500,
|
|
||||||
fontWeight: FontWeight.w600
|
|
||||||
),
|
|
||||||
),
|
|
||||||
Text(
|
|
||||||
'Last ${widget.lastTime}',
|
|
||||||
style: TextStyle(
|
|
||||||
color: ColorPalette.slate300,
|
|
||||||
fontWeight: FontWeight.w600
|
|
||||||
),
|
|
||||||
)
|
|
||||||
],
|
|
||||||
),
|
|
||||||
),
|
|
||||||
Padding(
|
|
||||||
padding: const EdgeInsets.symmetric(vertical: 48),
|
|
||||||
child: AspectRatio(
|
|
||||||
aspectRatio: 2.5,
|
|
||||||
child: LayoutBuilder(
|
|
||||||
builder: (context, constraints) {
|
|
||||||
return LineChart(
|
|
||||||
LineChartData(
|
|
||||||
// showingTooltipIndicators: showingTooltipOnSpots.map((index) {
|
|
||||||
// return ShowingTooltipIndicators([
|
|
||||||
// LineBarSpot(
|
|
||||||
// tooltipsOnBar,
|
|
||||||
// lineBarsData.indexOf(tooltipsOnBar),
|
|
||||||
// tooltipsOnBar.spots[index],
|
|
||||||
// ),
|
|
||||||
// ]);
|
|
||||||
// }).toList(),
|
|
||||||
extraLinesData: ExtraLinesData(
|
|
||||||
verticalLines: [
|
|
||||||
VerticalLine(
|
|
||||||
color: Colors.transparent,
|
|
||||||
x: indexHighestValue.toDouble(),
|
|
||||||
label: VerticalLineLabel(
|
|
||||||
show: spots.length < 7 ? false : isShowLabel,
|
|
||||||
padding: EdgeInsets.only(bottom: 20, top: -25),
|
|
||||||
alignment: (indexHighestValue / widget.dataChart.length) < 0.25 ? Alignment.topRight : (indexHighestValue / widget.dataChart.length) > 0.75 ? Alignment.topLeft : Alignment.topCenter,
|
|
||||||
style: const TextStyle(
|
|
||||||
color: ColorPalette.slate400,
|
|
||||||
fontSize: 12,
|
|
||||||
fontWeight: FontWeight.bold,
|
|
||||||
),
|
|
||||||
labelResolver: (p0) => NumberFormatter.numberCurrency(dataHighest, 'Rp ', 'id_ID'),
|
|
||||||
)
|
|
||||||
),
|
|
||||||
VerticalLine(
|
|
||||||
color: Colors.transparent,
|
|
||||||
x: indexLowestValue.toDouble(),
|
|
||||||
label: VerticalLineLabel(
|
|
||||||
show: spots.length < 7 ? false : isShowLabel,
|
|
||||||
padding: EdgeInsets.only(bottom: -5, top: 20),
|
|
||||||
alignment: (indexLowestValue / widget.dataChart.length ) < 0.25 ? Alignment.bottomRight : (indexLowestValue / widget.dataChart.length ) > 0.75 ? Alignment.bottomLeft : Alignment.bottomCenter,
|
|
||||||
style: const TextStyle(
|
|
||||||
color: ColorPalette.slate400,
|
|
||||||
fontSize: 12,
|
|
||||||
fontWeight: FontWeight.bold,
|
|
||||||
),
|
|
||||||
labelResolver: (p0) => NumberFormatter.numberCurrency(dataLowest, 'Rp ', 'id_ID'),
|
|
||||||
)
|
|
||||||
)
|
|
||||||
]
|
|
||||||
),
|
|
||||||
lineTouchData: LineTouchData(
|
|
||||||
getTouchLineEnd: (barData, spotIndex) => double.infinity,
|
|
||||||
getTouchedSpotIndicator: (barData, spotIndexes) {
|
|
||||||
return spotIndexes.map((spotIndex) {
|
|
||||||
return TouchedSpotIndicatorData(
|
|
||||||
const FlLine(strokeWidth: 1, color: ColorPalette.primary),
|
|
||||||
FlDotData(
|
|
||||||
getDotPainter: (spot, percent, barData, index) =>
|
|
||||||
FlDotCirclePainter(
|
|
||||||
radius: 1,
|
|
||||||
color: ColorPalette.white,
|
|
||||||
strokeColor: ColorPalette.primary,
|
|
||||||
strokeWidth: 2,
|
|
||||||
),
|
|
||||||
),
|
|
||||||
);
|
|
||||||
}).toList();
|
|
||||||
},
|
|
||||||
touchCallback: (FlTouchEvent event, LineTouchResponse? response) {
|
|
||||||
if (response == null || response.lineBarSpots == null) {
|
|
||||||
setState(() {
|
|
||||||
isShowLabel = true;
|
|
||||||
currentPrice = widget.dataChart.last;
|
|
||||||
dateTime = DateTime.now();
|
|
||||||
});
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
double? spotIndex = response.lineBarSpots?[0].x;
|
|
||||||
if(spotIndex != null){
|
|
||||||
int absIndex = (spotIndex.toInt() - (spots.length - 1)).abs();
|
|
||||||
setState(() {
|
|
||||||
isShowLabel = false;
|
|
||||||
spotIndicator = spotIndex.toInt();
|
|
||||||
currentPrice = widget.dataChart[spotIndex.toInt()];
|
|
||||||
dateTime = DateTime.now().subtract(Duration(days: absIndex));
|
|
||||||
});
|
|
||||||
}
|
|
||||||
},
|
|
||||||
touchTooltipData: LineTouchTooltipData(
|
|
||||||
tooltipBgColor: Colors.transparent,
|
|
||||||
tooltipPadding: EdgeInsets.all(0),
|
|
||||||
fitInsideHorizontally: true,
|
|
||||||
showOnTopOfTheChartBoxArea: true,
|
|
||||||
getTooltipItems: (touchedSpots) {
|
|
||||||
return touchedSpots.map((LineBarSpot touchedSpot) {
|
|
||||||
final textStyle = TextStyle(
|
|
||||||
color: ColorPalette.slate500,
|
|
||||||
fontWeight: FontWeight.bold,
|
|
||||||
fontSize: 12,
|
|
||||||
);
|
|
||||||
return LineTooltipItem(
|
|
||||||
DateFormat('dd MMM yyyy').format(dateTime),
|
|
||||||
textStyle,
|
|
||||||
);
|
|
||||||
}).toList();
|
|
||||||
},
|
|
||||||
),
|
|
||||||
handleBuiltInTouches: true,
|
|
||||||
),
|
|
||||||
lineBarsData: [
|
|
||||||
LineChartBarData(
|
|
||||||
color: ColorPalette.primary,
|
|
||||||
spots: spots,
|
|
||||||
isCurved: true,
|
|
||||||
preventCurveOverShooting: true,
|
|
||||||
isStrokeCapRound: true,
|
|
||||||
isStrokeJoinRound: true,
|
|
||||||
barWidth: 1.2,
|
|
||||||
belowBarData: BarAreaData(
|
|
||||||
show: true,
|
|
||||||
gradient: LinearGradient(
|
|
||||||
begin: Alignment.topCenter,
|
|
||||||
end: Alignment.bottomCenter,
|
|
||||||
colors: [
|
|
||||||
Color(0xFF5B8FF9),
|
|
||||||
Colors.white
|
|
||||||
]
|
|
||||||
),
|
|
||||||
spotsLine: BarAreaSpotsLine(
|
|
||||||
show: true,
|
|
||||||
applyCutOffY: true,
|
|
||||||
flLineStyle: FlLine(
|
|
||||||
color: ColorPalette.primary,
|
|
||||||
strokeWidth: 1,
|
|
||||||
),
|
|
||||||
checkToShowSpotLine: (spot) {
|
|
||||||
if(spot.x == spotIndicator && !isShowLabel){
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
return false;
|
|
||||||
},
|
|
||||||
)
|
|
||||||
),
|
|
||||||
dotData: FlDotData(
|
|
||||||
show: true,
|
|
||||||
getDotPainter: (p0, p1, p2, p3) {
|
|
||||||
return FlDotCirclePainter(
|
|
||||||
radius: 1,
|
|
||||||
color: ColorPalette.white,
|
|
||||||
strokeColor: ColorPalette.primary,
|
|
||||||
strokeWidth: 2,
|
|
||||||
);
|
|
||||||
},
|
|
||||||
checkToShowDot: (spot, barData) {
|
|
||||||
if(spot.x == spotIndicator && !isShowLabel){
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
return false;
|
|
||||||
},
|
|
||||||
),
|
|
||||||
),
|
|
||||||
],
|
|
||||||
titlesData: FlTitlesData(
|
|
||||||
leftTitles: AxisTitles(
|
|
||||||
sideTitles: SideTitles(
|
|
||||||
showTitles: false,
|
|
||||||
reservedSize: 56,
|
|
||||||
),
|
|
||||||
drawBelowEverything: true,
|
|
||||||
),
|
|
||||||
rightTitles: const AxisTitles(
|
|
||||||
sideTitles: SideTitles(showTitles: false),
|
|
||||||
),
|
|
||||||
bottomTitles: AxisTitles(
|
|
||||||
sideTitles: SideTitles(
|
|
||||||
showTitles: false,
|
|
||||||
reservedSize: 36,
|
|
||||||
interval: 1,
|
|
||||||
),
|
|
||||||
drawBelowEverything: true,
|
|
||||||
),
|
|
||||||
topTitles: const AxisTitles(
|
|
||||||
sideTitles: SideTitles(showTitles: false),
|
|
||||||
),
|
|
||||||
),
|
|
||||||
gridData: FlGridData(
|
|
||||||
show: false
|
|
||||||
),
|
|
||||||
borderData: FlBorderData(show: false),
|
|
||||||
),
|
|
||||||
);
|
|
||||||
},
|
|
||||||
),
|
|
||||||
),
|
|
||||||
),
|
|
||||||
],
|
|
||||||
);
|
|
||||||
}
|
|
||||||
}
|
|
|
@ -1,789 +0,0 @@
|
||||||
import 'dart:math';
|
|
||||||
|
|
||||||
import 'package:cims_apps/application/assets/path_assets.dart';
|
|
||||||
import 'package:cims_apps/application/component/button/button_back.dart';
|
|
||||||
import 'package:cims_apps/application/component/button/button_view.dart';
|
|
||||||
import 'package:cims_apps/application/component/image/image_view.dart';
|
|
||||||
import 'package:cims_apps/application/component/text_form/text_form_view.dart';
|
|
||||||
import 'package:cims_apps/application/component/text_title/text_title.dart';
|
|
||||||
import 'package:cims_apps/application/theme/color_palette.dart';
|
|
||||||
import 'package:cims_apps/core/utils/number_formatter.dart';
|
|
||||||
import 'package:cims_apps/core/utils/size_config.dart';
|
|
||||||
import 'package:cims_apps/features/dashboard/dashboard_account/view/product/product_chart_view.dart';
|
|
||||||
import 'package:flutter/material.dart';
|
|
||||||
import 'package:group_button/group_button.dart';
|
|
||||||
|
|
||||||
class Time {
|
|
||||||
int value;
|
|
||||||
String simpleName, completeName;
|
|
||||||
|
|
||||||
Time(this.value, this.simpleName, this.completeName);
|
|
||||||
}
|
|
||||||
|
|
||||||
class ProductView extends StatefulWidget {
|
|
||||||
final String investType;
|
|
||||||
const ProductView(this.investType, {super.key});
|
|
||||||
|
|
||||||
@override
|
|
||||||
State<ProductView> createState() => _ProductViewState();
|
|
||||||
}
|
|
||||||
|
|
||||||
class _ProductViewState extends State<ProductView> {
|
|
||||||
int selectedTab = 0;
|
|
||||||
Time selectedTime = Time(2, '1D', '1 day');
|
|
||||||
int selectedMachineType = 0;
|
|
||||||
int selectedMachineTime = 0;
|
|
||||||
|
|
||||||
List<Time> listTime = [
|
|
||||||
Time(2, '1D', '1 day'),
|
|
||||||
Time(30, '1M', '1 month'),
|
|
||||||
Time(90, '3M', '3 months'),
|
|
||||||
Time(365, '1Y', '1 year'),
|
|
||||||
];
|
|
||||||
|
|
||||||
List<String> listTab = ['NAV', 'AUM'];
|
|
||||||
|
|
||||||
List<String> listMachine = ['Monthly Routine', 'Connect Once'];
|
|
||||||
|
|
||||||
List<Time> listMachineTime = [
|
|
||||||
Time(1, '1D', '1 year'),
|
|
||||||
Time(3, '1M', '3 year'),
|
|
||||||
Time(5, '3M', '5 year'),
|
|
||||||
Time(10, '1Y', '10 year'),
|
|
||||||
];
|
|
||||||
|
|
||||||
TextEditingController machineController = TextEditingController();
|
|
||||||
|
|
||||||
GroupButtonController machineGroupButtonController = GroupButtonController(selectedIndex: 0);
|
|
||||||
|
|
||||||
List<String> listTopHoldings = [
|
|
||||||
'Bank Pembangunan Daerah Sulawesi Selatan dan Sulawesi Barat',
|
|
||||||
'PT. Bank Jabar Banten, TBK',
|
|
||||||
'PT. Bank Mega',
|
|
||||||
'PT. Bank Nagaria',
|
|
||||||
'PT. BPD Sulawesi Tengah'
|
|
||||||
];
|
|
||||||
|
|
||||||
List<double> data = [];
|
|
||||||
double estimatedValue = 0;
|
|
||||||
|
|
||||||
void setEstimatedValue() {
|
|
||||||
double parseValue = double.parse(machineController.text.replaceAll('Rp ', '').replaceAll('.', ''));
|
|
||||||
int machineType = selectedMachineType == 0 ? 12 : 1;
|
|
||||||
setState(() {
|
|
||||||
estimatedValue = (machineType * (listMachineTime[selectedMachineTime].value) * ((parseValue * machineType) * 10/100)) + parseValue;
|
|
||||||
});
|
|
||||||
}
|
|
||||||
|
|
||||||
@override
|
|
||||||
void initState() {
|
|
||||||
machineController.text = NumberFormatter.numberCurrency(100000, 'Rp ', 'id_ID', decimalDigits: 0);
|
|
||||||
selectedTime = listTime[0];
|
|
||||||
setEstimatedValue();
|
|
||||||
List.generate(2, (index) => {
|
|
||||||
data.add((2500 + index - Random().nextInt(100)).toDouble())
|
|
||||||
});
|
|
||||||
// TODO: implement initState
|
|
||||||
super.initState();
|
|
||||||
}
|
|
||||||
|
|
||||||
@override
|
|
||||||
void dispose() {
|
|
||||||
machineController.dispose();
|
|
||||||
machineGroupButtonController.dispose();
|
|
||||||
// TODO: implement dispose
|
|
||||||
super.dispose();
|
|
||||||
}
|
|
||||||
|
|
||||||
@override
|
|
||||||
Widget build(BuildContext context) {
|
|
||||||
return Scaffold(
|
|
||||||
body: SizedBox(
|
|
||||||
width: SizeConfig.width,
|
|
||||||
height: SizeConfig.height,
|
|
||||||
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: [
|
|
||||||
ButtonBack(),
|
|
||||||
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: Padding(
|
|
||||||
padding: const EdgeInsets.symmetric(horizontal: 24),
|
|
||||||
child: ButtonView(
|
|
||||||
name: 'Buy',
|
|
||||||
onPressed: () {
|
|
||||||
|
|
||||||
},
|
|
||||||
height: SizeConfig.height * 0.06,
|
|
||||||
marginVertical: 16,
|
|
||||||
),
|
|
||||||
),
|
|
||||||
);
|
|
||||||
}
|
|
||||||
|
|
||||||
Widget headContainer() {
|
|
||||||
return Padding(
|
|
||||||
padding: const EdgeInsets.symmetric(horizontal: 24),
|
|
||||||
child: Row(
|
|
||||||
mainAxisAlignment: MainAxisAlignment.spaceBetween,
|
|
||||||
children: [
|
|
||||||
Expanded(
|
|
||||||
child: Row(
|
|
||||||
children: [
|
|
||||||
ImageView(image: PathAssets.imgProduct, width: SizeConfig.width * .12),
|
|
||||||
SizedBox(width: 8),
|
|
||||||
Expanded(
|
|
||||||
child: Text(
|
|
||||||
'Gemilang Dana Kas Maxima',
|
|
||||||
maxLines: 2,
|
|
||||||
overflow: TextOverflow.ellipsis,
|
|
||||||
style: TextStyle(
|
|
||||||
color: Colors.white,
|
|
||||||
fontWeight: FontWeight.w700,
|
|
||||||
fontSize: 18
|
|
||||||
),
|
|
||||||
),
|
|
||||||
)
|
|
||||||
],
|
|
||||||
),
|
|
||||||
),
|
|
||||||
Container(
|
|
||||||
padding: const EdgeInsets.all(6),
|
|
||||||
decoration: BoxDecoration(
|
|
||||||
borderRadius: BorderRadius.circular(40),
|
|
||||||
color: ColorPalette.investTypeBgColor[widget.investType] ?? Colors.white,
|
|
||||||
border: Border.all(width: 2, color: ColorPalette.investTypeColor[widget.investType] ?? Colors.white)
|
|
||||||
),
|
|
||||||
child: Text(
|
|
||||||
widget.investType,
|
|
||||||
style: TextStyle(
|
|
||||||
color: ColorPalette.investTypeColor[widget.investType],
|
|
||||||
fontWeight: FontWeight.w600
|
|
||||||
),
|
|
||||||
),
|
|
||||||
)
|
|
||||||
],
|
|
||||||
),
|
|
||||||
);
|
|
||||||
}
|
|
||||||
|
|
||||||
Widget contentContainer() {
|
|
||||||
return ClipRRect(
|
|
||||||
borderRadius: BorderRadius.circular(12),
|
|
||||||
child: Container(
|
|
||||||
decoration: BoxDecoration(
|
|
||||||
color: Colors.white,
|
|
||||||
),
|
|
||||||
child: ListView(
|
|
||||||
children: [
|
|
||||||
ProductChartView(
|
|
||||||
tabType: listTab[selectedTab],
|
|
||||||
lastTime: selectedTime.completeName,
|
|
||||||
dataChart: data,
|
|
||||||
),
|
|
||||||
Center(
|
|
||||||
child: Padding(
|
|
||||||
padding: const EdgeInsets.all(24),
|
|
||||||
child: switchTab(listTab, (value) {
|
|
||||||
setState(() {
|
|
||||||
selectedTab = value;
|
|
||||||
data.clear();
|
|
||||||
List.generate(selectedTime.value, (index) => {
|
|
||||||
data.add((2500 + index - Random().nextInt(100)).toDouble())
|
|
||||||
});
|
|
||||||
});
|
|
||||||
}, selectedTab),
|
|
||||||
),
|
|
||||||
),
|
|
||||||
swithTime(),
|
|
||||||
const SizedBox(
|
|
||||||
height: 24,
|
|
||||||
),
|
|
||||||
Padding(
|
|
||||||
padding: const EdgeInsets.symmetric(horizontal: 24),
|
|
||||||
child: Row(
|
|
||||||
mainAxisAlignment: MainAxisAlignment.spaceBetween,
|
|
||||||
children: [
|
|
||||||
columnInformation('CAGR 1Y', '3,88%'),
|
|
||||||
columnInformation('Drawdown 1Y', '0%'),
|
|
||||||
columnInformation('Expense Ratio', '1,99%')
|
|
||||||
],
|
|
||||||
),
|
|
||||||
),
|
|
||||||
const SizedBox(
|
|
||||||
height: 16,
|
|
||||||
),
|
|
||||||
Padding(
|
|
||||||
padding: const EdgeInsets.symmetric(horizontal: 24),
|
|
||||||
child: Row(
|
|
||||||
mainAxisAlignment: MainAxisAlignment.spaceBetween,
|
|
||||||
children: [
|
|
||||||
columnInformation('Total AUM', '3,88%'),
|
|
||||||
columnInformation('Avg.Yield Dec 23', '6,44%'),
|
|
||||||
columnInformation('Risk Level', 'Conservative')
|
|
||||||
],
|
|
||||||
),
|
|
||||||
),
|
|
||||||
const SizedBox(
|
|
||||||
height: 24,
|
|
||||||
),
|
|
||||||
cardInformation('Investment Information', informationInvest()),
|
|
||||||
const SizedBox(
|
|
||||||
height: 24,
|
|
||||||
),
|
|
||||||
cardInformation('Investment Costs', investCost()),
|
|
||||||
const SizedBox(
|
|
||||||
height: 24,
|
|
||||||
),
|
|
||||||
moreAction(),
|
|
||||||
const SizedBox(
|
|
||||||
height: 24,
|
|
||||||
),
|
|
||||||
cardInformation('Time Machine', timeMachine()),
|
|
||||||
const SizedBox(
|
|
||||||
height: 24,
|
|
||||||
),
|
|
||||||
topFiveHoldings(),
|
|
||||||
const SizedBox(
|
|
||||||
height: 24,
|
|
||||||
),
|
|
||||||
cardInformation('Document', documentProduct()),
|
|
||||||
],
|
|
||||||
),
|
|
||||||
),
|
|
||||||
);
|
|
||||||
}
|
|
||||||
|
|
||||||
Widget switchTab(List<String> dataTab, void Function(int value) onTap, int current) {
|
|
||||||
return Container(
|
|
||||||
width: SizeConfig.width,
|
|
||||||
decoration: BoxDecoration(
|
|
||||||
border: Border.all(
|
|
||||||
color: ColorPalette.slate200,
|
|
||||||
),
|
|
||||||
borderRadius: BorderRadius.circular(80)
|
|
||||||
),
|
|
||||||
child: Stack(
|
|
||||||
children: [
|
|
||||||
// AnimatedPositioned(
|
|
||||||
// duration: const Duration(milliseconds: 200),
|
|
||||||
// curve: Curves.fastOutSlowIn,
|
|
||||||
// right: current == dataTab.length - 1 ? 0 : SizeConfig.width * current / dataTab.length - (12 * dataTab.length),
|
|
||||||
// left: current == 0 ? 0 : SizeConfig.width * current / dataTab.length - (12 * dataTab.length),
|
|
||||||
// child: Container(
|
|
||||||
// height: 35,
|
|
||||||
// decoration: BoxDecoration(
|
|
||||||
// color: ColorPalette.blue200,
|
|
||||||
// borderRadius: BorderRadius.circular(80)
|
|
||||||
// ),
|
|
||||||
// ),
|
|
||||||
// ),
|
|
||||||
Container(
|
|
||||||
height: 35,
|
|
||||||
decoration: BoxDecoration(
|
|
||||||
borderRadius: BorderRadius.circular(80)
|
|
||||||
),
|
|
||||||
child: Row(
|
|
||||||
children: dataTab.asMap().entries.map((e) => Expanded(
|
|
||||||
child: GestureDetector(
|
|
||||||
onTap: () {
|
|
||||||
onTap(e.key);
|
|
||||||
},
|
|
||||||
child: AnimatedContainer(
|
|
||||||
duration: const Duration(milliseconds: 300),
|
|
||||||
height: 35,
|
|
||||||
alignment: Alignment.center,
|
|
||||||
decoration: BoxDecoration(
|
|
||||||
borderRadius: BorderRadius.circular(80),
|
|
||||||
color: e.key == current ? ColorPalette.blue200 : ColorPalette.white
|
|
||||||
),
|
|
||||||
child: Text(
|
|
||||||
e.value,
|
|
||||||
textAlign: TextAlign.center,
|
|
||||||
style: TextStyle(
|
|
||||||
fontWeight: e.key == current ? FontWeight.w700 : FontWeight.w500,
|
|
||||||
color: e.key == current ? ColorPalette.primary : ColorPalette.slate500
|
|
||||||
),
|
|
||||||
),
|
|
||||||
)
|
|
||||||
)
|
|
||||||
)).toList(),
|
|
||||||
),
|
|
||||||
)
|
|
||||||
],
|
|
||||||
),
|
|
||||||
);
|
|
||||||
}
|
|
||||||
|
|
||||||
Widget swithTime() {
|
|
||||||
return Container(
|
|
||||||
color: ColorPalette.slate50,
|
|
||||||
alignment: Alignment.center,
|
|
||||||
child: SingleChildScrollView(
|
|
||||||
scrollDirection: Axis.horizontal,
|
|
||||||
padding: const EdgeInsets.symmetric(horizontal: 24),
|
|
||||||
child: Row(
|
|
||||||
mainAxisAlignment: MainAxisAlignment.center,
|
|
||||||
children: listTime.map((e) {
|
|
||||||
return GestureDetector(
|
|
||||||
onTap: () {
|
|
||||||
setState(() {
|
|
||||||
selectedTime = e;
|
|
||||||
data.clear();
|
|
||||||
List.generate(e.value, (index) => {
|
|
||||||
data.add((2500 + index - Random().nextInt(100)).toDouble())
|
|
||||||
});
|
|
||||||
});
|
|
||||||
},
|
|
||||||
child: AnimatedContainer(
|
|
||||||
duration: const Duration(milliseconds: 200),
|
|
||||||
width: SizeConfig.width * .12,
|
|
||||||
alignment: Alignment.center,
|
|
||||||
padding: const EdgeInsets.symmetric(vertical: 4),
|
|
||||||
decoration: BoxDecoration(
|
|
||||||
borderRadius: BorderRadius.circular(4),
|
|
||||||
color: selectedTime == e ? ColorPalette.primary : ColorPalette.slate50
|
|
||||||
),
|
|
||||||
child: Text(e.simpleName, style: TextStyle(
|
|
||||||
color: selectedTime == e ? ColorPalette.white : ColorPalette.slate400,
|
|
||||||
fontWeight: FontWeight.w700
|
|
||||||
)),
|
|
||||||
),
|
|
||||||
);
|
|
||||||
}).toList(),
|
|
||||||
),
|
|
||||||
)
|
|
||||||
);
|
|
||||||
}
|
|
||||||
|
|
||||||
Widget columnInformation(String title, String value) {
|
|
||||||
return Column(
|
|
||||||
crossAxisAlignment: CrossAxisAlignment.center,
|
|
||||||
children: [
|
|
||||||
rowInformation(title),
|
|
||||||
Row(
|
|
||||||
mainAxisAlignment: MainAxisAlignment.center,
|
|
||||||
children: [
|
|
||||||
Text(value)
|
|
||||||
],
|
|
||||||
)
|
|
||||||
],
|
|
||||||
);
|
|
||||||
}
|
|
||||||
|
|
||||||
Widget rowInformation(String title) {
|
|
||||||
return Row(
|
|
||||||
mainAxisAlignment: MainAxisAlignment.center,
|
|
||||||
children: [
|
|
||||||
Text(
|
|
||||||
title,
|
|
||||||
maxLines: 1,
|
|
||||||
style: const TextStyle(
|
|
||||||
color: ColorPalette.slate400,
|
|
||||||
fontWeight: FontWeight.w600
|
|
||||||
),
|
|
||||||
),
|
|
||||||
const SizedBox(width: 2),
|
|
||||||
const Icon(Icons.info_outline_rounded, size: 16, color: ColorPalette.slate400)
|
|
||||||
],
|
|
||||||
);
|
|
||||||
}
|
|
||||||
|
|
||||||
Widget cardInformation(String title, Widget child) {
|
|
||||||
return Container(
|
|
||||||
margin: const EdgeInsets.symmetric(horizontal: 24),
|
|
||||||
padding: const EdgeInsets.all(16),
|
|
||||||
decoration: BoxDecoration(
|
|
||||||
border: Border.all(color: ColorPalette.slate200),
|
|
||||||
borderRadius: BorderRadius.circular(12)
|
|
||||||
),
|
|
||||||
child: Column(
|
|
||||||
crossAxisAlignment: CrossAxisAlignment.start,
|
|
||||||
children: [
|
|
||||||
TextTitle(title: title, fontSize: 16),
|
|
||||||
const SizedBox(
|
|
||||||
height: 16,
|
|
||||||
),
|
|
||||||
child
|
|
||||||
],
|
|
||||||
),
|
|
||||||
);
|
|
||||||
}
|
|
||||||
|
|
||||||
Widget informationInvest() {
|
|
||||||
return Column(
|
|
||||||
children: [
|
|
||||||
const Row(
|
|
||||||
mainAxisAlignment: MainAxisAlignment.spaceBetween,
|
|
||||||
children: [
|
|
||||||
Text(
|
|
||||||
'Minimum Purchase',
|
|
||||||
style: TextStyle(
|
|
||||||
color: ColorPalette.slate400,
|
|
||||||
fontWeight: FontWeight.w600
|
|
||||||
),
|
|
||||||
),
|
|
||||||
Text('Rp10.000')
|
|
||||||
],
|
|
||||||
),
|
|
||||||
Row(
|
|
||||||
mainAxisAlignment: MainAxisAlignment.spaceBetween,
|
|
||||||
children: [
|
|
||||||
rowInformation('Custodian Bank'),
|
|
||||||
const Text('HSBC INDONESIA')
|
|
||||||
],
|
|
||||||
),
|
|
||||||
Row(
|
|
||||||
mainAxisAlignment: MainAxisAlignment.spaceBetween,
|
|
||||||
children: [
|
|
||||||
rowInformation('Depository Bank'),
|
|
||||||
const Text('BCA')
|
|
||||||
],
|
|
||||||
)
|
|
||||||
],
|
|
||||||
);
|
|
||||||
}
|
|
||||||
|
|
||||||
Widget investCost(){
|
|
||||||
return Column(
|
|
||||||
children: [
|
|
||||||
const Row(
|
|
||||||
mainAxisAlignment: MainAxisAlignment.spaceBetween,
|
|
||||||
children: [
|
|
||||||
Text(
|
|
||||||
'Purchase Commission',
|
|
||||||
style: TextStyle(
|
|
||||||
color: ColorPalette.slate400,
|
|
||||||
fontWeight: FontWeight.w600
|
|
||||||
),
|
|
||||||
),
|
|
||||||
Text('Free',
|
|
||||||
style: TextStyle(
|
|
||||||
fontWeight: FontWeight.bold
|
|
||||||
),
|
|
||||||
)
|
|
||||||
],
|
|
||||||
),
|
|
||||||
Row(
|
|
||||||
mainAxisAlignment: MainAxisAlignment.spaceBetween,
|
|
||||||
children: [
|
|
||||||
rowInformation('Sales Commission'),
|
|
||||||
const Text('Free',
|
|
||||||
style: TextStyle(
|
|
||||||
fontWeight: FontWeight.bold
|
|
||||||
),
|
|
||||||
)
|
|
||||||
],
|
|
||||||
),
|
|
||||||
],
|
|
||||||
);
|
|
||||||
}
|
|
||||||
|
|
||||||
Widget moreAction() {
|
|
||||||
return Padding(
|
|
||||||
padding: const EdgeInsets.symmetric(horizontal: 24),
|
|
||||||
child: Row(
|
|
||||||
children: [
|
|
||||||
Expanded(
|
|
||||||
child: ButtonView(
|
|
||||||
onPressed: () {
|
|
||||||
|
|
||||||
},
|
|
||||||
prefixIcon: Icon(Icons.space_dashboard_sharp),
|
|
||||||
backgroundColor: ColorPalette.blue50,
|
|
||||||
sizeBorderRadius: 8,
|
|
||||||
isSecondaryColor: false,
|
|
||||||
width: SizeConfig.width * .5,
|
|
||||||
heightWrapContent: true,
|
|
||||||
isOutlined: true,
|
|
||||||
widthPrefix: 10,
|
|
||||||
name: 'Routine Savings',
|
|
||||||
textSize: 14,
|
|
||||||
textAlign: TextAlign.start,
|
|
||||||
contentPadding: EdgeInsets.all(12),
|
|
||||||
)
|
|
||||||
),
|
|
||||||
SizedBox(
|
|
||||||
width: 16,
|
|
||||||
),
|
|
||||||
Expanded(
|
|
||||||
child: ButtonView(
|
|
||||||
onPressed: () {
|
|
||||||
|
|
||||||
},
|
|
||||||
prefixIcon: Icon(Icons.space_dashboard_sharp, color: ColorPalette.orange500),
|
|
||||||
widthPrefix: 10,
|
|
||||||
name: 'Compare Mutual Funds',
|
|
||||||
width: SizeConfig.width * .5,
|
|
||||||
heightWrapContent: true,
|
|
||||||
backgroundColor: ColorPalette.orange50,
|
|
||||||
sizeBorderRadius: 8,
|
|
||||||
isOutlined: true,
|
|
||||||
borderColor: ColorPalette.orange500,
|
|
||||||
textSize: 14,
|
|
||||||
textAlign: TextAlign.start,
|
|
||||||
textColor: ColorPalette.orange500,
|
|
||||||
contentPadding: EdgeInsets.all(12),
|
|
||||||
)
|
|
||||||
),
|
|
||||||
],
|
|
||||||
),
|
|
||||||
);
|
|
||||||
}
|
|
||||||
|
|
||||||
Widget timeMachine() {
|
|
||||||
return Column(
|
|
||||||
crossAxisAlignment: CrossAxisAlignment.start,
|
|
||||||
children: [
|
|
||||||
switchTab(listMachine, (value) {
|
|
||||||
setState(() {
|
|
||||||
selectedMachineType = value;
|
|
||||||
});
|
|
||||||
setEstimatedValue();
|
|
||||||
},
|
|
||||||
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
|
|
||||||
),
|
|
||||||
),
|
|
||||||
),
|
|
||||||
TextFormView(
|
|
||||||
name: '',
|
|
||||||
ctrl: machineController,
|
|
||||||
onChanged: (value) {
|
|
||||||
value = value.replaceAll('Rp ', '').replaceAll('.', '');
|
|
||||||
double parseValue = double.parse(value);
|
|
||||||
if(value.isNotEmpty){
|
|
||||||
machineController.text = NumberFormatter.numberCurrency(parseValue, 'Rp ', 'id_ID', decimalDigits: 0);
|
|
||||||
}else{
|
|
||||||
machineController.text = NumberFormatter.numberCurrency(0, 'Rp ', 'id_ID', decimalDigits: 0);
|
|
||||||
}
|
|
||||||
setEstimatedValue();
|
|
||||||
},
|
|
||||||
keyboardType: TextInputType.number,
|
|
||||||
),
|
|
||||||
const Padding(
|
|
||||||
padding: EdgeInsets.only(top: 16, bottom: 8),
|
|
||||||
child: Text(
|
|
||||||
"How many years ago did you start investing?",
|
|
||||||
style: TextStyle(
|
|
||||||
fontWeight: FontWeight.w600,
|
|
||||||
color: ColorPalette.slate800
|
|
||||||
),
|
|
||||||
),
|
|
||||||
),
|
|
||||||
Center(
|
|
||||||
child: GroupButton(
|
|
||||||
buttons: listMachineTime.map((e) => e.completeName).toList(),
|
|
||||||
controller: machineGroupButtonController,
|
|
||||||
onSelected: (value, index, isSelected) {
|
|
||||||
setState(() {
|
|
||||||
selectedMachineTime = index;
|
|
||||||
});
|
|
||||||
setEstimatedValue();
|
|
||||||
},
|
|
||||||
options: GroupButtonOptions(
|
|
||||||
buttonWidth: SizeConfig.width * .375,
|
|
||||||
mainGroupAlignment: MainGroupAlignment.spaceBetween,
|
|
||||||
groupRunAlignment: GroupRunAlignment.spaceBetween,
|
|
||||||
spacing: 16,
|
|
||||||
elevation: 0,
|
|
||||||
borderRadius: BorderRadius.circular(80),
|
|
||||||
selectedShadow: const [],
|
|
||||||
selectedColor: Colors.white,
|
|
||||||
selectedBorderColor: ColorPalette.primary,
|
|
||||||
selectedTextStyle: const TextStyle(
|
|
||||||
fontWeight: FontWeight.w700,
|
|
||||||
color: ColorPalette.primary
|
|
||||||
),
|
|
||||||
unselectedShadow: const [],
|
|
||||||
unselectedBorderColor: ColorPalette.slate200,
|
|
||||||
unselectedTextStyle: const TextStyle(
|
|
||||||
fontWeight: FontWeight.w500,
|
|
||||||
color: ColorPalette.slate500
|
|
||||||
),
|
|
||||||
),
|
|
||||||
),
|
|
||||||
),
|
|
||||||
const Padding(
|
|
||||||
padding: EdgeInsets.only(top: 16, bottom: 8),
|
|
||||||
child: Text(
|
|
||||||
"Today's Investment Estimated Value",
|
|
||||||
style: TextStyle(
|
|
||||||
fontWeight: FontWeight.w600,
|
|
||||||
color: ColorPalette.slate500
|
|
||||||
),
|
|
||||||
),
|
|
||||||
),
|
|
||||||
TextTitle(
|
|
||||||
title: NumberFormatter.numberCurrency(estimatedValue, 'Rp ', 'id_ID'),
|
|
||||||
fontSize: 24,
|
|
||||||
color: ColorPalette.primary,
|
|
||||||
)
|
|
||||||
],
|
|
||||||
);
|
|
||||||
}
|
|
||||||
|
|
||||||
Widget topFiveHoldings() {
|
|
||||||
return Column(
|
|
||||||
children: [
|
|
||||||
const Padding(
|
|
||||||
padding: EdgeInsets.symmetric(horizontal: 24),
|
|
||||||
child: Row(
|
|
||||||
mainAxisAlignment: MainAxisAlignment.spaceBetween,
|
|
||||||
children: [
|
|
||||||
TextTitle(title: 'Top 5 Holdings'),
|
|
||||||
Text(
|
|
||||||
'As of 31 Dec 2023',
|
|
||||||
style: TextStyle(
|
|
||||||
fontSize: 12,
|
|
||||||
color: ColorPalette.slate400
|
|
||||||
),
|
|
||||||
)
|
|
||||||
],
|
|
||||||
),
|
|
||||||
),
|
|
||||||
const SizedBox(
|
|
||||||
height: 16,
|
|
||||||
),
|
|
||||||
...listTopHoldings.asMap().entries.map((e) {
|
|
||||||
return topProduct(e.key, e.value);
|
|
||||||
})
|
|
||||||
],
|
|
||||||
);
|
|
||||||
}
|
|
||||||
|
|
||||||
Widget topProduct(int index, String name) {
|
|
||||||
return Column(
|
|
||||||
children: [
|
|
||||||
if(index != 0)...[
|
|
||||||
const Padding(
|
|
||||||
padding: EdgeInsets.symmetric(vertical: 16),
|
|
||||||
child: Divider(color: ColorPalette.slate200,),
|
|
||||||
)
|
|
||||||
],
|
|
||||||
Padding(
|
|
||||||
padding: const EdgeInsets.symmetric(horizontal: 24),
|
|
||||||
child: Row(
|
|
||||||
children: [
|
|
||||||
Container(
|
|
||||||
alignment: Alignment.center,
|
|
||||||
padding: const EdgeInsets.symmetric(vertical: 4, horizontal: 11),
|
|
||||||
decoration: BoxDecoration(
|
|
||||||
shape: BoxShape.circle,
|
|
||||||
color: ColorPalette.blue50,
|
|
||||||
border: Border.all(color: ColorPalette.blue200)
|
|
||||||
),
|
|
||||||
child: Text(index.toString(), style: const TextStyle(color: ColorPalette.primary)),
|
|
||||||
),
|
|
||||||
const SizedBox(
|
|
||||||
width: 16,
|
|
||||||
),
|
|
||||||
Expanded(
|
|
||||||
child: Text(
|
|
||||||
name,
|
|
||||||
style: const TextStyle(
|
|
||||||
color: ColorPalette.slate800,
|
|
||||||
fontSize: 16
|
|
||||||
),
|
|
||||||
)
|
|
||||||
)
|
|
||||||
],
|
|
||||||
),
|
|
||||||
)
|
|
||||||
],
|
|
||||||
);
|
|
||||||
}
|
|
||||||
|
|
||||||
Widget documentProduct() {
|
|
||||||
return Column(
|
|
||||||
children: [
|
|
||||||
Wrap(
|
|
||||||
runAlignment: WrapAlignment.spaceBetween,
|
|
||||||
alignment: WrapAlignment.spaceBetween,
|
|
||||||
children: [
|
|
||||||
SizedBox(
|
|
||||||
width: SizeConfig.width * .4,
|
|
||||||
child: const Row(
|
|
||||||
children: [
|
|
||||||
Icon(Icons.file_copy_outlined, color: ColorPalette.primary),
|
|
||||||
SizedBox(
|
|
||||||
width: 16,
|
|
||||||
),
|
|
||||||
Text(
|
|
||||||
'Prospektus',
|
|
||||||
style: TextStyle(
|
|
||||||
color: ColorPalette.primary,
|
|
||||||
fontWeight: FontWeight.w600
|
|
||||||
),
|
|
||||||
)
|
|
||||||
],
|
|
||||||
),
|
|
||||||
),
|
|
||||||
SizedBox(
|
|
||||||
width: SizeConfig.width * .4,
|
|
||||||
child: const Row(
|
|
||||||
children: [
|
|
||||||
Icon(Icons.file_copy_outlined, color: ColorPalette.primary),
|
|
||||||
SizedBox(
|
|
||||||
width: 16,
|
|
||||||
),
|
|
||||||
Expanded(
|
|
||||||
child: Text(
|
|
||||||
'Fun Fact Sheet',
|
|
||||||
overflow: TextOverflow.ellipsis,
|
|
||||||
style: TextStyle(
|
|
||||||
color: ColorPalette.primary,
|
|
||||||
fontWeight: FontWeight.w600
|
|
||||||
),
|
|
||||||
),
|
|
||||||
)
|
|
||||||
],
|
|
||||||
),
|
|
||||||
)
|
|
||||||
],
|
|
||||||
)
|
|
||||||
],
|
|
||||||
);
|
|
||||||
}
|
|
||||||
}
|
|
|
@ -5,7 +5,6 @@ import 'package:cims_apps/application/theme/color_palette.dart';
|
||||||
import 'package:cims_apps/core/route/route.dart';
|
import 'package:cims_apps/core/route/route.dart';
|
||||||
import 'package:cims_apps/core/utils/size_config.dart';
|
import 'package:cims_apps/core/utils/size_config.dart';
|
||||||
import 'package:cims_apps/features/auth/registration/view/registration_view.dart';
|
import 'package:cims_apps/features/auth/registration/view/registration_view.dart';
|
||||||
import 'package:cims_apps/features/bottom_navigation_view.dart';
|
|
||||||
import 'package:flutter/material.dart';
|
import 'package:flutter/material.dart';
|
||||||
|
|
||||||
class DashboardPublicView extends StatelessWidget {
|
class DashboardPublicView extends StatelessWidget {
|
||||||
|
@ -69,9 +68,7 @@ class DashboardPublicView extends StatelessWidget {
|
||||||
isOutlined: true,
|
isOutlined: true,
|
||||||
width: SizeConfig.width * .43,
|
width: SizeConfig.width * .43,
|
||||||
height: SizeConfig.height * .06,
|
height: SizeConfig.height * .06,
|
||||||
onPressed: () {
|
onPressed: () {},
|
||||||
routePush(context, page: const BottomNavigationView());
|
|
||||||
},
|
|
||||||
),
|
),
|
||||||
ButtonView(
|
ButtonView(
|
||||||
name: 'Sign Up',
|
name: 'Sign Up',
|
||||||
|
|
40
pubspec.lock
|
@ -49,14 +49,6 @@ packages:
|
||||||
url: "https://pub.dev"
|
url: "https://pub.dev"
|
||||||
source: hosted
|
source: hosted
|
||||||
version: "1.1.1"
|
version: "1.1.1"
|
||||||
carousel_slider:
|
|
||||||
dependency: "direct main"
|
|
||||||
description:
|
|
||||||
name: carousel_slider
|
|
||||||
sha256: "9c695cc963bf1d04a47bd6021f68befce8970bcd61d24938e1fb0918cf5d9c42"
|
|
||||||
url: "https://pub.dev"
|
|
||||||
source: hosted
|
|
||||||
version: "4.2.1"
|
|
||||||
characters:
|
characters:
|
||||||
dependency: transitive
|
dependency: transitive
|
||||||
description:
|
description:
|
||||||
|
@ -105,14 +97,6 @@ packages:
|
||||||
url: "https://pub.dev"
|
url: "https://pub.dev"
|
||||||
source: hosted
|
source: hosted
|
||||||
version: "1.0.6"
|
version: "1.0.6"
|
||||||
equatable:
|
|
||||||
dependency: transitive
|
|
||||||
description:
|
|
||||||
name: equatable
|
|
||||||
sha256: c2b87cb7756efdf69892005af546c56c0b5037f54d2a88269b4f347a505e3ca2
|
|
||||||
url: "https://pub.dev"
|
|
||||||
source: hosted
|
|
||||||
version: "2.0.5"
|
|
||||||
fake_async:
|
fake_async:
|
||||||
dependency: transitive
|
dependency: transitive
|
||||||
description:
|
description:
|
||||||
|
@ -145,14 +129,6 @@ packages:
|
||||||
url: "https://pub.dev"
|
url: "https://pub.dev"
|
||||||
source: hosted
|
source: hosted
|
||||||
version: "1.1.0"
|
version: "1.1.0"
|
||||||
fl_chart:
|
|
||||||
dependency: "direct main"
|
|
||||||
description:
|
|
||||||
name: fl_chart
|
|
||||||
sha256: "5a74434cc83bf64346efb562f1a06eefaf1bcb530dc3d96a104f631a1eff8d79"
|
|
||||||
url: "https://pub.dev"
|
|
||||||
source: hosted
|
|
||||||
version: "0.65.0"
|
|
||||||
flutter:
|
flutter:
|
||||||
dependency: "direct main"
|
dependency: "direct main"
|
||||||
description: flutter
|
description: flutter
|
||||||
|
@ -192,14 +168,6 @@ packages:
|
||||||
description: flutter
|
description: flutter
|
||||||
source: sdk
|
source: sdk
|
||||||
version: "0.0.0"
|
version: "0.0.0"
|
||||||
group_button:
|
|
||||||
dependency: "direct main"
|
|
||||||
description:
|
|
||||||
name: group_button
|
|
||||||
sha256: "0610fcf28ed122bfb4b410fce161a390f7f2531d55d1d65c5375982001415940"
|
|
||||||
url: "https://pub.dev"
|
|
||||||
source: hosted
|
|
||||||
version: "5.3.4"
|
|
||||||
http:
|
http:
|
||||||
dependency: transitive
|
dependency: transitive
|
||||||
description:
|
description:
|
||||||
|
@ -216,14 +184,6 @@ packages:
|
||||||
url: "https://pub.dev"
|
url: "https://pub.dev"
|
||||||
source: hosted
|
source: hosted
|
||||||
version: "4.0.2"
|
version: "4.0.2"
|
||||||
intl:
|
|
||||||
dependency: "direct main"
|
|
||||||
description:
|
|
||||||
name: intl
|
|
||||||
sha256: d6f56758b7d3014a48af9701c085700aac781a92a87a62b1333b46d8879661cf
|
|
||||||
url: "https://pub.dev"
|
|
||||||
source: hosted
|
|
||||||
version: "0.19.0"
|
|
||||||
js:
|
js:
|
||||||
dependency: transitive
|
dependency: transitive
|
||||||
description:
|
description:
|
||||||
|
|
|
@ -39,11 +39,7 @@ dependencies:
|
||||||
flutter_svg: ^1.1.6
|
flutter_svg: ^1.1.6
|
||||||
cached_network_image: ^3.2.3
|
cached_network_image: ^3.2.3
|
||||||
remove_emoji_input_formatter: ^0.0.1+1
|
remove_emoji_input_formatter: ^0.0.1+1
|
||||||
fl_chart: ^0.65.0
|
|
||||||
intl: ^0.19.0
|
|
||||||
carousel_slider: ^4.2.1
|
|
||||||
provider: ^6.1.1
|
provider: ^6.1.1
|
||||||
group_button: ^5.3.4
|
|
||||||
pinput: ^2.2.21
|
pinput: ^2.2.21
|
||||||
|
|
||||||
|
|
||||||
|
|