feat: home view, portfolio view, invest type view
This commit is contained in:
@@ -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<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();
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user