diff --git a/assets/icons/icon-portofolio-bonds.png b/assets/icons/icon-portofolio-bonds.png new file mode 100644 index 0000000..58f5130 Binary files /dev/null and b/assets/icons/icon-portofolio-bonds.png differ diff --git a/assets/icons/icon-portofolio-moneymarket.png b/assets/icons/icon-portofolio-moneymarket.png new file mode 100644 index 0000000..de2f2f5 Binary files /dev/null and b/assets/icons/icon-portofolio-moneymarket.png differ diff --git a/assets/icons/icon-portofolio-shares.png b/assets/icons/icon-portofolio-shares.png new file mode 100644 index 0000000..7ec4b3c Binary files /dev/null and b/assets/icons/icon-portofolio-shares.png differ diff --git a/assets/icons/icon-portofolio-sharia.png b/assets/icons/icon-portofolio-sharia.png new file mode 100644 index 0000000..04c348a Binary files /dev/null and b/assets/icons/icon-portofolio-sharia.png differ diff --git a/assets/images/img-articles.png b/assets/images/img-articles.png new file mode 100644 index 0000000..ab41cc1 Binary files /dev/null and b/assets/images/img-articles.png differ diff --git a/assets/images/img-carousel.png b/assets/images/img-carousel.png new file mode 100644 index 0000000..2fb419e Binary files /dev/null and b/assets/images/img-carousel.png differ diff --git a/assets/images/img-dashboard-account.png b/assets/images/img-dashboard-account.png new file mode 100644 index 0000000..c6a152c Binary files /dev/null and b/assets/images/img-dashboard-account.png differ diff --git a/assets/images/img-product.png b/assets/images/img-product.png new file mode 100644 index 0000000..c058b1c Binary files /dev/null and b/assets/images/img-product.png differ diff --git a/lib/application/assets/path_assets.dart b/lib/application/assets/path_assets.dart index bf981d5..e86ba76 100644 --- a/lib/application/assets/path_assets.dart +++ b/lib/application/assets/path_assets.dart @@ -10,6 +10,10 @@ class PathAssets { static const String iconGoogle = 'assets/icons/icon-google.png'; static const String icon1 = 'assets/icons/icon-1.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 iconFlag = 'assets/icons/icon-flag.png'; @@ -24,5 +28,9 @@ class PathAssets { static const String imgKtpCropped = 'assets/images/img-ktp-cropped.png'; static const String imgKtpClear = 'assets/images/img-ktp-clear.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'; } diff --git a/lib/application/component/button/button_back.dart b/lib/application/component/button/button_back.dart new file mode 100644 index 0000000..091b8bb --- /dev/null +++ b/lib/application/component/button/button_back.dart @@ -0,0 +1,23 @@ +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) + ), + ); + } +} diff --git a/lib/application/component/button/button_view.dart b/lib/application/component/button/button_view.dart index 8ea3823..888dc89 100644 --- a/lib/application/component/button/button_view.dart +++ b/lib/application/component/button/button_view.dart @@ -9,13 +9,14 @@ class ButtonView extends StatelessWidget { final double? height, width, widthSuffix, widthPrefix, marginVertical; final EdgeInsetsGeometry? contentPadding; final bool isSecondaryColor, isOutlined, heightWrapContent, disabled; - final Color? backgroundColor, textColor; + final Color? backgroundColor, textColor, borderColor; final MainAxisAlignment? mainAxisAlignmentContent; // final _widthBtn = SizeConfig.screenWidth / 1.5; final _widthBtn = SizeConfig.width * .9; // final _heightBtn = SizeConfig.screenHeight / 12; final _heightBtn = SizeConfig.height * .07; final FontWeight textWeight; + final TextAlign textAlign; final double? textSize, sizeBorderRadius; final int? maxLines; @@ -31,9 +32,11 @@ class ButtonView extends StatelessWidget { this.width, this.contentPadding, this.backgroundColor, + this.borderColor, this.textColor, this.textWeight = FontWeight.bold, this.textSize, + this.textAlign = TextAlign.center, this.mainAxisAlignmentContent, this.disabled = false, this.heightWrapContent = false, @@ -75,11 +78,11 @@ class ButtonView extends StatelessWidget { borderRadius: BorderRadius.circular(sizeBorderRadius ?? 48), side: isOutlined ? BorderSide( - color: disabled - ? ColorPalette.greyBorder + color: borderColor ?? (disabled + ? color.surface : isSecondaryColor - ? ColorPalette.greyBorder - : ColorPalette.primary, + ? ColorPalette.greyBorder + : ColorPalette.primary), ) : BorderSide.none, ), @@ -101,7 +104,7 @@ class ButtonView extends StatelessWidget { Flexible( child: Text( name, - textAlign: TextAlign.center, + textAlign: textAlign, maxLines: maxLines, overflow: TextOverflow.ellipsis, style: TextStyle( diff --git a/lib/application/component/text_title/text_title.dart b/lib/application/component/text_title/text_title.dart new file mode 100644 index 0000000..0df8c71 --- /dev/null +++ b/lib/application/component/text_title/text_title.dart @@ -0,0 +1,26 @@ +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, + ), + ); + } +} diff --git a/lib/application/theme/color_palette.dart b/lib/application/theme/color_palette.dart index 90ea85b..e4d255b 100644 --- a/lib/application/theme/color_palette.dart +++ b/lib/application/theme/color_palette.dart @@ -74,5 +74,37 @@ class ColorPalette { static const Color background = Color(0xFFDADADA); static const Color backgroundBlueLight = Color(0xFFEBF3FD); 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 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 investTypeColor = { + 'Money Market': purple500, + 'Shares': orange500, + 'Sharia': green500, + 'Bonds': cyan500 + }; + + static const Map investTypeBgColor = { + 'Money Market': purple100, + 'Shares': orange100, + 'Sharia': green100, + 'Bonds': cyan100 + }; } diff --git a/lib/core/utils/date_formatter.dart b/lib/core/utils/date_formatter.dart new file mode 100644 index 0000000..94c0a90 --- /dev/null +++ b/lib/core/utils/date_formatter.dart @@ -0,0 +1,3 @@ +class DateFormatter { + +} \ No newline at end of file diff --git a/lib/core/utils/number_formatter.dart b/lib/core/utils/number_formatter.dart new file mode 100644 index 0000000..2965417 --- /dev/null +++ b/lib/core/utils/number_formatter.dart @@ -0,0 +1,19 @@ +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; + } +} \ No newline at end of file diff --git a/lib/features/bottom_navigation_view.dart b/lib/features/bottom_navigation_view.dart index 239473e..53cd5b3 100644 --- a/lib/features/bottom_navigation_view.dart +++ b/lib/features/bottom_navigation_view.dart @@ -1,4 +1,6 @@ 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'; class BottomNavigationView extends StatefulWidget { @@ -15,15 +17,12 @@ class _BottomNavigationViewState extends State { Widget build(BuildContext context) { ///TODO: masukan pagenya dilistWidget ini List listWidget = [ - Container( - color: Colors.amberAccent, - ), + HomeView(), Container( color: Colors.redAccent, ), Container(), - Container(), - Container(), + PortofolioView(), Container(), ]; @@ -60,6 +59,7 @@ class _BottomNavigationViewState extends State { }, currentIndex: _selectedIndex, items: listNavigation, + type: BottomNavigationBarType.fixed, showUnselectedLabels: true, selectedItemColor: ColorPalette.primary, unselectedItemColor: Colors.black, diff --git a/lib/features/dashboard/dashboard_account/view/homepage/homepage_view.dart b/lib/features/dashboard/dashboard_account/view/homepage/homepage_view.dart new file mode 100644 index 0000000..8b35382 --- /dev/null +++ b/lib/features/dashboard/dashboard_account/view/homepage/homepage_view.dart @@ -0,0 +1,529 @@ +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 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 createState() => _HomeViewState(); +} + +class _HomeViewState extends State { + bool seePortofolioValue = false; + + List 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
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), + ), + ], + ) + ) + ], + ), + ); + } +} diff --git a/lib/features/dashboard/dashboard_account/view/invest_type/invest_type_view.dart b/lib/features/dashboard/dashboard_account/view/invest_type/invest_type_view.dart new file mode 100644 index 0000000..256f31c --- /dev/null +++ b/lib/features/dashboard/dashboard_account/view/invest_type/invest_type_view.dart @@ -0,0 +1,236 @@ +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 createState() => _InvestTypeViewState(); +} + +class _InvestTypeViewState extends State { + + List 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 + ), + ), + ], + ) + ], + ) + ], + ) + ], + ), + ); + } + +} diff --git a/lib/features/dashboard/dashboard_account/view/portfolio/portfolio_view.dart b/lib/features/dashboard/dashboard_account/view/portfolio/portfolio_view.dart new file mode 100644 index 0000000..afc11de --- /dev/null +++ b/lib/features/dashboard/dashboard_account/view/portfolio/portfolio_view.dart @@ -0,0 +1,347 @@ +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 createState() => _PortofolioViewState(); +} + +class _PortofolioViewState extends State { + List contentColor = [ + ColorPalette.purple500, + ColorPalette.orange500, + ColorPalette.cyan500, + ColorPalette.green500, + ]; + List bgContentColor = [ + ColorPalette.purple100, + ColorPalette.orange100, + ColorPalette.cyan100, + ColorPalette.green100, + ]; + + bool seePortofolioValue = false; + int touchedIndex = -1; + + List listCategoryPortofolio = [ + CategoryPortofolio(20, 'Money Market'), + CategoryPortofolio(15, 'Shares'), + CategoryPortofolio(8, 'Bonds'), + CategoryPortofolio(50, 'Sharia'), + ]; + + List 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 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 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(); + } +} diff --git a/lib/features/dashboard/dashboard_account/view/product/product_chart_view.dart b/lib/features/dashboard/dashboard_account/view/product/product_chart_view.dart new file mode 100644 index 0000000..186e06e --- /dev/null +++ b/lib/features/dashboard/dashboard_account/view/product/product_chart_view.dart @@ -0,0 +1,325 @@ +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 dataChart; + + const ProductChartView({ + super.key, + required this.tabType, + required this.lastTime, + required this.dataChart, + }); + + @override + State createState() => _ProductChartViewState(); +} + +class _ProductChartViewState extends State { + bool isShowLabel = true; + DateTime dateTime = DateTime.now(); + double currentPrice = 0; + int spotIndicator = 0; + List showingTooltipOnSpots = [1, 3, 5]; + List 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), + ), + ); + }, + ), + ), + ), + ], + ); + } +} diff --git a/lib/features/dashboard/dashboard_account/view/product/product_view.dart b/lib/features/dashboard/dashboard_account/view/product/product_view.dart new file mode 100644 index 0000000..5502cb3 --- /dev/null +++ b/lib/features/dashboard/dashboard_account/view/product/product_view.dart @@ -0,0 +1,789 @@ +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 createState() => _ProductViewState(); +} + +class _ProductViewState extends State { + int selectedTab = 0; + Time selectedTime = Time(2, '1D', '1 day'); + int selectedMachineType = 0; + int selectedMachineTime = 0; + + List