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/text_title/text_title.dart b/lib/application/component/text_title/text_title.dart index 2440efa..0df8c71 100644 --- a/lib/application/component/text_title/text_title.dart +++ b/lib/application/component/text_title/text_title.dart @@ -3,11 +3,13 @@ import 'package:flutter/cupertino.dart'; class TextTitle extends StatelessWidget { final String title; - final Color color; + final Color? color; + final double? fontSize; const TextTitle({ Key? key, required this.title, - required this.color, + this.color, + this.fontSize, }) : super(key: key); @override @@ -15,9 +17,9 @@ class TextTitle extends StatelessWidget { return Text( title, style: TextStyle( - fontSize: 20, + fontSize: fontSize ?? 20, fontWeight: FontWeight.w700, - color: color, + color: color ?? ColorPalette.slate800, ), ); } diff --git a/lib/application/theme/color_palette.dart b/lib/application/theme/color_palette.dart index 72154aa..a21c90c 100644 --- a/lib/application/theme/color_palette.dart +++ b/lib/application/theme/color_palette.dart @@ -73,6 +73,8 @@ class ColorPalette { static const Color chathamsBlue = Color(0xFF285BB9); static const Color background = Color(0xFFDADADA); static const Color backgroundBlueLight = Color(0xFFEBF3FD); + static const Color blue200 = Color(0xFFBFDBFE); + static const Color slate50 = Color(0xFFF8FAFC); static const Color slate200 = Color(0xFFE2E8F0); static const Color slate400 = Color(0xFF94A3B8); static const Color slate500 = Color(0xFF64748B); @@ -86,4 +88,19 @@ class ColorPalette { 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/features/dashboard/dashboard_account/view/invest_type/invest_type_view.dart b/lib/features/dashboard/dashboard_account/view/invest_type/invest_type_view.dart index bdff514..f146c96 100644 --- 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 @@ -1,8 +1,11 @@ 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/size_config.dart'; +import 'package:cims_apps/features/dashboard/dashboard_account/view/product/product_view.dart'; import 'package:flutter/material.dart'; class Product { @@ -49,19 +52,7 @@ class _InvestTypeViewState extends State { child: Row( mainAxisAlignment: MainAxisAlignment.spaceBetween, children: [ - SizedBox( - width: SizeConfig.width * 0.1, - child: IconButton( - style: IconButton.styleFrom( - backgroundColor: Colors.white, - shape: const CircleBorder() - ), - onPressed: () { - - }, - icon: const Icon(Icons.arrow_back) - ), - ), + ButtonBack(), TextTitle(title: widget.title, color: Colors.white), SizedBox( width: SizeConfig.width * 0.1, @@ -84,12 +75,20 @@ class _InvestTypeViewState extends State { ListView( shrinkWrap: true, children: listProduct.asMap().entries.map((e) { - return cardProduct(e.value); + 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(), ) ], ), - ) + ), ], ) ], @@ -174,13 +173,13 @@ class _InvestTypeViewState extends State { Row( children: [ Text( - '${product.yield.toString()} %', + '${product.yield.toString()}%', style: TextStyle( color: ColorPalette.green400, fontWeight: FontWeight.w600 ), ), - Text(' / '), + Text('/'), Text('3year', style: TextStyle(color: ColorPalette.slate400, fontWeight: FontWeight.w600),) ], ) @@ -192,11 +191,14 @@ class _InvestTypeViewState extends State { Row( children: [ Text( - product.priceUnit.toString(), + 'Rp${product.priceUnit.toString()}', style: TextStyle( fontWeight: FontWeight.w600 ), ), + SizedBox( + width: 2, + ), Icon(Icons.trending_up_outlined, size: 18, color: ColorPalette.green400,) ], ) diff --git a/lib/features/dashboard/dashboard_account/view/portfolio/portfolio_view.dart b/lib/features/dashboard/dashboard_account/view/portfolio/portfolio_view.dart index 5d1b325..afc11de 100644 --- a/lib/features/dashboard/dashboard_account/view/portfolio/portfolio_view.dart +++ b/lib/features/dashboard/dashboard_account/view/portfolio/portfolio_view.dart @@ -271,7 +271,7 @@ class _PortofolioViewState extends State { color: bgContentColor[e.key], ), child: Text( - '${e.value.value} %', + '${e.value.value}%', style: TextStyle( fontWeight: FontWeight.bold, color: contentColor[e.key]), 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..0c6aac7 --- /dev/null +++ b/lib/features/dashboard/dashboard_account/view/product/product_view.dart @@ -0,0 +1,433 @@ +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/image/image_view.dart'; +import 'package:cims_apps/application/component/text_title/text_title.dart'; +import 'package:cims_apps/application/theme/color_palette.dart'; +import 'package:cims_apps/core/utils/size_config.dart'; +import 'package:flutter/material.dart'; + +class ProductView extends StatefulWidget { + final String investType; + const ProductView(this.investType, {super.key}); + + @override + State createState() => _ProductViewState(); +} + +class _ProductViewState extends State { + int chooseTab = 0; + String chooseTime = '1Y'; + int chooseMachine = 0; + + List listTime = ['1D', '1M', '3M', 'YTD', '1Y', '3Y', '5Y', '10Y', 'All']; + + List listTab = ['NAV', 'AUM']; + + List listMachine = ['Monthly Routine', 'Connect Once']; + + @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() + ) + ], + ) + ], + ), + ), + ); + } + + Widget headContainer() { + return Padding( + padding: const EdgeInsets.symmetric(horizontal: 24), + child: Row( + mainAxisAlignment: MainAxisAlignment.spaceBetween, + children: [ + const Expanded( + child: Row( + children: [ + Expanded( + child: Text( + 'Gemilang Dana Kas Maxima', + 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 Container( + decoration: BoxDecoration( + borderRadius: BorderRadius.circular(12), + color: Colors.white, + ), + child: ListView( + children: [ + Padding( + padding: const EdgeInsets.symmetric(horizontal: 24), + child: Wrap( + spacing: 8, + children: [ + Text(listTab[chooseTab]), + const Text('26 Jan 24'), + ], + ), + ), + Center( + child: Padding( + padding: const EdgeInsets.all(24), + child: switchTab(listTab, (value) { + setState(() { + chooseTab = value; + }); + }, chooseTab), + ), + ), + 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', '0%'), + columnInformation('Risk Level', '1,99%') + ], + ), + ), + const SizedBox( + height: 24, + ), + cardInformation('Informasi Investasi', informationInvest()), + const SizedBox( + height: 24, + ), + cardInformation('Informasi Investasi', investCost()), + const SizedBox( + height: 24, + ), + cardInformation('Time Machine', timeMachine()) + ], + ), + ); + } + + Widget switchTab(List 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: 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, + child: SingleChildScrollView( + scrollDirection: Axis.horizontal, + padding: const EdgeInsets.symmetric(horizontal: 24), + child: Row( + mainAxisAlignment: MainAxisAlignment.center, + children: listTime.map((e) { + return GestureDetector( + onTap: () { + setState(() { + chooseTime = e; + }); + }, + 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: chooseTime == e ? ColorPalette.primary : ColorPalette.slate50 + ), + child: Text(e, style: TextStyle( + color: chooseTime == e ? ColorPalette.white : ColorPalette.slate400, + fontWeight: FontWeight.w700 + )), + ), + ); + }).toList(), + ), + ) + ); + } + + Widget columnInformation(String title, String value) { + return Column( + crossAxisAlignment: CrossAxisAlignment.center, + children: [ + Row( + mainAxisAlignment: MainAxisAlignment.center, + children: [ + Text( + title, + maxLines: 1, + style: const TextStyle( + color: ColorPalette.slate400 + ), + ), + const SizedBox(width: 2), + const Icon(Icons.info_outline_rounded, size: 16, color: ColorPalette.slate400) + ], + ), + Row( + mainAxisAlignment: MainAxisAlignment.center, + children: [ + Text(value) + ], + ) + ], + ); + } + + 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), + SizedBox( + height: 16, + ), + child + ], + ), + ); + } + + Widget informationInvest() { + return const Column( + children: [ + Row( + mainAxisAlignment: MainAxisAlignment.spaceBetween, + children: [ + Text( + 'Minimum Purchase', + style: TextStyle( + color: ColorPalette.slate400, + fontWeight: FontWeight.w600 + ), + ), + Text('Rp10.000') + ], + ), + Row( + mainAxisAlignment: MainAxisAlignment.spaceBetween, + children: [ + Text( + 'Custodian Bank', + style: TextStyle( + color: ColorPalette.slate400, + fontWeight: FontWeight.w600 + ), + ), + Text('HSBC INDONESIA') + ], + ), + Row( + mainAxisAlignment: MainAxisAlignment.spaceBetween, + children: [ + Text( + 'Depository Bank', + style: TextStyle( + color: ColorPalette.slate400, + fontWeight: FontWeight.w600 + ), + ), + Text('BCA') + ], + ) + ], + ); + } + + Widget investCost(){ + return const Column( + children: [ + Row( + mainAxisAlignment: MainAxisAlignment.spaceBetween, + children: [ + Text( + 'Purchase Commission', + style: TextStyle( + color: ColorPalette.slate400, + fontWeight: FontWeight.w600 + ), + ), + Text('Free') + ], + ), + Row( + mainAxisAlignment: MainAxisAlignment.spaceBetween, + children: [ + Text( + 'Sales Commission', + style: TextStyle( + color: ColorPalette.slate400, + fontWeight: FontWeight.w600 + ), + ), + Text('Free') + ], + ), + ], + ); + } + + Widget timeMachine() { + return Column( + children: [ + switchTab(listMachine, (value) { + setState(() { + chooseMachine = value; + }); + }, + chooseMachine + ) + ], + ); + } +}