Files
unionflow-mobile-apps/lib/shared/design_system/components/union_pie_chart.dart
2026-03-31 09:14:47 +00:00

159 lines
4.9 KiB
Dart
Raw Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

import 'package:flutter/material.dart';
import 'package:fl_chart/fl_chart.dart';
import '../tokens/unionflow_colors.dart';
/// Graphique circulaire UnionFlow — petit donut compact avec légende latérale
/// Layout horizontal : donut 80×80 à gauche + légende à droite
/// Style uniforme avec les autres cards du design system (border + borderRadius)
class UnionPieChart extends StatelessWidget {
final List<PieChartSectionData> sections;
final String title;
final String? subtitle;
final double? centerSpaceRadius;
const UnionPieChart({
super.key,
required this.sections,
required this.title,
this.subtitle,
this.centerSpaceRadius,
});
@override
Widget build(BuildContext context) {
// Forcer compact : radius 14, pas de titre dans le donut
final compactSections = sections
.map((s) => s.copyWith(radius: 14, showTitle: false))
.toList();
return Container(
padding: const EdgeInsets.fromLTRB(14, 12, 14, 12),
decoration: BoxDecoration(
color: UnionFlowColors.surface,
borderRadius: BorderRadius.circular(10),
border: Border.all(color: UnionFlowColors.border),
),
child: Column(
crossAxisAlignment: CrossAxisAlignment.start,
children: [
// Header
Row(
children: [
Text(
title,
style: const TextStyle(
fontSize: 12,
fontWeight: FontWeight.w700,
color: UnionFlowColors.textPrimary,
),
),
const Spacer(),
if (subtitle != null)
Text(
subtitle!,
style: const TextStyle(
fontSize: 10,
color: UnionFlowColors.textTertiary,
),
),
],
),
const SizedBox(height: 10),
// Donut + légende côte à côte
Row(
children: [
// Petit donut
SizedBox(
width: 80,
height: 80,
child: PieChart(
PieChartData(
sectionsSpace: 2,
centerSpaceRadius: centerSpaceRadius ?? 22,
sections: compactSections,
),
),
),
const SizedBox(width: 14),
// Légende
Expanded(
child: Column(
crossAxisAlignment: CrossAxisAlignment.start,
mainAxisAlignment: MainAxisAlignment.center,
children: sections.map((s) {
// Le title de la section peut contenir '\n' ex: '50%\nActifs'
final parts = s.title.split('\n');
final pct = parts.isNotEmpty ? parts[0] : '';
final label = parts.length > 1 ? parts[1] : s.title;
return Padding(
padding: const EdgeInsets.only(bottom: 6),
child: Row(
children: [
Container(
width: 8,
height: 8,
decoration: BoxDecoration(
color: s.color,
shape: BoxShape.circle,
),
),
const SizedBox(width: 6),
Expanded(
child: Text(
label,
style: const TextStyle(
fontSize: 10,
color: UnionFlowColors.textSecondary,
),
overflow: TextOverflow.ellipsis,
),
),
Text(
pct,
style: TextStyle(
fontSize: 10,
fontWeight: FontWeight.w700,
color: s.color,
),
),
],
),
);
}).toList(),
),
),
],
),
],
),
);
}
}
/// Helper pour créer des sections de pie chart
class UnionPieChartSection {
static PieChartSectionData create({
required double value,
required Color color,
required String title,
double radius = 50,
bool showTitle = true,
}) {
return PieChartSectionData(
color: color,
value: value,
title: title,
radius: radius,
showTitle: showTitle,
titleStyle: const TextStyle(
fontSize: 11,
fontWeight: FontWeight.w600,
color: Colors.white,
),
badgeWidget: null,
);
}
}