first commit
This commit is contained in:
@@ -0,0 +1,335 @@
|
||||
import 'package:flutter/material.dart';
|
||||
import 'package:fl_chart/fl_chart.dart';
|
||||
import '../../../../shared/theme/app_theme.dart';
|
||||
|
||||
class ChartCard extends StatelessWidget {
|
||||
final String title;
|
||||
final Widget chart;
|
||||
final String? subtitle;
|
||||
final VoidCallback? onTap;
|
||||
|
||||
const ChartCard({
|
||||
super.key,
|
||||
required this.title,
|
||||
required this.chart,
|
||||
this.subtitle,
|
||||
this.onTap,
|
||||
});
|
||||
|
||||
@override
|
||||
Widget build(BuildContext context) {
|
||||
return GestureDetector(
|
||||
onTap: onTap,
|
||||
child: Container(
|
||||
padding: const EdgeInsets.all(20),
|
||||
decoration: BoxDecoration(
|
||||
color: Colors.white,
|
||||
borderRadius: BorderRadius.circular(16),
|
||||
boxShadow: [
|
||||
BoxShadow(
|
||||
color: Colors.black.withOpacity(0.08),
|
||||
blurRadius: 15,
|
||||
offset: const Offset(0, 4),
|
||||
),
|
||||
],
|
||||
),
|
||||
child: Column(
|
||||
crossAxisAlignment: CrossAxisAlignment.start,
|
||||
children: [
|
||||
Row(
|
||||
children: [
|
||||
Expanded(
|
||||
child: Column(
|
||||
crossAxisAlignment: CrossAxisAlignment.start,
|
||||
children: [
|
||||
Text(
|
||||
title,
|
||||
style: const TextStyle(
|
||||
fontSize: 18,
|
||||
fontWeight: FontWeight.bold,
|
||||
color: AppTheme.textPrimary,
|
||||
),
|
||||
),
|
||||
if (subtitle != null) ...[
|
||||
const SizedBox(height: 4),
|
||||
Text(
|
||||
subtitle!,
|
||||
style: const TextStyle(
|
||||
fontSize: 14,
|
||||
color: AppTheme.textSecondary,
|
||||
),
|
||||
),
|
||||
],
|
||||
],
|
||||
),
|
||||
),
|
||||
if (onTap != null)
|
||||
const Icon(
|
||||
Icons.arrow_forward_ios,
|
||||
size: 16,
|
||||
color: AppTheme.textHint,
|
||||
),
|
||||
],
|
||||
),
|
||||
const SizedBox(height: 20),
|
||||
SizedBox(
|
||||
height: 200,
|
||||
child: chart,
|
||||
),
|
||||
],
|
||||
),
|
||||
),
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
class MembershipChart extends StatelessWidget {
|
||||
const MembershipChart({super.key});
|
||||
|
||||
@override
|
||||
Widget build(BuildContext context) {
|
||||
return LineChart(
|
||||
LineChartData(
|
||||
gridData: FlGridData(
|
||||
show: true,
|
||||
drawVerticalLine: false,
|
||||
horizontalInterval: 200,
|
||||
getDrawingHorizontalLine: (value) {
|
||||
return FlLine(
|
||||
color: AppTheme.borderColor.withOpacity(0.5),
|
||||
strokeWidth: 1,
|
||||
);
|
||||
},
|
||||
),
|
||||
titlesData: FlTitlesData(
|
||||
show: true,
|
||||
rightTitles: const AxisTitles(
|
||||
sideTitles: SideTitles(showTitles: false),
|
||||
),
|
||||
topTitles: const AxisTitles(
|
||||
sideTitles: SideTitles(showTitles: false),
|
||||
),
|
||||
leftTitles: AxisTitles(
|
||||
sideTitles: SideTitles(
|
||||
showTitles: true,
|
||||
interval: 200,
|
||||
getTitlesWidget: (value, meta) {
|
||||
return Text(
|
||||
value.toInt().toString(),
|
||||
style: const TextStyle(
|
||||
color: AppTheme.textHint,
|
||||
fontSize: 12,
|
||||
),
|
||||
);
|
||||
},
|
||||
),
|
||||
),
|
||||
bottomTitles: AxisTitles(
|
||||
sideTitles: SideTitles(
|
||||
showTitles: true,
|
||||
getTitlesWidget: (value, meta) {
|
||||
const months = ['Jan', 'Fév', 'Mar', 'Avr', 'Mai', 'Jun'];
|
||||
if (value.toInt() < months.length) {
|
||||
return Text(
|
||||
months[value.toInt()],
|
||||
style: const TextStyle(
|
||||
color: AppTheme.textHint,
|
||||
fontSize: 12,
|
||||
),
|
||||
);
|
||||
}
|
||||
return const Text('');
|
||||
},
|
||||
),
|
||||
),
|
||||
),
|
||||
borderData: FlBorderData(show: false),
|
||||
minX: 0,
|
||||
maxX: 5,
|
||||
minY: 800,
|
||||
maxY: 1400,
|
||||
lineBarsData: [
|
||||
LineChartBarData(
|
||||
spots: const [
|
||||
FlSpot(0, 1000),
|
||||
FlSpot(1, 1050),
|
||||
FlSpot(2, 1100),
|
||||
FlSpot(3, 1180),
|
||||
FlSpot(4, 1220),
|
||||
FlSpot(5, 1247),
|
||||
],
|
||||
color: AppTheme.primaryColor,
|
||||
barWidth: 3,
|
||||
isStrokeCapRound: true,
|
||||
dotData: FlDotData(
|
||||
show: true,
|
||||
getDotPainter: (spot, percent, barData, index) {
|
||||
return FlDotCirclePainter(
|
||||
radius: 4,
|
||||
color: AppTheme.primaryColor,
|
||||
strokeWidth: 2,
|
||||
strokeColor: Colors.white,
|
||||
);
|
||||
},
|
||||
),
|
||||
belowBarData: BarAreaData(
|
||||
show: true,
|
||||
gradient: LinearGradient(
|
||||
colors: [
|
||||
AppTheme.primaryColor.withOpacity(0.3),
|
||||
AppTheme.primaryColor.withOpacity(0.1),
|
||||
AppTheme.primaryColor.withOpacity(0.0),
|
||||
],
|
||||
begin: Alignment.topCenter,
|
||||
end: Alignment.bottomCenter,
|
||||
),
|
||||
),
|
||||
),
|
||||
],
|
||||
),
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
class CategoryChart extends StatelessWidget {
|
||||
const CategoryChart({super.key});
|
||||
|
||||
@override
|
||||
Widget build(BuildContext context) {
|
||||
return PieChart(
|
||||
PieChartData(
|
||||
sectionsSpace: 4,
|
||||
centerSpaceRadius: 50,
|
||||
sections: [
|
||||
PieChartSectionData(
|
||||
color: AppTheme.primaryColor,
|
||||
value: 45,
|
||||
title: 'Actifs\n45%',
|
||||
radius: 60,
|
||||
titleStyle: const TextStyle(
|
||||
fontSize: 12,
|
||||
fontWeight: FontWeight.bold,
|
||||
color: Colors.white,
|
||||
),
|
||||
),
|
||||
PieChartSectionData(
|
||||
color: AppTheme.secondaryColor,
|
||||
value: 30,
|
||||
title: 'Retraités\n30%',
|
||||
radius: 60,
|
||||
titleStyle: const TextStyle(
|
||||
fontSize: 12,
|
||||
fontWeight: FontWeight.bold,
|
||||
color: Colors.white,
|
||||
),
|
||||
),
|
||||
PieChartSectionData(
|
||||
color: AppTheme.accentColor,
|
||||
value: 25,
|
||||
title: 'Étudiants\n25%',
|
||||
radius: 60,
|
||||
titleStyle: const TextStyle(
|
||||
fontSize: 12,
|
||||
fontWeight: FontWeight.bold,
|
||||
color: Colors.white,
|
||||
),
|
||||
),
|
||||
],
|
||||
),
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
class RevenueChart extends StatelessWidget {
|
||||
const RevenueChart({super.key});
|
||||
|
||||
@override
|
||||
Widget build(BuildContext context) {
|
||||
return BarChart(
|
||||
BarChartData(
|
||||
alignment: BarChartAlignment.spaceAround,
|
||||
maxY: 15000,
|
||||
barTouchData: BarTouchData(enabled: false),
|
||||
titlesData: FlTitlesData(
|
||||
show: true,
|
||||
rightTitles: const AxisTitles(
|
||||
sideTitles: SideTitles(showTitles: false),
|
||||
),
|
||||
topTitles: const AxisTitles(
|
||||
sideTitles: SideTitles(showTitles: false),
|
||||
),
|
||||
leftTitles: AxisTitles(
|
||||
sideTitles: SideTitles(
|
||||
showTitles: true,
|
||||
interval: 5000,
|
||||
getTitlesWidget: (value, meta) {
|
||||
return Text(
|
||||
'${(value / 1000).toInt()}k€',
|
||||
style: const TextStyle(
|
||||
color: AppTheme.textHint,
|
||||
fontSize: 12,
|
||||
),
|
||||
);
|
||||
},
|
||||
),
|
||||
),
|
||||
bottomTitles: AxisTitles(
|
||||
sideTitles: SideTitles(
|
||||
showTitles: true,
|
||||
getTitlesWidget: (value, meta) {
|
||||
const months = ['J', 'F', 'M', 'A', 'M', 'J'];
|
||||
if (value.toInt() < months.length) {
|
||||
return Text(
|
||||
months[value.toInt()],
|
||||
style: const TextStyle(
|
||||
color: AppTheme.textHint,
|
||||
fontSize: 12,
|
||||
),
|
||||
);
|
||||
}
|
||||
return const Text('');
|
||||
},
|
||||
),
|
||||
),
|
||||
),
|
||||
borderData: FlBorderData(show: false),
|
||||
gridData: FlGridData(
|
||||
show: true,
|
||||
drawVerticalLine: false,
|
||||
horizontalInterval: 5000,
|
||||
getDrawingHorizontalLine: (value) {
|
||||
return FlLine(
|
||||
color: AppTheme.borderColor.withOpacity(0.5),
|
||||
strokeWidth: 1,
|
||||
);
|
||||
},
|
||||
),
|
||||
barGroups: [
|
||||
_buildBarGroup(0, 8000, AppTheme.primaryColor),
|
||||
_buildBarGroup(1, 9500, AppTheme.primaryColor),
|
||||
_buildBarGroup(2, 7800, AppTheme.primaryColor),
|
||||
_buildBarGroup(3, 11200, AppTheme.primaryColor),
|
||||
_buildBarGroup(4, 13500, AppTheme.primaryColor),
|
||||
_buildBarGroup(5, 12800, AppTheme.primaryColor),
|
||||
],
|
||||
),
|
||||
);
|
||||
}
|
||||
|
||||
BarChartGroupData _buildBarGroup(int x, double y, Color color) {
|
||||
return BarChartGroupData(
|
||||
x: x,
|
||||
barRods: [
|
||||
BarChartRodData(
|
||||
toY: y,
|
||||
color: color,
|
||||
width: 16,
|
||||
borderRadius: const BorderRadius.only(
|
||||
topLeft: Radius.circular(4),
|
||||
topRight: Radius.circular(4),
|
||||
),
|
||||
),
|
||||
],
|
||||
);
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user